提交 98f1b7f3 编写于 作者: D David S. Miller

Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next

John W. Linville says:

====================
This is a batch of updates intended for 3.12.  It is mostly driver
stuff, although Johannes Berg and Simon Wunderlich make a good
showing with mac80211 bits (particularly some work on 5/10 MHz
channel support).

The usual suspects are mostly represented.  There are lots of updates
to iwlwifi, ath9k, ath10k, mwifiex, rt2x00, wil6210, as usual.
The bcma bus gets some love this time, as do cw1200, iwl4965, and a
few other bits here and there.  I don't think there is much unusual
here, FWIW.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -4360,7 +4360,7 @@ F: drivers/net/wireless/iwlegacy/ ...@@ -4360,7 +4360,7 @@ F: drivers/net/wireless/iwlegacy/
INTEL WIRELESS WIFI LINK (iwlwifi) INTEL WIRELESS WIFI LINK (iwlwifi)
M: Johannes Berg <johannes.berg@intel.com> M: Johannes Berg <johannes.berg@intel.com>
M: Wey-Yi Guy <wey-yi.w.guy@intel.com> M: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com> M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://intellinuxwireless.org W: http://intellinuxwireless.org
......
...@@ -35,8 +35,14 @@ config BCMA_DRIVER_PCI_HOSTMODE ...@@ -35,8 +35,14 @@ config BCMA_DRIVER_PCI_HOSTMODE
PCI core hostmode operation (external PCI bus). PCI core hostmode operation (external PCI bus).
config BCMA_HOST_SOC config BCMA_HOST_SOC
bool bool "Support for BCMA in a SoC"
depends on BCMA_DRIVER_MIPS depends on BCMA
help
Host interface for a Broadcom AIX bus directly mapped into
the memory. This only works with the Broadcom SoCs from the
BCM47XX line.
If unsure, say N
config BCMA_DRIVER_MIPS config BCMA_DRIVER_MIPS
bool "BCMA Broadcom MIPS core driver" bool "BCMA Broadcom MIPS core driver"
......
...@@ -237,7 +237,7 @@ int bcma_bus_register(struct bcma_bus *bus) ...@@ -237,7 +237,7 @@ int bcma_bus_register(struct bcma_bus *bus)
err = bcma_bus_scan(bus); err = bcma_bus_scan(bus);
if (err) { if (err) {
bcma_err(bus, "Failed to scan: %d\n", err); bcma_err(bus, "Failed to scan: %d\n", err);
return -1; return err;
} }
/* Early init CC core */ /* Early init CC core */
......
...@@ -32,6 +32,18 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = { ...@@ -32,6 +32,18 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = {
{ BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" }, { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
{ BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" }, { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
{ BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" }, { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" },
{ BCMA_CORE_PCIEG2, "PCIe Gen 2" },
{ BCMA_CORE_DMA, "DMA" },
{ BCMA_CORE_SDIO3, "SDIO3" },
{ BCMA_CORE_USB20, "USB 2.0" },
{ BCMA_CORE_USB30, "USB 3.0" },
{ BCMA_CORE_A9JTAG, "ARM Cortex A9 JTAG" },
{ BCMA_CORE_DDR23, "Denali DDR2/DDR3 memory controller" },
{ BCMA_CORE_ROM, "ROM" },
{ BCMA_CORE_NAND, "NAND flash controller" },
{ BCMA_CORE_QSPI, "SPI flash controller" },
{ BCMA_CORE_CHIPCOMMON_B, "Chipcommon B" },
{ BCMA_CORE_ARMCA9, "ARM Cortex A9 core (ihost)" },
{ BCMA_CORE_AMEMC, "AMEMC (DDR)" }, { BCMA_CORE_AMEMC, "AMEMC (DDR)" },
{ BCMA_CORE_ALTA, "ALTA (I2S)" }, { BCMA_CORE_ALTA, "ALTA (I2S)" },
{ BCMA_CORE_INVALID, "Invalid" }, { BCMA_CORE_INVALID, "Invalid" },
...@@ -201,7 +213,7 @@ static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr) ...@@ -201,7 +213,7 @@ static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
return ent; return ent;
} }
static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr, static u32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
u32 type, u8 port) u32 type, u8 port)
{ {
u32 addrl, addrh, sizel, sizeh = 0; u32 addrl, addrh, sizel, sizeh = 0;
...@@ -213,7 +225,7 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -213,7 +225,7 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
((ent & SCAN_ADDR_TYPE) != type) || ((ent & SCAN_ADDR_TYPE) != type) ||
(((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) { (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
bcma_erom_push_ent(eromptr); bcma_erom_push_ent(eromptr);
return -EINVAL; return (u32)-EINVAL;
} }
addrl = ent & SCAN_ADDR_ADDR; addrl = ent & SCAN_ADDR_ADDR;
...@@ -261,7 +273,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -261,7 +273,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
struct bcma_device_id *match, int core_num, struct bcma_device_id *match, int core_num,
struct bcma_device *core) struct bcma_device *core)
{ {
s32 tmp; u32 tmp;
u8 i, j; u8 i, j;
s32 cia, cib; s32 cia, cib;
u8 ports[2], wrappers[2]; u8 ports[2], wrappers[2];
...@@ -339,11 +351,11 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -339,11 +351,11 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
* the main register space for the core * the main register space for the core
*/ */
tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0); tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
if (tmp <= 0) { if (tmp == 0 || IS_ERR_VALUE(tmp)) {
/* Try again to see if it is a bridge */ /* Try again to see if it is a bridge */
tmp = bcma_erom_get_addr_desc(bus, eromptr, tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_BRIDGE, 0); SCAN_ADDR_TYPE_BRIDGE, 0);
if (tmp <= 0) { if (tmp == 0 || IS_ERR_VALUE(tmp)) {
return -EILSEQ; return -EILSEQ;
} else { } else {
bcma_info(bus, "Bridge found\n"); bcma_info(bus, "Bridge found\n");
...@@ -357,7 +369,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -357,7 +369,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) { for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr, tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_SLAVE, i); SCAN_ADDR_TYPE_SLAVE, i);
if (tmp < 0) { if (IS_ERR_VALUE(tmp)) {
/* no more entries for port _i_ */ /* no more entries for port _i_ */
/* pr_debug("erom: slave port %d " /* pr_debug("erom: slave port %d "
* "has %d descriptors\n", i, j); */ * "has %d descriptors\n", i, j); */
...@@ -374,7 +386,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -374,7 +386,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) { for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr, tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_MWRAP, i); SCAN_ADDR_TYPE_MWRAP, i);
if (tmp < 0) { if (IS_ERR_VALUE(tmp)) {
/* no more entries for port _i_ */ /* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d " /* pr_debug("erom: master wrapper %d "
* "has %d descriptors\n", i, j); */ * "has %d descriptors\n", i, j); */
...@@ -392,7 +404,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -392,7 +404,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) { for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr, tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_SWRAP, i + hack); SCAN_ADDR_TYPE_SWRAP, i + hack);
if (tmp < 0) { if (IS_ERR_VALUE(tmp)) {
/* no more entries for port _i_ */ /* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d " /* pr_debug("erom: master wrapper %d "
* has %d descriptors\n", i, j); */ * has %d descriptors\n", i, j); */
......
...@@ -130,7 +130,7 @@ config BNX2X_SRIOV ...@@ -130,7 +130,7 @@ config BNX2X_SRIOV
config BGMAC config BGMAC
tristate "BCMA bus GBit core support" tristate "BCMA bus GBit core support"
depends on BCMA_HOST_SOC && HAS_DMA depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
select PHYLIB select PHYLIB
---help--- ---help---
This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus. This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
......
...@@ -159,7 +159,7 @@ struct ath_common { ...@@ -159,7 +159,7 @@ struct ath_common {
bool btcoex_enabled; bool btcoex_enabled;
bool disable_ani; bool disable_ani;
bool antenna_diversity; bool bt_ant_diversity;
}; };
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
......
...@@ -20,6 +20,12 @@ ...@@ -20,6 +20,12 @@
#include "debug.h" #include "debug.h"
#include "htc.h" #include "htc.h"
void ath10k_bmi_start(struct ath10k *ar)
{
ath10k_dbg(ATH10K_DBG_CORE, "BMI started\n");
ar->bmi.done_sent = false;
}
int ath10k_bmi_done(struct ath10k *ar) int ath10k_bmi_done(struct ath10k *ar)
{ {
struct bmi_cmd cmd; struct bmi_cmd cmd;
...@@ -105,7 +111,8 @@ int ath10k_bmi_read_memory(struct ath10k *ar, ...@@ -105,7 +111,8 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
&resp, &rxlen); &resp, &rxlen);
if (ret) { if (ret) {
ath10k_warn("unable to read from the device\n"); ath10k_warn("unable to read from the device (%d)\n",
ret);
return ret; return ret;
} }
...@@ -149,7 +156,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar, ...@@ -149,7 +156,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
NULL, NULL); NULL, NULL);
if (ret) { if (ret) {
ath10k_warn("unable to write to the device\n"); ath10k_warn("unable to write to the device (%d)\n",
ret);
return ret; return ret;
} }
......
...@@ -184,6 +184,7 @@ struct bmi_target_info { ...@@ -184,6 +184,7 @@ struct bmi_target_info {
#define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_TARG 0
#define BMI_CE_NUM_TO_HOST 1 #define BMI_CE_NUM_TO_HOST 1
void ath10k_bmi_start(struct ath10k *ar);
int ath10k_bmi_done(struct ath10k *ar); int ath10k_bmi_done(struct ath10k *ar);
int ath10k_bmi_get_target_info(struct ath10k *ar, int ath10k_bmi_get_target_info(struct ath10k *ar,
struct bmi_target_info *target_info); struct bmi_target_info *target_info);
......
...@@ -79,7 +79,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, ...@@ -79,7 +79,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar,
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
void __iomem *indicator_addr; void __iomem *indicator_addr;
if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) { if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) {
ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n);
return; return;
} }
......
...@@ -100,7 +100,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) ...@@ -100,7 +100,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar)
goto conn_fail; goto conn_fail;
/* Start HTC */ /* Start HTC */
status = ath10k_htc_start(ar->htc); status = ath10k_htc_start(&ar->htc);
if (status) if (status)
goto conn_fail; goto conn_fail;
...@@ -116,7 +116,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) ...@@ -116,7 +116,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar)
return 0; return 0;
timeout: timeout:
ath10k_htc_stop(ar->htc); ath10k_htc_stop(&ar->htc);
conn_fail: conn_fail:
return status; return status;
} }
...@@ -247,19 +247,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, ...@@ -247,19 +247,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,
static int ath10k_download_board_data(struct ath10k *ar) static int ath10k_download_board_data(struct ath10k *ar)
{ {
const struct firmware *fw = ar->board_data;
u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 address; u32 address;
const struct firmware *fw;
int ret; int ret;
fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
ar->hw_params.fw.board);
if (IS_ERR(fw)) {
ath10k_err("could not fetch board data fw file (%ld)\n",
PTR_ERR(fw));
return PTR_ERR(fw);
}
ret = ath10k_push_board_ext_data(ar, fw); ret = ath10k_push_board_ext_data(ar, fw);
if (ret) { if (ret) {
ath10k_err("could not push board ext data (%d)\n", ret); ath10k_err("could not push board ext data (%d)\n", ret);
...@@ -286,32 +278,20 @@ static int ath10k_download_board_data(struct ath10k *ar) ...@@ -286,32 +278,20 @@ static int ath10k_download_board_data(struct ath10k *ar)
} }
exit: exit:
release_firmware(fw);
return ret; return ret;
} }
static int ath10k_download_and_run_otp(struct ath10k *ar) static int ath10k_download_and_run_otp(struct ath10k *ar)
{ {
const struct firmware *fw; const struct firmware *fw = ar->otp;
u32 address; u32 address = ar->hw_params.patch_load_addr;
u32 exec_param; u32 exec_param;
int ret; int ret;
/* OTP is optional */ /* OTP is optional */
if (ar->hw_params.fw.otp == NULL) { if (!ar->otp)
ath10k_info("otp file not defined\n");
return 0;
}
address = ar->hw_params.patch_load_addr;
fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
ar->hw_params.fw.otp);
if (IS_ERR(fw)) {
ath10k_warn("could not fetch otp (%ld)\n", PTR_ERR(fw));
return 0; return 0;
}
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
if (ret) { if (ret) {
...@@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) ...@@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
} }
exit: exit:
release_firmware(fw);
return ret; return ret;
} }
static int ath10k_download_fw(struct ath10k *ar) static int ath10k_download_fw(struct ath10k *ar)
{ {
const struct firmware *fw; const struct firmware *fw = ar->firmware;
u32 address; u32 address;
int ret; int ret;
if (ar->hw_params.fw.fw == NULL)
return -EINVAL;
address = ar->hw_params.patch_load_addr; address = ar->hw_params.patch_load_addr;
fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
ar->hw_params.fw.fw);
if (IS_ERR(fw)) {
ath10k_err("could not fetch fw (%ld)\n", PTR_ERR(fw));
return PTR_ERR(fw);
}
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
if (ret) { if (ret) {
ath10k_err("could not write fw (%d)\n", ret); ath10k_err("could not write fw (%d)\n", ret);
...@@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar) ...@@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar)
} }
exit: exit:
release_firmware(fw); return ret;
}
static void ath10k_core_free_firmware_files(struct ath10k *ar)
{
if (ar->board_data && !IS_ERR(ar->board_data))
release_firmware(ar->board_data);
if (ar->otp && !IS_ERR(ar->otp))
release_firmware(ar->otp);
if (ar->firmware && !IS_ERR(ar->firmware))
release_firmware(ar->firmware);
ar->board_data = NULL;
ar->otp = NULL;
ar->firmware = NULL;
}
static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
{
int ret = 0;
if (ar->hw_params.fw.fw == NULL) {
ath10k_err("firmware file not defined\n");
return -EINVAL;
}
if (ar->hw_params.fw.board == NULL) {
ath10k_err("board data file not defined");
return -EINVAL;
}
ar->board_data = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
ar->hw_params.fw.board);
if (IS_ERR(ar->board_data)) {
ret = PTR_ERR(ar->board_data);
ath10k_err("could not fetch board data (%d)\n", ret);
goto err;
}
ar->firmware = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
ar->hw_params.fw.fw);
if (IS_ERR(ar->firmware)) {
ret = PTR_ERR(ar->firmware);
ath10k_err("could not fetch firmware (%d)\n", ret);
goto err;
}
/* OTP may be undefined. If so, don't fetch it at all */
if (ar->hw_params.fw.otp == NULL)
return 0;
ar->otp = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
ar->hw_params.fw.otp);
if (IS_ERR(ar->otp)) {
ret = PTR_ERR(ar->otp);
ath10k_err("could not fetch otp (%d)\n", ret);
goto err;
}
return 0;
err:
ath10k_core_free_firmware_files(ar);
return ret; return ret;
} }
...@@ -440,8 +476,35 @@ static int ath10k_init_hw_params(struct ath10k *ar) ...@@ -440,8 +476,35 @@ static int ath10k_init_hw_params(struct ath10k *ar)
return 0; return 0;
} }
static void ath10k_core_restart(struct work_struct *work)
{
struct ath10k *ar = container_of(work, struct ath10k, restart_work);
mutex_lock(&ar->conf_mutex);
switch (ar->state) {
case ATH10K_STATE_ON:
ath10k_halt(ar);
ar->state = ATH10K_STATE_RESTARTING;
ieee80211_restart_hw(ar->hw);
break;
case ATH10K_STATE_OFF:
/* this can happen if driver is being unloaded */
ath10k_warn("cannot restart a device that hasn't been started\n");
break;
case ATH10K_STATE_RESTARTING:
case ATH10K_STATE_RESTARTED:
ar->state = ATH10K_STATE_WEDGED;
/* fall through */
case ATH10K_STATE_WEDGED:
ath10k_warn("device is wedged, will not restart\n");
break;
}
mutex_unlock(&ar->conf_mutex);
}
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
enum ath10k_bus bus,
const struct ath10k_hif_ops *hif_ops) const struct ath10k_hif_ops *hif_ops)
{ {
struct ath10k *ar; struct ath10k *ar;
...@@ -458,9 +521,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ...@@ -458,9 +521,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
ar->hif.priv = hif_priv; ar->hif.priv = hif_priv;
ar->hif.ops = hif_ops; ar->hif.ops = hif_ops;
ar->hif.bus = bus;
ar->free_vdev_map = 0xFF; /* 8 vdevs */
init_completion(&ar->scan.started); init_completion(&ar->scan.started);
init_completion(&ar->scan.completed); init_completion(&ar->scan.completed);
...@@ -487,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ...@@ -487,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_waitqueue_head(&ar->event_queue); init_waitqueue_head(&ar->event_queue);
INIT_WORK(&ar->restart_work, ath10k_core_restart);
return ar; return ar;
err_wq: err_wq:
...@@ -504,24 +566,11 @@ void ath10k_core_destroy(struct ath10k *ar) ...@@ -504,24 +566,11 @@ void ath10k_core_destroy(struct ath10k *ar)
} }
EXPORT_SYMBOL(ath10k_core_destroy); EXPORT_SYMBOL(ath10k_core_destroy);
int ath10k_core_start(struct ath10k *ar)
int ath10k_core_register(struct ath10k *ar)
{ {
struct ath10k_htc_ops htc_ops;
struct bmi_target_info target_info;
int status; int status;
memset(&target_info, 0, sizeof(target_info)); ath10k_bmi_start(ar);
status = ath10k_bmi_get_target_info(ar, &target_info);
if (status)
goto err;
ar->target_version = target_info.version;
ar->hw->wiphy->hw_version = target_info.version;
status = ath10k_init_hw_params(ar);
if (status)
goto err;
if (ath10k_init_configure_target(ar)) { if (ath10k_init_configure_target(ar)) {
status = -EINVAL; status = -EINVAL;
...@@ -536,32 +585,32 @@ int ath10k_core_register(struct ath10k *ar) ...@@ -536,32 +585,32 @@ int ath10k_core_register(struct ath10k *ar)
if (status) if (status)
goto err; goto err;
htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; ar->htc.htc_ops.target_send_suspend_complete =
ath10k_send_suspend_complete;
ar->htc = ath10k_htc_create(ar, &htc_ops); status = ath10k_htc_init(ar);
if (IS_ERR(ar->htc)) { if (status) {
status = PTR_ERR(ar->htc); ath10k_err("could not init HTC (%d)\n", status);
ath10k_err("could not create HTC (%d)\n", status);
goto err; goto err;
} }
status = ath10k_bmi_done(ar); status = ath10k_bmi_done(ar);
if (status) if (status)
goto err_htc_destroy; goto err;
status = ath10k_wmi_attach(ar); status = ath10k_wmi_attach(ar);
if (status) { if (status) {
ath10k_err("WMI attach failed: %d\n", status); ath10k_err("WMI attach failed: %d\n", status);
goto err_htc_destroy; goto err;
} }
status = ath10k_htc_wait_target(ar->htc); status = ath10k_htc_wait_target(&ar->htc);
if (status) if (status)
goto err_wmi_detach; goto err_wmi_detach;
ar->htt = ath10k_htt_attach(ar); status = ath10k_htt_attach(ar);
if (!ar->htt) { if (status) {
status = -ENOMEM; ath10k_err("could not attach htt (%d)\n", status);
goto err_wmi_detach; goto err_wmi_detach;
} }
...@@ -588,77 +637,127 @@ int ath10k_core_register(struct ath10k *ar) ...@@ -588,77 +637,127 @@ int ath10k_core_register(struct ath10k *ar)
goto err_disconnect_htc; goto err_disconnect_htc;
} }
status = ath10k_htt_attach_target(ar->htt); status = ath10k_htt_attach_target(&ar->htt);
if (status)
goto err_disconnect_htc;
status = ath10k_mac_register(ar);
if (status) if (status)
goto err_disconnect_htc; goto err_disconnect_htc;
status = ath10k_debug_create(ar); ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
if (status) {
ath10k_err("unable to initialize debugfs\n");
goto err_unregister_mac;
}
return 0; return 0;
err_unregister_mac:
ath10k_mac_unregister(ar);
err_disconnect_htc: err_disconnect_htc:
ath10k_htc_stop(ar->htc); ath10k_htc_stop(&ar->htc);
err_htt_detach: err_htt_detach:
ath10k_htt_detach(ar->htt); ath10k_htt_detach(&ar->htt);
err_wmi_detach: err_wmi_detach:
ath10k_wmi_detach(ar); ath10k_wmi_detach(ar);
err_htc_destroy:
ath10k_htc_destroy(ar->htc);
err: err:
return status; return status;
} }
EXPORT_SYMBOL(ath10k_core_register); EXPORT_SYMBOL(ath10k_core_start);
void ath10k_core_unregister(struct ath10k *ar) void ath10k_core_stop(struct ath10k *ar)
{ {
/* We must unregister from mac80211 before we stop HTC and HIF. ath10k_htc_stop(&ar->htc);
* Otherwise we will fail to submit commands to FW and mac80211 will be ath10k_htt_detach(&ar->htt);
* unhappy about callback failures. */
ath10k_mac_unregister(ar);
ath10k_htc_stop(ar->htc);
ath10k_htt_detach(ar->htt);
ath10k_wmi_detach(ar); ath10k_wmi_detach(ar);
ath10k_htc_destroy(ar->htc);
} }
EXPORT_SYMBOL(ath10k_core_unregister); EXPORT_SYMBOL(ath10k_core_stop);
int ath10k_core_target_suspend(struct ath10k *ar) /* mac80211 manages fw/hw initialization through start/stop hooks. However in
* order to know what hw capabilities should be advertised to mac80211 it is
* necessary to load the firmware (and tear it down immediately since start
* hook will try to init it again) before registering */
static int ath10k_core_probe_fw(struct ath10k *ar)
{ {
int ret; struct bmi_target_info target_info;
int ret = 0;
ret = ath10k_hif_power_up(ar);
if (ret) {
ath10k_err("could not start pci hif (%d)\n", ret);
return ret;
}
ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); memset(&target_info, 0, sizeof(target_info));
ret = ath10k_bmi_get_target_info(ar, &target_info);
if (ret) {
ath10k_err("could not get target info (%d)\n", ret);
ath10k_hif_power_down(ar);
return ret;
}
ret = ath10k_wmi_pdev_suspend_target(ar); ar->target_version = target_info.version;
if (ret) ar->hw->wiphy->hw_version = target_info.version;
ath10k_warn("could not suspend target (%d)\n", ret);
return ret; ret = ath10k_init_hw_params(ar);
if (ret) {
ath10k_err("could not get hw params (%d)\n", ret);
ath10k_hif_power_down(ar);
return ret;
}
ret = ath10k_core_fetch_firmware_files(ar);
if (ret) {
ath10k_err("could not fetch firmware files (%d)\n", ret);
ath10k_hif_power_down(ar);
return ret;
}
ret = ath10k_core_start(ar);
if (ret) {
ath10k_err("could not init core (%d)\n", ret);
ath10k_core_free_firmware_files(ar);
ath10k_hif_power_down(ar);
return ret;
}
ath10k_core_stop(ar);
ath10k_hif_power_down(ar);
return 0;
} }
EXPORT_SYMBOL(ath10k_core_target_suspend);
int ath10k_core_target_resume(struct ath10k *ar) int ath10k_core_register(struct ath10k *ar)
{ {
int ret; int status;
ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); status = ath10k_core_probe_fw(ar);
if (status) {
ath10k_err("could not probe fw (%d)\n", status);
return status;
}
ret = ath10k_wmi_pdev_resume_target(ar); status = ath10k_mac_register(ar);
if (ret) if (status) {
ath10k_warn("could not resume target (%d)\n", ret); ath10k_err("could not register to mac80211 (%d)\n", status);
goto err_release_fw;
}
return ret; status = ath10k_debug_create(ar);
if (status) {
ath10k_err("unable to initialize debugfs\n");
goto err_unregister_mac;
}
return 0;
err_unregister_mac:
ath10k_mac_unregister(ar);
err_release_fw:
ath10k_core_free_firmware_files(ar);
return status;
}
EXPORT_SYMBOL(ath10k_core_register);
void ath10k_core_unregister(struct ath10k *ar)
{
/* We must unregister from mac80211 before we stop HTC and HIF.
* Otherwise we will fail to submit commands to FW and mac80211 will be
* unhappy about callback failures. */
ath10k_mac_unregister(ar);
ath10k_core_free_firmware_files(ar);
} }
EXPORT_SYMBOL(ath10k_core_target_resume); EXPORT_SYMBOL(ath10k_core_unregister);
MODULE_AUTHOR("Qualcomm Atheros"); MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); MODULE_DESCRIPTION("Core module for QCA988X PCIe devices.");
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "htt.h"
#include "htc.h" #include "htc.h"
#include "hw.h" #include "hw.h"
#include "targaddrs.h" #include "targaddrs.h"
...@@ -43,10 +44,6 @@ ...@@ -43,10 +44,6 @@
struct ath10k; struct ath10k;
enum ath10k_bus {
ATH10K_BUS_PCI,
};
struct ath10k_skb_cb { struct ath10k_skb_cb {
dma_addr_t paddr; dma_addr_t paddr;
bool is_mapped; bool is_mapped;
...@@ -250,6 +247,28 @@ struct ath10k_debug { ...@@ -250,6 +247,28 @@ struct ath10k_debug {
struct completion event_stats_compl; struct completion event_stats_compl;
}; };
enum ath10k_state {
ATH10K_STATE_OFF = 0,
ATH10K_STATE_ON,
/* When doing firmware recovery the device is first powered down.
* mac80211 is supposed to call in to start() hook later on. It is
* however possible that driver unloading and firmware crash overlap.
* mac80211 can wait on conf_mutex in stop() while the device is
* stopped in ath10k_core_restart() work holding conf_mutex. The state
* RESTARTED means that the device is up and mac80211 has started hw
* reconfiguration. Once mac80211 is done with the reconfiguration we
* set the state to STATE_ON in restart_complete(). */
ATH10K_STATE_RESTARTING,
ATH10K_STATE_RESTARTED,
/* The device has crashed while restarting hw. This state is like ON
* but commands are blocked in HTC and -ECOMM response is given. This
* prevents completion timeouts and makes the driver more responsive to
* userspace commands. This is also prevents recursive recovery. */
ATH10K_STATE_WEDGED,
};
struct ath10k { struct ath10k {
struct ath_common ath_common; struct ath_common ath_common;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
...@@ -274,19 +293,16 @@ struct ath10k { ...@@ -274,19 +293,16 @@ struct ath10k {
struct { struct {
void *priv; void *priv;
enum ath10k_bus bus;
const struct ath10k_hif_ops *ops; const struct ath10k_hif_ops *ops;
} hif; } hif;
struct ath10k_wmi wmi;
wait_queue_head_t event_queue; wait_queue_head_t event_queue;
bool is_target_paused; bool is_target_paused;
struct ath10k_bmi bmi; struct ath10k_bmi bmi;
struct ath10k_wmi wmi;
struct ath10k_htc *htc; struct ath10k_htc htc;
struct ath10k_htt *htt; struct ath10k_htt htt;
struct ath10k_hw_params { struct ath10k_hw_params {
u32 id; u32 id;
...@@ -301,6 +317,10 @@ struct ath10k { ...@@ -301,6 +317,10 @@ struct ath10k {
} fw; } fw;
} hw_params; } hw_params;
const struct firmware *board_data;
const struct firmware *otp;
const struct firmware *firmware;
struct { struct {
struct completion started; struct completion started;
struct completion completed; struct completion completed;
...@@ -350,20 +370,22 @@ struct ath10k { ...@@ -350,20 +370,22 @@ struct ath10k {
struct completion offchan_tx_completed; struct completion offchan_tx_completed;
struct sk_buff *offchan_tx_skb; struct sk_buff *offchan_tx_skb;
enum ath10k_state state;
struct work_struct restart_work;
#ifdef CONFIG_ATH10K_DEBUGFS #ifdef CONFIG_ATH10K_DEBUGFS
struct ath10k_debug debug; struct ath10k_debug debug;
#endif #endif
}; };
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
enum ath10k_bus bus,
const struct ath10k_hif_ops *hif_ops); const struct ath10k_hif_ops *hif_ops);
void ath10k_core_destroy(struct ath10k *ar); void ath10k_core_destroy(struct ath10k *ar);
int ath10k_core_start(struct ath10k *ar);
void ath10k_core_stop(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar);
void ath10k_core_unregister(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar);
int ath10k_core_target_suspend(struct ath10k *ar);
int ath10k_core_target_resume(struct ath10k *ar);
#endif /* _CORE_H_ */ #endif /* _CORE_H_ */
...@@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, ...@@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
struct wmi_pdev_stats *ps; struct wmi_pdev_stats *ps;
int i; int i;
mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock);
stats = &ar->debug.target_stats; stats = &ar->debug.target_stats;
...@@ -259,6 +259,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, ...@@ -259,6 +259,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
} }
} }
spin_unlock_bh(&ar->data_lock);
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
complete(&ar->debug.event_stats_compl); complete(&ar->debug.event_stats_compl);
} }
...@@ -268,35 +269,35 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, ...@@ -268,35 +269,35 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
{ {
struct ath10k *ar = file->private_data; struct ath10k *ar = file->private_data;
struct ath10k_target_stats *fw_stats; struct ath10k_target_stats *fw_stats;
char *buf; char *buf = NULL;
unsigned int len = 0, buf_len = 2500; unsigned int len = 0, buf_len = 2500;
ssize_t ret_cnt; ssize_t ret_cnt = 0;
long left; long left;
int i; int i;
int ret; int ret;
fw_stats = &ar->debug.target_stats; fw_stats = &ar->debug.target_stats;
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH10K_STATE_ON)
goto exit;
buf = kzalloc(buf_len, GFP_KERNEL); buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; goto exit;
ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
if (ret) { if (ret) {
ath10k_warn("could not request stats (%d)\n", ret); ath10k_warn("could not request stats (%d)\n", ret);
kfree(buf); goto exit;
return -EIO;
} }
left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ); left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
if (left <= 0)
goto exit;
if (left <= 0) { spin_lock_bh(&ar->data_lock);
kfree(buf);
return -ETIMEDOUT;
}
mutex_lock(&ar->conf_mutex);
len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s\n", len += scnprintf(buf + len, buf_len - len, "%30s\n",
"ath10k PDEV stats"); "ath10k PDEV stats");
...@@ -424,14 +425,15 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, ...@@ -424,14 +425,15 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
fw_stats->peer_stat[i].peer_tx_rate); fw_stats->peer_stat[i].peer_tx_rate);
len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "\n");
} }
spin_unlock_bh(&ar->data_lock);
if (len > buf_len) if (len > buf_len)
len = buf_len; len = buf_len;
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
exit:
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
kfree(buf); kfree(buf);
return ret_cnt; return ret_cnt;
} }
...@@ -443,6 +445,60 @@ static const struct file_operations fops_fw_stats = { ...@@ -443,6 +445,60 @@ static const struct file_operations fops_fw_stats = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
const char buf[] = "To simulate firmware crash write the keyword"
" `crash` to this file.\nThis will force firmware"
" to report a crash to the host system.\n";
return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
}
static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
char buf[32] = {};
int ret;
mutex_lock(&ar->conf_mutex);
simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) {
ret = -EINVAL;
goto exit;
}
if (ar->state != ATH10K_STATE_ON &&
ar->state != ATH10K_STATE_RESTARTED) {
ret = -ENETDOWN;
goto exit;
}
ath10k_info("simulating firmware crash\n");
ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
if (ret)
ath10k_warn("failed to force fw hang (%d)\n", ret);
if (ret == 0)
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_simulate_fw_crash = {
.read = ath10k_read_simulate_fw_crash,
.write = ath10k_write_simulate_fw_crash,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath10k_debug_create(struct ath10k *ar) int ath10k_debug_create(struct ath10k *ar)
{ {
ar->debug.debugfs_phy = debugfs_create_dir("ath10k", ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
...@@ -459,6 +515,9 @@ int ath10k_debug_create(struct ath10k *ar) ...@@ -459,6 +515,9 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar, debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_wmi_services); &fops_wmi_services);
debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_simulate_fw_crash);
return 0; return 0;
} }
#endif /* CONFIG_ATH10K_DEBUGFS */ #endif /* CONFIG_ATH10K_DEBUGFS */
......
...@@ -46,8 +46,11 @@ struct ath10k_hif_ops { ...@@ -46,8 +46,11 @@ struct ath10k_hif_ops {
void *request, u32 request_len, void *request, u32 request_len,
void *response, u32 *response_len); void *response, u32 *response_len);
/* Post BMI phase, after FW is loaded. Starts regular operation */
int (*start)(struct ath10k *ar); int (*start)(struct ath10k *ar);
/* Clean up what start() did. This does not revert to BMI phase. If
* desired so, call power_down() and power_up() */
void (*stop)(struct ath10k *ar); void (*stop)(struct ath10k *ar);
int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id, int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
...@@ -66,10 +69,20 @@ struct ath10k_hif_ops { ...@@ -66,10 +69,20 @@ struct ath10k_hif_ops {
*/ */
void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force); void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force);
void (*init)(struct ath10k *ar, void (*set_callbacks)(struct ath10k *ar,
struct ath10k_hif_cb *callbacks); struct ath10k_hif_cb *callbacks);
u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
/* Power up the device and enter BMI transfer mode for FW download */
int (*power_up)(struct ath10k *ar);
/* Power down the device and free up resources. stop() must be called
* before this if start() was called earlier */
void (*power_down)(struct ath10k *ar);
int (*suspend)(struct ath10k *ar);
int (*resume)(struct ath10k *ar);
}; };
...@@ -122,10 +135,10 @@ static inline void ath10k_hif_send_complete_check(struct ath10k *ar, ...@@ -122,10 +135,10 @@ static inline void ath10k_hif_send_complete_check(struct ath10k *ar,
ar->hif.ops->send_complete_check(ar, pipe_id, force); ar->hif.ops->send_complete_check(ar, pipe_id, force);
} }
static inline void ath10k_hif_init(struct ath10k *ar, static inline void ath10k_hif_set_callbacks(struct ath10k *ar,
struct ath10k_hif_cb *callbacks) struct ath10k_hif_cb *callbacks)
{ {
ar->hif.ops->init(ar, callbacks); ar->hif.ops->set_callbacks(ar, callbacks);
} }
static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar, static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar,
...@@ -134,4 +147,30 @@ static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar, ...@@ -134,4 +147,30 @@ static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar,
return ar->hif.ops->get_free_queue_number(ar, pipe_id); return ar->hif.ops->get_free_queue_number(ar, pipe_id);
} }
static inline int ath10k_hif_power_up(struct ath10k *ar)
{
return ar->hif.ops->power_up(ar);
}
static inline void ath10k_hif_power_down(struct ath10k *ar)
{
ar->hif.ops->power_down(ar);
}
static inline int ath10k_hif_suspend(struct ath10k *ar)
{
if (!ar->hif.ops->suspend)
return -EOPNOTSUPP;
return ar->hif.ops->suspend(ar);
}
static inline int ath10k_hif_resume(struct ath10k *ar)
{
if (!ar->hif.ops->resume)
return -EOPNOTSUPP;
return ar->hif.ops->resume(ar);
}
#endif /* _HIF_H_ */ #endif /* _HIF_H_ */
...@@ -246,15 +246,22 @@ int ath10k_htc_send(struct ath10k_htc *htc, ...@@ -246,15 +246,22 @@ int ath10k_htc_send(struct ath10k_htc *htc,
{ {
struct ath10k_htc_ep *ep = &htc->endpoint[eid]; struct ath10k_htc_ep *ep = &htc->endpoint[eid];
if (htc->ar->state == ATH10K_STATE_WEDGED)
return -ECOMM;
if (eid >= ATH10K_HTC_EP_COUNT) { if (eid >= ATH10K_HTC_EP_COUNT) {
ath10k_warn("Invalid endpoint id: %d\n", eid); ath10k_warn("Invalid endpoint id: %d\n", eid);
return -ENOENT; return -ENOENT;
} }
skb_push(skb, sizeof(struct ath10k_htc_hdr));
spin_lock_bh(&htc->tx_lock); spin_lock_bh(&htc->tx_lock);
if (htc->stopped) {
spin_unlock_bh(&htc->tx_lock);
return -ESHUTDOWN;
}
__skb_queue_tail(&ep->tx_queue, skb); __skb_queue_tail(&ep->tx_queue, skb);
skb_push(skb, sizeof(struct ath10k_htc_hdr));
spin_unlock_bh(&htc->tx_lock); spin_unlock_bh(&htc->tx_lock);
queue_work(htc->ar->workqueue, &ep->send_work); queue_work(htc->ar->workqueue, &ep->send_work);
...@@ -265,25 +272,19 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar, ...@@ -265,25 +272,19 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
struct sk_buff *skb, struct sk_buff *skb,
unsigned int eid) unsigned int eid)
{ {
struct ath10k_htc *htc = ar->htc; struct ath10k_htc *htc = &ar->htc;
struct ath10k_htc_ep *ep = &htc->endpoint[eid]; struct ath10k_htc_ep *ep = &htc->endpoint[eid];
bool stopping;
ath10k_htc_notify_tx_completion(ep, skb); ath10k_htc_notify_tx_completion(ep, skb);
/* the skb now belongs to the completion handler */ /* the skb now belongs to the completion handler */
/* note: when using TX credit flow, the re-checking of queues happens
* when credits flow back from the target. in the non-TX credit case,
* we recheck after the packet completes */
spin_lock_bh(&htc->tx_lock); spin_lock_bh(&htc->tx_lock);
stopping = htc->stopping; if (!ep->tx_credit_flow_enabled && !htc->stopped)
spin_unlock_bh(&htc->tx_lock);
if (!ep->tx_credit_flow_enabled && !stopping)
/*
* note: when using TX credit flow, the re-checking of
* queues happens when credits flow back from the target.
* in the non-TX credit case, we recheck after the packet
* completes
*/
queue_work(ar->workqueue, &ep->send_work); queue_work(ar->workqueue, &ep->send_work);
spin_unlock_bh(&htc->tx_lock);
return 0; return 0;
} }
...@@ -414,7 +415,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, ...@@ -414,7 +415,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
u8 pipe_id) u8 pipe_id)
{ {
int status = 0; int status = 0;
struct ath10k_htc *htc = ar->htc; struct ath10k_htc *htc = &ar->htc;
struct ath10k_htc_hdr *hdr; struct ath10k_htc_hdr *hdr;
struct ath10k_htc_ep *ep; struct ath10k_htc_ep *ep;
u16 payload_len; u16 payload_len;
...@@ -751,8 +752,9 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, ...@@ -751,8 +752,9 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
tx_alloc = ath10k_htc_get_credit_allocation(htc, tx_alloc = ath10k_htc_get_credit_allocation(htc,
conn_req->service_id); conn_req->service_id);
if (!tx_alloc) if (!tx_alloc)
ath10k_warn("HTC Service %s does not allocate target credits\n", ath10k_dbg(ATH10K_DBG_HTC,
htc_service_name(conn_req->service_id)); "HTC Service %s does not allocate target credits\n",
htc_service_name(conn_req->service_id));
skb = ath10k_htc_build_tx_ctrl_skb(htc->ar); skb = ath10k_htc_build_tx_ctrl_skb(htc->ar);
if (!skb) { if (!skb) {
...@@ -947,7 +949,7 @@ void ath10k_htc_stop(struct ath10k_htc *htc) ...@@ -947,7 +949,7 @@ void ath10k_htc_stop(struct ath10k_htc *htc)
struct ath10k_htc_ep *ep; struct ath10k_htc_ep *ep;
spin_lock_bh(&htc->tx_lock); spin_lock_bh(&htc->tx_lock);
htc->stopping = true; htc->stopped = true;
spin_unlock_bh(&htc->tx_lock); spin_unlock_bh(&htc->tx_lock);
for (i = ATH10K_HTC_EP_0; i < ATH10K_HTC_EP_COUNT; i++) { for (i = ATH10K_HTC_EP_0; i < ATH10K_HTC_EP_COUNT; i++) {
...@@ -956,26 +958,18 @@ void ath10k_htc_stop(struct ath10k_htc *htc) ...@@ -956,26 +958,18 @@ void ath10k_htc_stop(struct ath10k_htc *htc)
} }
ath10k_hif_stop(htc->ar); ath10k_hif_stop(htc->ar);
ath10k_htc_reset_endpoint_states(htc);
} }
/* registered target arrival callback from the HIF layer */ /* registered target arrival callback from the HIF layer */
struct ath10k_htc *ath10k_htc_create(struct ath10k *ar, int ath10k_htc_init(struct ath10k *ar)
struct ath10k_htc_ops *htc_ops)
{ {
struct ath10k_hif_cb htc_callbacks; struct ath10k_hif_cb htc_callbacks;
struct ath10k_htc_ep *ep = NULL; struct ath10k_htc_ep *ep = NULL;
struct ath10k_htc *htc = NULL; struct ath10k_htc *htc = &ar->htc;
/* FIXME: use struct ath10k instead */
htc = kzalloc(sizeof(struct ath10k_htc), GFP_KERNEL);
if (!htc)
return ERR_PTR(-ENOMEM);
spin_lock_init(&htc->tx_lock); spin_lock_init(&htc->tx_lock);
memcpy(&htc->htc_ops, htc_ops, sizeof(struct ath10k_htc_ops)); htc->stopped = false;
ath10k_htc_reset_endpoint_states(htc); ath10k_htc_reset_endpoint_states(htc);
/* setup HIF layer callbacks */ /* setup HIF layer callbacks */
...@@ -986,15 +980,10 @@ struct ath10k_htc *ath10k_htc_create(struct ath10k *ar, ...@@ -986,15 +980,10 @@ struct ath10k_htc *ath10k_htc_create(struct ath10k *ar,
/* Get HIF default pipe for HTC message exchange */ /* Get HIF default pipe for HTC message exchange */
ep = &htc->endpoint[ATH10K_HTC_EP_0]; ep = &htc->endpoint[ATH10K_HTC_EP_0];
ath10k_hif_init(ar, &htc_callbacks); ath10k_hif_set_callbacks(ar, &htc_callbacks);
ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id); ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id);
init_completion(&htc->ctl_resp); init_completion(&htc->ctl_resp);
return htc; return 0;
}
void ath10k_htc_destroy(struct ath10k_htc *htc)
{
kfree(htc);
} }
...@@ -335,7 +335,7 @@ struct ath10k_htc { ...@@ -335,7 +335,7 @@ struct ath10k_htc {
struct ath10k *ar; struct ath10k *ar;
struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT]; struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
/* protects endpoint and stopping fields */ /* protects endpoint and stopped fields */
spinlock_t tx_lock; spinlock_t tx_lock;
struct ath10k_htc_ops htc_ops; struct ath10k_htc_ops htc_ops;
...@@ -349,11 +349,10 @@ struct ath10k_htc { ...@@ -349,11 +349,10 @@ struct ath10k_htc {
struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT]; struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
int target_credit_size; int target_credit_size;
bool stopping; bool stopped;
}; };
struct ath10k_htc *ath10k_htc_create(struct ath10k *ar, int ath10k_htc_init(struct ath10k *ar);
struct ath10k_htc_ops *htc_ops);
int ath10k_htc_wait_target(struct ath10k_htc *htc); int ath10k_htc_wait_target(struct ath10k_htc *htc);
int ath10k_htc_start(struct ath10k_htc *htc); int ath10k_htc_start(struct ath10k_htc *htc);
int ath10k_htc_connect_service(struct ath10k_htc *htc, int ath10k_htc_connect_service(struct ath10k_htc *htc,
...@@ -362,7 +361,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, ...@@ -362,7 +361,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
struct sk_buff *packet); struct sk_buff *packet);
void ath10k_htc_stop(struct ath10k_htc *htc); void ath10k_htc_stop(struct ath10k_htc *htc);
void ath10k_htc_destroy(struct ath10k_htc *htc);
struct sk_buff *ath10k_htc_alloc_skb(int size); struct sk_buff *ath10k_htc_alloc_skb(int size);
#endif #endif
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
*/ */
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/if_ether.h>
#include "htt.h" #include "htt.h"
#include "core.h" #include "core.h"
...@@ -36,7 +37,7 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt) ...@@ -36,7 +37,7 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
/* connect to control service */ /* connect to control service */
conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG; conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG;
status = ath10k_htc_connect_service(htt->ar->htc, &conn_req, status = ath10k_htc_connect_service(&htt->ar->htc, &conn_req,
&conn_resp); &conn_resp);
if (status) if (status)
...@@ -47,15 +48,11 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt) ...@@ -47,15 +48,11 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
return 0; return 0;
} }
struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) int ath10k_htt_attach(struct ath10k *ar)
{ {
struct ath10k_htt *htt; struct ath10k_htt *htt = &ar->htt;
int ret; int ret;
htt = kzalloc(sizeof(*htt), GFP_KERNEL);
if (!htt)
return NULL;
htt->ar = ar; htt->ar = ar;
htt->max_throughput_mbps = 800; htt->max_throughput_mbps = 800;
...@@ -65,8 +62,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) ...@@ -65,8 +62,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
* since ath10k_htt_rx_attach involves sending a rx ring configure * since ath10k_htt_rx_attach involves sending a rx ring configure
* message to the target. * message to the target.
*/ */
if (ath10k_htt_htc_attach(htt)) ret = ath10k_htt_htc_attach(htt);
if (ret) {
ath10k_err("could not attach htt htc (%d)\n", ret);
goto err_htc_attach; goto err_htc_attach;
}
ret = ath10k_htt_tx_attach(htt); ret = ath10k_htt_tx_attach(htt);
if (ret) { if (ret) {
...@@ -74,8 +74,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) ...@@ -74,8 +74,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
goto err_htc_attach; goto err_htc_attach;
} }
if (ath10k_htt_rx_attach(htt)) ret = ath10k_htt_rx_attach(htt);
if (ret) {
ath10k_err("could not attach htt rx (%d)\n", ret);
goto err_rx_attach; goto err_rx_attach;
}
/* /*
* Prefetch enough data to satisfy target * Prefetch enough data to satisfy target
...@@ -89,13 +92,12 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) ...@@ -89,13 +92,12 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
8 + /* llc snap */ 8 + /* llc snap */
2; /* ip4 dscp or ip6 priority */ 2; /* ip4 dscp or ip6 priority */
return htt; return 0;
err_rx_attach: err_rx_attach:
ath10k_htt_tx_detach(htt); ath10k_htt_tx_detach(htt);
err_htc_attach: err_htc_attach:
kfree(htt); return ret;
return NULL;
} }
#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ) #define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
...@@ -148,5 +150,4 @@ void ath10k_htt_detach(struct ath10k_htt *htt) ...@@ -148,5 +150,4 @@ void ath10k_htt_detach(struct ath10k_htt *htt)
{ {
ath10k_htt_rx_detach(htt); ath10k_htt_rx_detach(htt);
ath10k_htt_tx_detach(htt); ath10k_htt_tx_detach(htt);
kfree(htt);
} }
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/bug.h> #include <linux/bug.h>
#include "core.h"
#include "htc.h" #include "htc.h"
#include "rx_desc.h" #include "rx_desc.h"
...@@ -1317,7 +1316,7 @@ struct htt_rx_desc { ...@@ -1317,7 +1316,7 @@ struct htt_rx_desc {
#define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */
#define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1)
struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar); int ath10k_htt_attach(struct ath10k *ar);
int ath10k_htt_attach_target(struct ath10k_htt *htt); int ath10k_htt_attach_target(struct ath10k_htt *htt);
void ath10k_htt_detach(struct ath10k_htt *htt); void ath10k_htt_detach(struct ath10k_htt *htt);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "core.h"
#include "htc.h" #include "htc.h"
#include "htt.h" #include "htt.h"
#include "txrx.h" #include "txrx.h"
...@@ -1036,7 +1037,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, ...@@ -1036,7 +1037,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{ {
struct ath10k_htt *htt = ar->htt; struct ath10k_htt *htt = &ar->htt;
struct htt_resp *resp = (struct htt_resp *)skb->data; struct htt_resp *resp = (struct htt_resp *)skb->data;
/* confirm alignment */ /* confirm alignment */
......
...@@ -92,7 +92,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt) ...@@ -92,7 +92,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
/* At the beginning free queue number should hint us the maximum /* At the beginning free queue number should hint us the maximum
* queue length */ * queue length */
pipe = htt->ar->htc->endpoint[htt->eid].ul_pipe_id; pipe = htt->ar->htc.endpoint[htt->eid].ul_pipe_id;
htt->max_num_pending_tx = ath10k_hif_get_free_queue_number(htt->ar, htt->max_num_pending_tx = ath10k_hif_get_free_queue_number(htt->ar,
pipe); pipe);
...@@ -153,7 +153,7 @@ void ath10k_htt_tx_detach(struct ath10k_htt *htt) ...@@ -153,7 +153,7 @@ void ath10k_htt_tx_detach(struct ath10k_htt *htt)
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
{ {
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
struct ath10k_htt *htt = ar->htt; struct ath10k_htt *htt = &ar->htt;
if (skb_cb->htt.is_conf) { if (skb_cb->htt.is_conf) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
...@@ -194,7 +194,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) ...@@ -194,7 +194,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
ATH10K_SKB_CB(skb)->htt.is_conf = true; ATH10K_SKB_CB(skb)->htt.is_conf = true;
ret = ath10k_htc_send(htt->ar->htc, htt->eid, skb); ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
if (ret) { if (ret) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return ret; return ret;
...@@ -281,7 +281,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) ...@@ -281,7 +281,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
ATH10K_SKB_CB(skb)->htt.is_conf = true; ATH10K_SKB_CB(skb)->htt.is_conf = true;
ret = ath10k_htc_send(htt->ar->htc, htt->eid, skb); ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
if (ret) { if (ret) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return ret; return ret;
...@@ -346,7 +346,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -346,7 +346,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb->htt.refcount = 2; skb_cb->htt.refcount = 2;
skb_cb->htt.msdu = msdu; skb_cb->htt.msdu = msdu;
res = ath10k_htc_send(htt->ar->htc, htt->eid, txdesc); res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
if (res) if (res)
goto err; goto err;
...@@ -486,7 +486,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -486,7 +486,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb->htt.txfrag = txfrag; skb_cb->htt.txfrag = txfrag;
skb_cb->htt.msdu = msdu; skb_cb->htt.msdu = msdu;
res = ath10k_htc_send(htt->ar->htc, htt->eid, txdesc); res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
if (res) if (res)
goto err; goto err;
......
...@@ -34,6 +34,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id); ...@@ -34,6 +34,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
void ath10k_reset_scan(unsigned long ptr); void ath10k_reset_scan(unsigned long ptr);
void ath10k_offchan_tx_purge(struct ath10k *ar); void ath10k_offchan_tx_purge(struct ath10k *ar);
void ath10k_offchan_tx_work(struct work_struct *work); void ath10k_offchan_tx_work(struct work_struct *work);
void ath10k_halt(struct ath10k *ar);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{ {
......
...@@ -54,6 +54,8 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info, ...@@ -54,6 +54,8 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,
int num); int num);
static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info); static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info);
static void ath10k_pci_stop_ce(struct ath10k *ar); static void ath10k_pci_stop_ce(struct ath10k *ar);
static void ath10k_pci_device_reset(struct ath10k *ar);
static int ath10k_pci_reset_target(struct ath10k *ar);
static const struct ce_attr host_ce_config_wlan[] = { static const struct ce_attr host_ce_config_wlan[] = {
/* host->target HTC control and raw streams */ /* host->target HTC control and raw streams */
...@@ -718,6 +720,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) ...@@ -718,6 +720,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
reg_dump_values[i + 1], reg_dump_values[i + 1],
reg_dump_values[i + 2], reg_dump_values[i + 2],
reg_dump_values[i + 3]); reg_dump_values[i + 3]);
ieee80211_queue_work(ar->hw, &ar->restart_work);
} }
static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
...@@ -744,8 +748,8 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, ...@@ -744,8 +748,8 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
ath10k_ce_per_engine_service(ar, pipe); ath10k_ce_per_engine_service(ar, pipe);
} }
static void ath10k_pci_hif_post_init(struct ath10k *ar, static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
struct ath10k_hif_cb *callbacks) struct ath10k_hif_cb *callbacks)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
...@@ -1263,7 +1267,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ...@@ -1263,7 +1267,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_process_ce(ar); ath10k_pci_process_ce(ar);
ath10k_pci_cleanup_ce(ar); ath10k_pci_cleanup_ce(ar);
ath10k_pci_buffer_cleanup(ar); ath10k_pci_buffer_cleanup(ar);
ath10k_pci_ce_deinit(ar);
} }
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
...@@ -1735,6 +1738,115 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ...@@ -1735,6 +1738,115 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
ath10k_pci_sleep(ar); ath10k_pci_sleep(ar);
} }
static int ath10k_pci_hif_power_up(struct ath10k *ar)
{
int ret;
/*
* Bring the target up cleanly.
*
* The target may be in an undefined state with an AUX-powered Target
* and a Host in WoW mode. If the Host crashes, loses power, or is
* restarted (without unloading the driver) then the Target is left
* (aux) powered and running. On a subsequent driver load, the Target
* is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe.
*/
ath10k_pci_device_reset(ar);
ret = ath10k_pci_reset_target(ar);
if (ret)
goto err;
if (ath10k_target_ps) {
ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n");
} else {
/* Force AWAKE forever */
ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save disabled\n");
ath10k_do_pci_wake(ar);
}
ret = ath10k_pci_ce_init(ar);
if (ret)
goto err_ps;
ret = ath10k_pci_init_config(ar);
if (ret)
goto err_ce;
ret = ath10k_pci_wake_target_cpu(ar);
if (ret) {
ath10k_err("could not wake up target CPU (%d)\n", ret);
goto err_ce;
}
return 0;
err_ce:
ath10k_pci_ce_deinit(ar);
err_ps:
if (!ath10k_target_ps)
ath10k_do_pci_sleep(ar);
err:
return ret;
}
static void ath10k_pci_hif_power_down(struct ath10k *ar)
{
ath10k_pci_ce_deinit(ar);
if (!ath10k_target_ps)
ath10k_do_pci_sleep(ar);
}
#ifdef CONFIG_PM
#define ATH10K_PCI_PM_CONTROL 0x44
static int ath10k_pci_hif_suspend(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct pci_dev *pdev = ar_pci->pdev;
u32 val;
pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
if ((val & 0x000000ff) != 0x3) {
pci_save_state(pdev);
pci_disable_device(pdev);
pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
(val & 0xffffff00) | 0x03);
}
return 0;
}
static int ath10k_pci_hif_resume(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct pci_dev *pdev = ar_pci->pdev;
u32 val;
pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
if ((val & 0x000000ff) != 0) {
pci_restore_state(pdev);
pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
val & 0xffffff00);
/*
* Suspend/Resume resets the PCI configuration space,
* so we have to re-disable the RETRY_TIMEOUT register (0x41)
* to keep PCI Tx retries from interfering with C3 CPU state
*/
pci_read_config_dword(pdev, 0x40, &val);
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
}
return 0;
}
#endif
static const struct ath10k_hif_ops ath10k_pci_hif_ops = { static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.send_head = ath10k_pci_hif_send_head, .send_head = ath10k_pci_hif_send_head,
.exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
...@@ -1743,8 +1855,14 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { ...@@ -1743,8 +1855,14 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe, .map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe,
.get_default_pipe = ath10k_pci_hif_get_default_pipe, .get_default_pipe = ath10k_pci_hif_get_default_pipe,
.send_complete_check = ath10k_pci_hif_send_complete_check, .send_complete_check = ath10k_pci_hif_send_complete_check,
.init = ath10k_pci_hif_post_init, .set_callbacks = ath10k_pci_hif_set_callbacks,
.get_free_queue_number = ath10k_pci_hif_get_free_queue_number, .get_free_queue_number = ath10k_pci_hif_get_free_queue_number,
.power_up = ath10k_pci_hif_power_up,
.power_down = ath10k_pci_hif_power_down,
#ifdef CONFIG_PM
.suspend = ath10k_pci_hif_suspend,
.resume = ath10k_pci_hif_resume,
#endif
}; };
static void ath10k_pci_ce_tasklet(unsigned long ptr) static void ath10k_pci_ce_tasklet(unsigned long ptr)
...@@ -2059,9 +2177,9 @@ static int ath10k_pci_reset_target(struct ath10k *ar) ...@@ -2059,9 +2177,9 @@ static int ath10k_pci_reset_target(struct ath10k *ar)
return 0; return 0;
} }
static void ath10k_pci_device_reset(struct ath10k_pci *ar_pci) static void ath10k_pci_device_reset(struct ath10k *ar)
{ {
struct ath10k *ar = ar_pci->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
void __iomem *mem = ar_pci->mem; void __iomem *mem = ar_pci->mem;
int i; int i;
u32 val; u32 val;
...@@ -2118,7 +2236,7 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci) ...@@ -2118,7 +2236,7 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
case ATH10K_PCI_FEATURE_MSI_X: case ATH10K_PCI_FEATURE_MSI_X:
ath10k_dbg(ATH10K_DBG_PCI, "device supports MSI-X\n"); ath10k_dbg(ATH10K_DBG_PCI, "device supports MSI-X\n");
break; break;
case ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND: case ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND:
ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n"); ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n");
break; break;
} }
...@@ -2145,7 +2263,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -2145,7 +2263,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
switch (pci_dev->device) { switch (pci_dev->device) {
case QCA988X_1_0_DEVICE_ID: case QCA988X_1_0_DEVICE_ID:
set_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features); set_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features);
break; break;
case QCA988X_2_0_DEVICE_ID: case QCA988X_2_0_DEVICE_ID:
set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features); set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
...@@ -2158,8 +2276,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -2158,8 +2276,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ath10k_pci_dump_features(ar_pci); ath10k_pci_dump_features(ar_pci);
ar = ath10k_core_create(ar_pci, ar_pci->dev, ATH10K_BUS_PCI, ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
&ath10k_pci_hif_ops);
if (!ar) { if (!ar) {
ath10k_err("ath10k_core_create failed!\n"); ath10k_err("ath10k_core_create failed!\n");
ret = -EINVAL; ret = -EINVAL;
...@@ -2167,7 +2284,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -2167,7 +2284,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
} }
/* Enable QCA988X_1.0 HW workarounds */ /* Enable QCA988X_1.0 HW workarounds */
if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features))
spin_lock_init(&ar_pci->hw_v1_workaround_lock); spin_lock_init(&ar_pci->hw_v1_workaround_lock);
ar_pci->ar = ar; ar_pci->ar = ar;
...@@ -2247,54 +2364,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -2247,54 +2364,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_iomap; goto err_iomap;
} }
/*
* Bring the target up cleanly.
*
* The target may be in an undefined state with an AUX-powered Target
* and a Host in WoW mode. If the Host crashes, loses power, or is
* restarted (without unloading the driver) then the Target is left
* (aux) powered and running. On a subsequent driver load, the Target
* is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe.
*/
ath10k_pci_device_reset(ar_pci);
ret = ath10k_pci_reset_target(ar);
if (ret)
goto err_intr;
if (ath10k_target_ps) {
ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n");
} else {
/* Force AWAKE forever */
ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save disabled\n");
ath10k_do_pci_wake(ar);
}
ret = ath10k_pci_ce_init(ar);
if (ret)
goto err_intr;
ret = ath10k_pci_init_config(ar);
if (ret)
goto err_ce;
ret = ath10k_pci_wake_target_cpu(ar);
if (ret) {
ath10k_err("could not wake up target CPU (%d)\n", ret);
goto err_ce;
}
ret = ath10k_core_register(ar); ret = ath10k_core_register(ar);
if (ret) { if (ret) {
ath10k_err("could not register driver core (%d)\n", ret); ath10k_err("could not register driver core (%d)\n", ret);
goto err_ce; goto err_intr;
} }
return 0; return 0;
err_ce:
ath10k_pci_ce_deinit(ar);
err_intr: err_intr:
ath10k_pci_stop_intr(ar); ath10k_pci_stop_intr(ar);
err_iomap: err_iomap:
...@@ -2345,128 +2422,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev) ...@@ -2345,128 +2422,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
kfree(ar_pci); kfree(ar_pci);
} }
#if defined(CONFIG_PM_SLEEP)
#define ATH10K_PCI_PM_CONTROL 0x44
static int ath10k_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct ath10k *ar = pci_get_drvdata(pdev);
struct ath10k_pci *ar_pci;
u32 val;
int ret, retval;
ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
if (!ar)
return -ENODEV;
ar_pci = ath10k_pci_priv(ar);
if (!ar_pci)
return -ENODEV;
if (ath10k_core_target_suspend(ar))
return -EBUSY;
ret = wait_event_interruptible_timeout(ar->event_queue,
ar->is_target_paused == true,
1 * HZ);
if (ret < 0) {
ath10k_warn("suspend interrupted (%d)\n", ret);
retval = ret;
goto resume;
} else if (ret == 0) {
ath10k_warn("suspend timed out - target pause event never came\n");
retval = EIO;
goto resume;
}
/*
* reset is_target_paused and host can check that in next time,
* or it will always be TRUE and host just skip the waiting
* condition, it causes target assert due to host already
* suspend
*/
ar->is_target_paused = false;
pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
if ((val & 0x000000ff) != 0x3) {
pci_save_state(pdev);
pci_disable_device(pdev);
pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
(val & 0xffffff00) | 0x03);
}
return 0;
resume:
ret = ath10k_core_target_resume(ar);
if (ret)
ath10k_warn("could not resume (%d)\n", ret);
return retval;
}
static int ath10k_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct ath10k *ar = pci_get_drvdata(pdev);
struct ath10k_pci *ar_pci;
int ret;
u32 val;
ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
if (!ar)
return -ENODEV;
ar_pci = ath10k_pci_priv(ar);
if (!ar_pci)
return -ENODEV;
ret = pci_enable_device(pdev);
if (ret) {
ath10k_warn("cannot enable PCI device: %d\n", ret);
return ret;
}
pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
if ((val & 0x000000ff) != 0) {
pci_restore_state(pdev);
pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
val & 0xffffff00);
/*
* Suspend/Resume resets the PCI configuration space,
* so we have to re-disable the RETRY_TIMEOUT register (0x41)
* to keep PCI Tx retries from interfering with C3 CPU state
*/
pci_read_config_dword(pdev, 0x40, &val);
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
}
ret = ath10k_core_target_resume(ar);
if (ret)
ath10k_warn("target resume failed: %d\n", ret);
return ret;
}
static SIMPLE_DEV_PM_OPS(ath10k_dev_pm_ops,
ath10k_pci_suspend,
ath10k_pci_resume);
#define ATH10K_PCI_PM_OPS (&ath10k_dev_pm_ops)
#else
#define ATH10K_PCI_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table); MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
static struct pci_driver ath10k_pci_driver = { static struct pci_driver ath10k_pci_driver = {
...@@ -2474,7 +2429,6 @@ static struct pci_driver ath10k_pci_driver = { ...@@ -2474,7 +2429,6 @@ static struct pci_driver ath10k_pci_driver = {
.id_table = ath10k_pci_id_table, .id_table = ath10k_pci_id_table,
.probe = ath10k_pci_probe, .probe = ath10k_pci_probe,
.remove = ath10k_pci_remove, .remove = ath10k_pci_remove,
.driver.pm = ATH10K_PCI_PM_OPS,
}; };
static int __init ath10k_pci_init(void) static int __init ath10k_pci_init(void)
......
...@@ -152,7 +152,7 @@ struct service_to_pipe { ...@@ -152,7 +152,7 @@ struct service_to_pipe {
enum ath10k_pci_features { enum ath10k_pci_features {
ATH10K_PCI_FEATURE_MSI_X = 0, ATH10K_PCI_FEATURE_MSI_X = 0,
ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND = 1, ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND = 1,
/* keep last */ /* keep last */
ATH10K_PCI_FEATURE_COUNT ATH10K_PCI_FEATURE_COUNT
...@@ -311,7 +311,7 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, ...@@ -311,7 +311,7 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
void __iomem *addr = ar_pci->mem; void __iomem *addr = ar_pci->mem;
if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) { if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) {
unsigned long irq_flags; unsigned long irq_flags;
spin_lock_irqsave(&ar_pci->hw_v1_workaround_lock, irq_flags); spin_lock_irqsave(&ar_pci->hw_v1_workaround_lock, irq_flags);
......
...@@ -27,6 +27,13 @@ void ath10k_wmi_flush_tx(struct ath10k *ar) ...@@ -27,6 +27,13 @@ void ath10k_wmi_flush_tx(struct ath10k *ar)
{ {
int ret; int ret;
lockdep_assert_held(&ar->conf_mutex);
if (ar->state == ATH10K_STATE_WEDGED) {
ath10k_warn("wmi flush skipped - device is wedged anyway\n");
return;
}
ret = wait_event_timeout(ar->wmi.wq, ret = wait_event_timeout(ar->wmi.wq,
atomic_read(&ar->wmi.pending_tx_count) == 0, atomic_read(&ar->wmi.pending_tx_count) == 0,
5*HZ); 5*HZ);
...@@ -111,7 +118,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, ...@@ -111,7 +118,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len); trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len);
status = ath10k_htc_send(ar->htc, ar->wmi.eid, skb); status = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
if (status) { if (status) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
atomic_dec(&ar->wmi.pending_tx_count); atomic_dec(&ar->wmi.pending_tx_count);
...@@ -501,8 +508,8 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, ...@@ -501,8 +508,8 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies, ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies,
(u8 *)skb_tail_pointer(bcn) - ies); (u8 *)skb_tail_pointer(bcn) - ies);
if (!ie) { if (!ie) {
/* highly unlikely for mac80211 */ if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
ath10k_warn("no tim ie found;\n"); ath10k_warn("no tim ie found;\n");
return; return;
} }
...@@ -1114,7 +1121,7 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar) ...@@ -1114,7 +1121,7 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar)
/* connect to control service */ /* connect to control service */
conn_req.service_id = ATH10K_HTC_SVC_ID_WMI_CONTROL; conn_req.service_id = ATH10K_HTC_SVC_ID_WMI_CONTROL;
status = ath10k_htc_connect_service(ar->htc, &conn_req, &conn_resp); status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp);
if (status) { if (status) {
ath10k_warn("failed to connect to WMI CONTROL service status: %d\n", ath10k_warn("failed to connect to WMI CONTROL service status: %d\n",
status); status);
...@@ -1748,6 +1755,9 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar, ...@@ -1748,6 +1755,9 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
if (arg->key_data) if (arg->key_data)
memcpy(cmd->key_data, arg->key_data, arg->key_len); memcpy(cmd->key_data, arg->key_data, arg->key_len);
ath10k_dbg(ATH10K_DBG_WMI,
"wmi vdev install key idx %d cipher %d len %d\n",
arg->key_idx, arg->key_cipher, arg->key_len);
return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_INSTALL_KEY_CMDID); return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_INSTALL_KEY_CMDID);
} }
...@@ -2011,6 +2021,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, ...@@ -2011,6 +2021,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
cmd->peer_vht_rates.tx_mcs_set = cmd->peer_vht_rates.tx_mcs_set =
__cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
ath10k_dbg(ATH10K_DBG_WMI,
"wmi peer assoc vdev %d addr %pM\n",
arg->vdev_id, arg->addr);
return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID); return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID);
} }
...@@ -2079,3 +2092,22 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) ...@@ -2079,3 +2092,22 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
return ath10k_wmi_cmd_send(ar, skb, WMI_REQUEST_STATS_CMDID); return ath10k_wmi_cmd_send(ar, skb, WMI_REQUEST_STATS_CMDID);
} }
int ath10k_wmi_force_fw_hang(struct ath10k *ar,
enum wmi_force_fw_hang_type type, u32 delay_ms)
{
struct wmi_force_fw_hang_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_force_fw_hang_cmd *)skb->data;
cmd->type = __cpu_to_le32(type);
cmd->delay_ms = __cpu_to_le32(delay_ms);
ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
type, delay_ms);
return ath10k_wmi_cmd_send(ar, skb, WMI_FORCE_FW_HANG_CMDID);
}
...@@ -416,6 +416,7 @@ enum wmi_cmd_id { ...@@ -416,6 +416,7 @@ enum wmi_cmd_id {
WMI_PDEV_FTM_INTG_CMDID, WMI_PDEV_FTM_INTG_CMDID,
WMI_VDEV_SET_KEEPALIVE_CMDID, WMI_VDEV_SET_KEEPALIVE_CMDID,
WMI_VDEV_GET_KEEPALIVE_CMDID, WMI_VDEV_GET_KEEPALIVE_CMDID,
WMI_FORCE_FW_HANG_CMDID,
/* GPIO Configuration */ /* GPIO Configuration */
WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP(WMI_GRP_GPIO), WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP(WMI_GRP_GPIO),
...@@ -2972,6 +2973,22 @@ struct wmi_sta_keepalive_cmd { ...@@ -2972,6 +2973,22 @@ struct wmi_sta_keepalive_cmd {
struct wmi_sta_keepalive_arp_resp arp_resp; struct wmi_sta_keepalive_arp_resp arp_resp;
} __packed; } __packed;
enum wmi_force_fw_hang_type {
WMI_FORCE_FW_HANG_ASSERT = 1,
WMI_FORCE_FW_HANG_NO_DETECT,
WMI_FORCE_FW_HANG_CTRL_EP_FULL,
WMI_FORCE_FW_HANG_EMPTY_POINT,
WMI_FORCE_FW_HANG_STACK_OVERFLOW,
WMI_FORCE_FW_HANG_INFINITE_LOOP,
};
#define WMI_FORCE_FW_HANG_RANDOM_TIME 0xFFFFFFFF
struct wmi_force_fw_hang_cmd {
__le32 type;
__le32 delay_ms;
} __packed;
#define ATH10K_RTS_MAX 2347 #define ATH10K_RTS_MAX 2347
#define ATH10K_FRAGMT_THRESHOLD_MIN 540 #define ATH10K_FRAGMT_THRESHOLD_MIN 540
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346 #define ATH10K_FRAGMT_THRESHOLD_MAX 2346
...@@ -3048,5 +3065,7 @@ int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg); ...@@ -3048,5 +3065,7 @@ int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg);
int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
const struct wmi_pdev_set_wmm_params_arg *arg); const struct wmi_pdev_set_wmm_params_arg *arg);
int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
int ath10k_wmi_force_fw_hang(struct ath10k *ar,
enum wmi_force_fw_hang_type type, u32 delay_ms);
#endif /* _WMI_H_ */ #endif /* _WMI_H_ */
...@@ -96,6 +96,16 @@ config ATH9K_LEGACY_RATE_CONTROL ...@@ -96,6 +96,16 @@ config ATH9K_LEGACY_RATE_CONTROL
has to be passed to mac80211 using the module parameter, has to be passed to mac80211 using the module parameter,
ieee80211_default_rc_algo. ieee80211_default_rc_algo.
config ATH9K_RFKILL
bool "Atheros ath9k rfkill support" if EXPERT
depends on ATH9K
depends on RFKILL=y || RFKILL=ATH9K
default y
help
Say Y to have ath9k poll the RF-Kill GPIO every couple of
seconds. Turn off to save power, but enable it if you have
a platform that can toggle the RF-Kill GPIO.
config ATH9K_HTC config ATH9K_HTC
tristate "Atheros HTC based wireless cards support" tristate "Atheros HTC based wireless cards support"
depends on USB && MAC80211 depends on USB && MAC80211
......
...@@ -555,6 +555,69 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, ...@@ -555,6 +555,69 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
} }
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
{
struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
u8 antdiv_ctrl1, antdiv_ctrl2;
u32 regval;
if (enable) {
antdiv_ctrl1 = ATH_BT_COEX_ANTDIV_CONTROL1_ENABLE;
antdiv_ctrl2 = ATH_BT_COEX_ANTDIV_CONTROL2_ENABLE;
/*
* Don't disable BT ant to allow BB to control SWCOM.
*/
btcoex->bt_coex_mode2 &= (~(AR_BT_DISABLE_BT_ANT));
REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2);
REG_WRITE(ah, AR_PHY_SWITCH_COM, ATH_BT_COEX_ANT_DIV_SWITCH_COM);
REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
} else {
/*
* Disable antenna diversity, use LNA1 only.
*/
antdiv_ctrl1 = ATH_BT_COEX_ANTDIV_CONTROL1_FIXED_A;
antdiv_ctrl2 = ATH_BT_COEX_ANTDIV_CONTROL2_FIXED_A;
/*
* Disable BT Ant. to allow concurrent BT and WLAN receive.
*/
btcoex->bt_coex_mode2 |= AR_BT_DISABLE_BT_ANT;
REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2);
/*
* Program SWCOM table to make sure RF switch always parks
* at BT side.
*/
REG_WRITE(ah, AR_PHY_SWITCH_COM, 0);
REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
}
regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
regval &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
/*
* Clear ant_fast_div_bias [14:9] since for WB195,
* the main LNA is always LNA1.
*/
regval &= (~(AR_PHY_9285_FAST_DIV_BIAS));
regval |= SM(antdiv_ctrl1, AR_PHY_9285_ANT_DIV_CTL);
regval |= SM(antdiv_ctrl2, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
regval |= SM((antdiv_ctrl2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
regval |= SM((antdiv_ctrl1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB);
regval |= SM((antdiv_ctrl1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
regval = REG_READ(ah, AR_PHY_CCK_DETECT);
regval &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
regval |= SM((antdiv_ctrl1 >> 3), AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
}
#endif
static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
struct ath_spec_scan *param) struct ath_spec_scan *param)
{ {
...@@ -634,5 +697,9 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah) ...@@ -634,5 +697,9 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger; ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger;
ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait; ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait;
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
ops->set_bt_ant_diversity = ar9002_hw_set_bt_ant_diversity;
#endif
ar9002_hw_set_nf_limits(ah); ar9002_hw_set_nf_limits(ah);
} }
...@@ -317,13 +317,15 @@ ...@@ -317,13 +317,15 @@
#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29 #define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29
#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000 #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000
#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30 #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30
#define AR_PHY_9285_ANT_DIV_LNA1 2
#define AR_PHY_9285_ANT_DIV_LNA2 1
#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3
#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
#define AR_PHY_9285_ANT_DIV_GAINTB_0 0 #define AR_PHY_9285_ANT_DIV_GAINTB_0 0
#define AR_PHY_9285_ANT_DIV_GAINTB_1 1 #define AR_PHY_9285_ANT_DIV_GAINTB_1 1
#define ATH_BT_COEX_ANTDIV_CONTROL1_ENABLE 0x0b
#define ATH_BT_COEX_ANTDIV_CONTROL2_ENABLE 0x09
#define ATH_BT_COEX_ANTDIV_CONTROL1_FIXED_A 0x04
#define ATH_BT_COEX_ANTDIV_CONTROL2_FIXED_A 0x09
#define ATH_BT_COEX_ANT_DIV_SWITCH_COM 0x66666666
#define AR_PHY_EXT_CCA0 0x99b8 #define AR_PHY_EXT_CCA0 0x99b8
#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF #define AR_PHY_EXT_CCA0_THRESH62 0x000000FF
#define AR_PHY_EXT_CCA0_THRESH62_S 0 #define AR_PHY_EXT_CCA0_THRESH62_S 0
......
...@@ -3541,13 +3541,12 @@ static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is2ghz) ...@@ -3541,13 +3541,12 @@ static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is2ghz)
return le16_to_cpu(ar9003_modal_header(ah, is2ghz)->switchcomspdt); return le16_to_cpu(ar9003_modal_header(ah, is2ghz)->switchcomspdt);
} }
u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
{ {
return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon); return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon);
} }
static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz) u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz)
{ {
return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon2); return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon2);
} }
...@@ -3561,6 +3560,7 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, int chain, ...@@ -3561,6 +3560,7 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, int chain,
static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
{ {
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_hw_capabilities *pCap = &ah->caps;
int chain; int chain;
u32 regval, value, gpio; u32 regval, value, gpio;
...@@ -3614,6 +3614,11 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) ...@@ -3614,6 +3614,11 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
} }
value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
if (AR_SREV_9485(ah) && common->bt_ant_diversity) {
regval &= ~AR_SWITCH_TABLE_COM2_ALL;
regval |= ah->config.ant_ctrl_comm2g_switch_enable;
}
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) { if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) {
...@@ -3645,8 +3650,11 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) ...@@ -3645,8 +3650,11 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
regval &= (~AR_PHY_ANT_DIV_LNADIV); regval &= (~AR_PHY_ANT_DIV_LNADIV);
regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S;
if (AR_SREV_9485(ah) && common->bt_ant_diversity)
regval |= AR_ANT_DIV_ENABLE;
if (AR_SREV_9565(ah)) { if (AR_SREV_9565(ah)) {
if (ah->shared_chain_lnadiv) { if (common->bt_ant_diversity) {
regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S); regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S);
} else { } else {
regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S); regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S);
...@@ -3656,10 +3664,14 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) ...@@ -3656,10 +3664,14 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
/*enable fast_div */ /* enable fast_div */
regval = REG_READ(ah, AR_PHY_CCK_DETECT); regval = REG_READ(ah, AR_PHY_CCK_DETECT);
regval &= (~AR_FAST_DIV_ENABLE); regval &= (~AR_FAST_DIV_ENABLE);
regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S;
if (AR_SREV_9485(ah) && common->bt_ant_diversity)
regval |= AR_FAST_DIV_ENABLE;
REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
...@@ -3673,9 +3685,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) ...@@ -3673,9 +3685,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
AR_PHY_ANT_DIV_ALT_GAINTB | AR_PHY_ANT_DIV_ALT_GAINTB |
AR_PHY_ANT_DIV_MAIN_GAINTB)); AR_PHY_ANT_DIV_MAIN_GAINTB));
/* by default use LNA1 for the main antenna */ /* by default use LNA1 for the main antenna */
regval |= (AR_PHY_ANT_DIV_LNA1 << regval |= (ATH_ANT_DIV_COMB_LNA1 <<
AR_PHY_ANT_DIV_MAIN_LNACONF_S); AR_PHY_ANT_DIV_MAIN_LNACONF_S);
regval |= (AR_PHY_ANT_DIV_LNA2 << regval |= (ATH_ANT_DIV_COMB_LNA2 <<
AR_PHY_ANT_DIV_ALT_LNACONF_S); AR_PHY_ANT_DIV_ALT_LNACONF_S);
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
} }
......
...@@ -334,6 +334,8 @@ struct ar9300_eeprom { ...@@ -334,6 +334,8 @@ struct ar9300_eeprom {
s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah); s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah);
s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah); s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah);
u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz);
u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz);
u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz); u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz);
......
...@@ -632,6 +632,22 @@ static void ar9003_hw_override_ini(struct ath_hw *ah) ...@@ -632,6 +632,22 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
REG_SET_BIT(ah, AR_PHY_CCK_DETECT, REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL))
ah->enabled_cals |= TX_IQ_CAL;
else
ah->enabled_cals &= ~TX_IQ_CAL;
if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
ah->enabled_cals |= TX_CL_CAL;
else
ah->enabled_cals &= ~TX_CL_CAL;
}
} }
static void ar9003_hw_prog_ini(struct ath_hw *ah, static void ar9003_hw_prog_ini(struct ath_hw *ah,
...@@ -814,29 +830,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, ...@@ -814,29 +830,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
if (chan->channel == 2484) if (chan->channel == 2484)
ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1); ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
ah->modes_index = modesIndex; ah->modes_index = modesIndex;
ar9003_hw_override_ini(ah); ar9003_hw_override_ini(ah);
ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_channel_regs(ah, chan);
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
ath9k_hw_apply_txpower(ah, chan, false); ath9k_hw_apply_txpower(ah, chan, false);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL))
ah->enabled_cals |= TX_IQ_CAL;
else
ah->enabled_cals &= ~TX_IQ_CAL;
if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
ah->enabled_cals |= TX_CL_CAL;
else
ah->enabled_cals &= ~TX_CL_CAL;
}
return 0; return 0;
} }
...@@ -1413,65 +1412,111 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, ...@@ -1413,65 +1412,111 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
} }
static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
bool enable)
static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
{ {
struct ath9k_hw_capabilities *pCap = &ah->caps;
u8 ant_div_ctl1; u8 ant_div_ctl1;
u32 regval; u32 regval;
if (!AR_SREV_9565(ah)) if (!AR_SREV_9485(ah) && !AR_SREV_9565(ah))
return; return;
ah->shared_chain_lnadiv = enable; if (AR_SREV_9485(ah)) {
regval = ar9003_hw_ant_ctrl_common_2_get(ah,
IS_CHAN_2GHZ(ah->curchan));
if (enable) {
regval &= ~AR_SWITCH_TABLE_COM2_ALL;
regval |= ah->config.ant_ctrl_comm2g_switch_enable;
}
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2,
AR_SWITCH_TABLE_COM2_ALL, regval);
}
ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
/*
* Set MAIN/ALT LNA conf.
* Set MAIN/ALT gain_tb.
*/
regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
regval &= (~AR_ANT_DIV_CTRL_ALL); regval &= (~AR_ANT_DIV_CTRL_ALL);
regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S; regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S;
regval &= ~AR_PHY_ANT_DIV_LNADIV;
regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S;
if (enable)
regval |= AR_ANT_DIV_ENABLE;
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
regval = REG_READ(ah, AR_PHY_CCK_DETECT); if (AR_SREV_9485_11(ah)) {
regval &= ~AR_FAST_DIV_ENABLE; /*
regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; * Enable LNA diversity.
*/
if (enable)
regval |= AR_FAST_DIV_ENABLE;
REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
if (enable) {
REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,
(1 << AR_PHY_ANT_SW_RX_PROT_S));
if (ah->curchan && IS_CHAN_2GHZ(ah->curchan))
REG_SET_BIT(ah, AR_PHY_RESTART,
AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
AR_BTCOEX_WL_LNADIV_FORCE_ON);
} else {
REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE);
REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
(1 << AR_PHY_ANT_SW_RX_PROT_S));
REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE);
REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,
AR_BTCOEX_WL_LNADIV_FORCE_ON);
regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF | regval &= ~AR_PHY_ANT_DIV_LNADIV;
AR_PHY_ANT_DIV_ALT_LNACONF | regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S;
AR_PHY_ANT_DIV_MAIN_GAINTB | if (enable)
AR_PHY_ANT_DIV_ALT_GAINTB); regval |= AR_ANT_DIV_ENABLE;
regval |= (AR_PHY_ANT_DIV_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S);
regval |= (AR_PHY_ANT_DIV_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S);
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
/*
* Enable fast antenna diversity.
*/
regval = REG_READ(ah, AR_PHY_CCK_DETECT);
regval &= ~AR_FAST_DIV_ENABLE;
regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S;
if (enable)
regval |= AR_FAST_DIV_ENABLE;
REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
regval &= (~(AR_PHY_ANT_DIV_MAIN_LNACONF |
AR_PHY_ANT_DIV_ALT_LNACONF |
AR_PHY_ANT_DIV_ALT_GAINTB |
AR_PHY_ANT_DIV_MAIN_GAINTB));
/*
* Set MAIN to LNA1 and ALT to LNA2 at the
* beginning.
*/
regval |= (ATH_ANT_DIV_COMB_LNA1 <<
AR_PHY_ANT_DIV_MAIN_LNACONF_S);
regval |= (ATH_ANT_DIV_COMB_LNA2 <<
AR_PHY_ANT_DIV_ALT_LNACONF_S);
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
}
} else if (AR_SREV_9565(ah)) {
if (enable) {
REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,
(1 << AR_PHY_ANT_SW_RX_PROT_S));
if (ah->curchan && IS_CHAN_2GHZ(ah->curchan))
REG_SET_BIT(ah, AR_PHY_RESTART,
AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
AR_BTCOEX_WL_LNADIV_FORCE_ON);
} else {
REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE);
REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
(1 << AR_PHY_ANT_SW_RX_PROT_S));
REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE);
REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,
AR_BTCOEX_WL_LNADIV_FORCE_ON);
regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF |
AR_PHY_ANT_DIV_ALT_LNACONF |
AR_PHY_ANT_DIV_MAIN_GAINTB |
AR_PHY_ANT_DIV_ALT_GAINTB);
regval |= (ATH_ANT_DIV_COMB_LNA1 <<
AR_PHY_ANT_DIV_MAIN_LNACONF_S);
regval |= (ATH_ANT_DIV_COMB_LNA2 <<
AR_PHY_ANT_DIV_ALT_LNACONF_S);
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
}
} }
} }
#endif
static int ar9003_hw_fast_chan_change(struct ath_hw *ah, static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
struct ath9k_channel *chan, struct ath9k_channel *chan,
u8 *ini_reloaded) u8 *ini_reloaded)
...@@ -1518,6 +1563,18 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, ...@@ -1518,6 +1563,18 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
if (AR_SREV_9462_20_OR_LATER(ah)) {
/*
* CUS217 mix LNA mode.
*/
if (ar9003_hw_get_rx_gain_idx(ah) == 2) {
REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_core,
1, regWrites);
REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_postamble,
modesIndex, regWrites);
}
}
/* /*
* For 5GHz channels requiring Fast Clock, apply * For 5GHz channels requiring Fast Clock, apply
* different modal values. * different modal values.
...@@ -1528,7 +1585,11 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, ...@@ -1528,7 +1585,11 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
if (AR_SREV_9565(ah)) if (AR_SREV_9565(ah))
REG_WRITE_ARRAY(&ah->iniModesFastClock, 1, regWrites); REG_WRITE_ARRAY(&ah->iniModesFastClock, 1, regWrites);
REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); /*
* JAPAN regulatory.
*/
if (chan->channel == 2484)
ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
ah->modes_index = modesIndex; ah->modes_index = modesIndex;
*ini_reloaded = true; *ini_reloaded = true;
...@@ -1631,11 +1692,14 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) ...@@ -1631,11 +1692,14 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
ops->spectral_scan_config = ar9003_hw_spectral_scan_config; ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger; ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger;
ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait; ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait;
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity;
#endif
ar9003_hw_set_nf_limits(ah); ar9003_hw_set_nf_limits(ah);
ar9003_hw_set_radar_conf(ah); ar9003_hw_set_radar_conf(ah);
memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs)); memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
......
...@@ -296,11 +296,6 @@ ...@@ -296,11 +296,6 @@
#define AR_PHY_ANT_DIV_MAIN_GAINTB 0x40000000 #define AR_PHY_ANT_DIV_MAIN_GAINTB 0x40000000
#define AR_PHY_ANT_DIV_MAIN_GAINTB_S 30 #define AR_PHY_ANT_DIV_MAIN_GAINTB_S 30
#define AR_PHY_ANT_DIV_LNA1_MINUS_LNA2 0x0
#define AR_PHY_ANT_DIV_LNA2 0x1
#define AR_PHY_ANT_DIV_LNA1 0x2
#define AR_PHY_ANT_DIV_LNA1_PLUS_LNA2 0x3
#define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c) #define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c)
#define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30) #define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30)
#define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34) #define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34)
......
...@@ -137,7 +137,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, ...@@ -137,7 +137,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_AGGR_ENCRYPTDELIM 10 #define ATH_AGGR_ENCRYPTDELIM 10
/* minimum h/w qdepth to be sustained to maximize aggregation */ /* minimum h/w qdepth to be sustained to maximize aggregation */
#define ATH_AGGR_MIN_QDEPTH 2 #define ATH_AGGR_MIN_QDEPTH 2
#define ATH_AMPDU_SUBFRAME_DEFAULT 32 /* minimum h/w qdepth for non-aggregated traffic */
#define ATH_NON_AGGR_MIN_QDEPTH 8
#define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_SEQ_MAX 4096 #define IEEE80211_SEQ_MAX 4096
...@@ -174,12 +175,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, ...@@ -174,12 +175,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_TX_COMPLETE_POLL_INT 1000 #define ATH_TX_COMPLETE_POLL_INT 1000
enum ATH_AGGR_STATUS {
ATH_AGGR_DONE,
ATH_AGGR_BAW_CLOSED,
ATH_AGGR_LIMITED,
};
#define ATH_TXFIFO_DEPTH 8 #define ATH_TXFIFO_DEPTH 8
struct ath_txq { struct ath_txq {
int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
...@@ -212,8 +207,9 @@ struct ath_frame_info { ...@@ -212,8 +207,9 @@ struct ath_frame_info {
int framelen; int framelen;
enum ath9k_key_type keytype; enum ath9k_key_type keytype;
u8 keyix; u8 keyix;
u8 retries;
u8 rtscts_rate; u8 rtscts_rate;
u8 retries : 7;
u8 baw_tracked : 1;
}; };
struct ath_buf_state { struct ath_buf_state {
...@@ -241,6 +237,7 @@ struct ath_buf { ...@@ -241,6 +237,7 @@ struct ath_buf {
struct ath_atx_tid { struct ath_atx_tid {
struct list_head list; struct list_head list;
struct sk_buff_head buf_q; struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an; struct ath_node *an;
struct ath_atx_ac *ac; struct ath_atx_ac *ac;
unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
...@@ -268,6 +265,7 @@ struct ath_node { ...@@ -268,6 +265,7 @@ struct ath_node {
u8 mpdudensity; u8 mpdudensity;
bool sleeping; bool sleeping;
bool no_ps_filter;
#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) #if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
struct dentry *node_stat; struct dentry *node_stat;
...@@ -367,6 +365,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, ...@@ -367,6 +365,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
/********/ /********/
struct ath_vif { struct ath_vif {
struct ath_node mcast_node;
int av_bslot; int av_bslot;
bool primary_sta_vif; bool primary_sta_vif;
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */ __le64 tsf_adjust; /* TSF adjustment for staggered beacons */
...@@ -585,19 +584,14 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) ...@@ -585,19 +584,14 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
#define ATH_ANT_DIV_COMB_MAX_COUNT 100 #define ATH_ANT_DIV_COMB_MAX_COUNT 100
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI 50
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI 50
#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1 #define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4 #define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2 #define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2 #define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
enum ath9k_ant_div_comb_lna_conf {
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
ATH_ANT_DIV_COMB_LNA2,
ATH_ANT_DIV_COMB_LNA1,
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
};
struct ath_ant_comb { struct ath_ant_comb {
u16 count; u16 count;
u16 total_pkt_count; u16 total_pkt_count;
...@@ -614,27 +608,35 @@ struct ath_ant_comb { ...@@ -614,27 +608,35 @@ struct ath_ant_comb {
int rssi_first; int rssi_first;
int rssi_second; int rssi_second;
int rssi_third; int rssi_third;
int ant_ratio;
int ant_ratio2;
bool alt_good; bool alt_good;
int quick_scan_cnt; int quick_scan_cnt;
int main_conf; enum ath9k_ant_div_comb_lna_conf main_conf;
enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf; enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf; enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
bool first_ratio; bool first_ratio;
bool second_ratio; bool second_ratio;
unsigned long scan_start_time; unsigned long scan_start_time;
/*
* Card-specific config values.
*/
int low_rssi_thresh;
int fast_div_bias;
}; };
void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
void ath_ant_comb_update(struct ath_softc *sc);
/********************/ /********************/
/* Main driver core */ /* Main driver core */
/********************/ /********************/
#define ATH9K_PCI_CUS198 0x0001 #define ATH9K_PCI_CUS198 0x0001
#define ATH9K_PCI_CUS230 0x0002 #define ATH9K_PCI_CUS230 0x0002
#define ATH9K_PCI_CUS217 0x0004 #define ATH9K_PCI_CUS217 0x0004
#define ATH9K_PCI_WOW 0x0008 #define ATH9K_PCI_WOW 0x0008
#define ATH9K_PCI_BT_ANT_DIV 0x0010
/* /*
* Default cache line size, in bytes. * Default cache line size, in bytes.
......
...@@ -270,25 +270,29 @@ static const struct file_operations fops_ani = { ...@@ -270,25 +270,29 @@ static const struct file_operations fops_ani = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t read_file_ant_diversity(struct file *file, char __user *user_buf, #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
size_t count, loff_t *ppos)
static ssize_t read_file_bt_ant_diversity(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{ {
struct ath_softc *sc = file->private_data; struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32]; char buf[32];
unsigned int len; unsigned int len;
len = sprintf(buf, "%d\n", common->antenna_diversity); len = sprintf(buf, "%d\n", common->bt_ant_diversity);
return simple_read_from_buffer(user_buf, count, ppos, buf, len); return simple_read_from_buffer(user_buf, count, ppos, buf, len);
} }
static ssize_t write_file_ant_diversity(struct file *file, static ssize_t write_file_bt_ant_diversity(struct file *file,
const char __user *user_buf, const char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath_softc *sc = file->private_data; struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long antenna_diversity; struct ath9k_hw_capabilities *pCap = &sc->sc_ah->caps;
unsigned long bt_ant_diversity;
char buf[32]; char buf[32];
ssize_t len; ssize_t len;
...@@ -296,26 +300,147 @@ static ssize_t write_file_ant_diversity(struct file *file, ...@@ -296,26 +300,147 @@ static ssize_t write_file_ant_diversity(struct file *file,
if (copy_from_user(buf, user_buf, len)) if (copy_from_user(buf, user_buf, len))
return -EFAULT; return -EFAULT;
if (!AR_SREV_9565(sc->sc_ah)) if (!(pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV))
goto exit; goto exit;
buf[len] = '\0'; buf[len] = '\0';
if (kstrtoul(buf, 0, &antenna_diversity)) if (kstrtoul(buf, 0, &bt_ant_diversity))
return -EINVAL; return -EINVAL;
common->antenna_diversity = !!antenna_diversity; common->bt_ant_diversity = !!bt_ant_diversity;
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
ath_ant_comb_update(sc); ath9k_hw_set_bt_ant_diversity(sc->sc_ah, common->bt_ant_diversity);
ath_dbg(common, CONFIG, "Antenna diversity: %d\n", ath_dbg(common, CONFIG, "Enable WLAN/BT RX Antenna diversity: %d\n",
common->antenna_diversity); common->bt_ant_diversity);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
exit: exit:
return count; return count;
} }
static const struct file_operations fops_ant_diversity = { static const struct file_operations fops_bt_ant_diversity = {
.read = read_file_ant_diversity, .read = read_file_bt_ant_diversity,
.write = write_file_ant_diversity, .write = write_file_bt_ant_diversity,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
#endif
void ath9k_debug_stat_ant(struct ath_softc *sc,
struct ath_hw_antcomb_conf *div_ant_conf,
int main_rssi_avg, int alt_rssi_avg)
{
struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
as_main->lna_attempt_cnt[div_ant_conf->main_lna_conf]++;
as_alt->lna_attempt_cnt[div_ant_conf->alt_lna_conf]++;
as_main->rssi_avg = main_rssi_avg;
as_alt->rssi_avg = alt_rssi_avg;
}
static ssize_t read_file_antenna_diversity(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_hw *ah = sc->sc_ah;
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
struct ath_hw_antcomb_conf div_ant_conf;
unsigned int len = 0, size = 1024;
ssize_t retval = 0;
char *buf;
char *lna_conf_str[4] = {"LNA1_MINUS_LNA2",
"LNA2",
"LNA1",
"LNA1_PLUS_LNA2"};
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
if (!(pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) {
len += snprintf(buf + len, size - len, "%s\n",
"Antenna Diversity Combining is disabled");
goto exit;
}
ath9k_ps_wakeup(sc);
ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
len += snprintf(buf + len, size - len, "Current MAIN config : %s\n",
lna_conf_str[div_ant_conf.main_lna_conf]);
len += snprintf(buf + len, size - len, "Current ALT config : %s\n",
lna_conf_str[div_ant_conf.alt_lna_conf]);
len += snprintf(buf + len, size - len, "Average MAIN RSSI : %d\n",
as_main->rssi_avg);
len += snprintf(buf + len, size - len, "Average ALT RSSI : %d\n\n",
as_alt->rssi_avg);
ath9k_ps_restore(sc);
len += snprintf(buf + len, size - len, "Packet Receive Cnt:\n");
len += snprintf(buf + len, size - len, "-------------------\n");
len += snprintf(buf + len, size - len, "%30s%15s\n",
"MAIN", "ALT");
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"TOTAL COUNT",
as_main->recv_cnt,
as_alt->recv_cnt);
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"LNA1",
as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1],
as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]);
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"LNA2",
as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2],
as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]);
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"LNA1 + LNA2",
as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"LNA1 - LNA2",
as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
len += snprintf(buf + len, size - len, "\nLNA Config Attempts:\n");
len += snprintf(buf + len, size - len, "--------------------\n");
len += snprintf(buf + len, size - len, "%30s%15s\n",
"MAIN", "ALT");
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"LNA1",
as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1],
as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]);
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"LNA2",
as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2],
as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]);
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"LNA1 + LNA2",
as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
"LNA1 - LNA2",
as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
exit:
if (len > size)
len = size;
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
}
static const struct file_operations fops_antenna_diversity = {
.read = read_file_antenna_diversity,
.open = simple_open, .open = simple_open,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = default_llseek, .llseek = default_llseek,
...@@ -607,6 +732,28 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, ...@@ -607,6 +732,28 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
return retval; return retval;
} }
static ssize_t print_queue(struct ath_softc *sc, struct ath_txq *txq,
char *buf, ssize_t size)
{
ssize_t len = 0;
ath_txq_lock(sc, txq);
len += snprintf(buf + len, size - len, "%s: %d ",
"qnum", txq->axq_qnum);
len += snprintf(buf + len, size - len, "%s: %2d ",
"qdepth", txq->axq_depth);
len += snprintf(buf + len, size - len, "%s: %2d ",
"ampdu-depth", txq->axq_ampdu_depth);
len += snprintf(buf + len, size - len, "%s: %3d ",
"pending", txq->pending_frames);
len += snprintf(buf + len, size - len, "%s: %d\n",
"stopped", txq->stopped);
ath_txq_unlock(sc, txq);
return len;
}
static ssize_t read_file_queues(struct file *file, char __user *user_buf, static ssize_t read_file_queues(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
...@@ -624,24 +771,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf, ...@@ -624,24 +771,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf,
for (i = 0; i < IEEE80211_NUM_ACS; i++) { for (i = 0; i < IEEE80211_NUM_ACS; i++) {
txq = sc->tx.txq_map[i]; txq = sc->tx.txq_map[i];
len += snprintf(buf + len, size - len, "(%s): ", qname[i]); len += snprintf(buf + len, size - len, "(%s): ", qname[i]);
len += print_queue(sc, txq, buf + len, size - len);
ath_txq_lock(sc, txq);
len += snprintf(buf + len, size - len, "%s: %d ",
"qnum", txq->axq_qnum);
len += snprintf(buf + len, size - len, "%s: %2d ",
"qdepth", txq->axq_depth);
len += snprintf(buf + len, size - len, "%s: %2d ",
"ampdu-depth", txq->axq_ampdu_depth);
len += snprintf(buf + len, size - len, "%s: %3d ",
"pending", txq->pending_frames);
len += snprintf(buf + len, size - len, "%s: %d\n",
"stopped", txq->stopped);
ath_txq_unlock(sc, txq);
} }
len += snprintf(buf + len, size - len, "(CAB): ");
len += print_queue(sc, sc->beacon.cabq, buf + len, size - len);
if (len > size) if (len > size)
len = size; len = size;
...@@ -1814,9 +1950,11 @@ int ath9k_init_debug(struct ath_hw *ah) ...@@ -1814,9 +1950,11 @@ int ath9k_init_debug(struct ath_hw *ah)
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
debugfs_create_file("diversity", S_IRUSR | S_IWUSR, debugfs_create_file("antenna_diversity", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_ant_diversity); sc->debug.debugfs_phy, sc, &fops_antenna_diversity);
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
debugfs_create_file("bt_ant_diversity", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_bt_ant_diversity);
debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_btcoex); &fops_btcoex);
#endif #endif
......
...@@ -28,9 +28,13 @@ struct fft_sample_tlv; ...@@ -28,9 +28,13 @@ struct fft_sample_tlv;
#ifdef CONFIG_ATH9K_DEBUGFS #ifdef CONFIG_ATH9K_DEBUGFS
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
#define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++ #define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++
#define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++
#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_recv_cnt[c]++;
#else #else
#define TX_STAT_INC(q, c) do { } while (0) #define TX_STAT_INC(q, c) do { } while (0)
#define RESET_STAT_INC(sc, type) do { } while (0) #define RESET_STAT_INC(sc, type) do { } while (0)
#define ANT_STAT_INC(i, c) do { } while (0)
#define ANT_LNA_INC(i, c) do { } while (0)
#endif #endif
enum ath_reset_type { enum ath_reset_type {
...@@ -243,11 +247,22 @@ struct ath_rx_stats { ...@@ -243,11 +247,22 @@ struct ath_rx_stats {
u32 rx_spectral; u32 rx_spectral;
}; };
#define ANT_MAIN 0
#define ANT_ALT 1
struct ath_antenna_stats {
u32 recv_cnt;
u32 rssi_avg;
u32 lna_recv_cnt[4];
u32 lna_attempt_cnt[4];
};
struct ath_stats { struct ath_stats {
struct ath_interrupt_stats istats; struct ath_interrupt_stats istats;
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
struct ath_rx_stats rxstats; struct ath_rx_stats rxstats;
struct ath_dfs_stats dfs_stats; struct ath_dfs_stats dfs_stats;
struct ath_antenna_stats ant_stats[2];
u32 reset[__RESET_TYPE_MAX]; u32 reset[__RESET_TYPE_MAX];
}; };
...@@ -281,10 +296,11 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, ...@@ -281,10 +296,11 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct dentry *dir); struct dentry *dir);
void ath_debug_send_fft_sample(struct ath_softc *sc, void ath_debug_send_fft_sample(struct ath_softc *sc,
struct fft_sample_tlv *fft_sample); struct fft_sample_tlv *fft_sample);
void ath9k_debug_stat_ant(struct ath_softc *sc,
struct ath_hw_antcomb_conf *div_ant_conf,
int main_rssi_avg, int alt_rssi_avg);
#else #else
#define RX_STAT_INC(c) /* NOP */ #define RX_STAT_INC(c) /* NOP */
...@@ -297,12 +313,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah) ...@@ -297,12 +313,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
static inline void ath9k_deinit_debug(struct ath_softc *sc) static inline void ath9k_deinit_debug(struct ath_softc *sc)
{ {
} }
static inline void ath_debug_stat_interrupt(struct ath_softc *sc, static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
enum ath9k_int status) enum ath9k_int status)
{ {
} }
static inline void ath_debug_stat_tx(struct ath_softc *sc, static inline void ath_debug_stat_tx(struct ath_softc *sc,
struct ath_buf *bf, struct ath_buf *bf,
struct ath_tx_status *ts, struct ath_tx_status *ts,
...@@ -310,10 +324,15 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc, ...@@ -310,10 +324,15 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc,
unsigned int flags) unsigned int flags)
{ {
} }
static inline void ath_debug_stat_rx(struct ath_softc *sc, static inline void ath_debug_stat_rx(struct ath_softc *sc,
struct ath_rx_status *rs) struct ath_rx_status *rs)
{ {
}
static inline void ath9k_debug_stat_ant(struct ath_softc *sc,
struct ath_hw_antcomb_conf *div_ant_conf,
int main_rssi_avg, int alt_rssi_avg)
{
} }
#endif /* CONFIG_ATH9K_DEBUGFS */ #endif /* CONFIG_ATH9K_DEBUGFS */
......
...@@ -812,6 +812,7 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, ...@@ -812,6 +812,7 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
struct ath9k_channel *chan) struct ath9k_channel *chan)
{ {
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct modal_eep_4k_header *pModal; struct modal_eep_4k_header *pModal;
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
struct base_eep_header_4k *pBase = &eep->baseEepHeader; struct base_eep_header_4k *pBase = &eep->baseEepHeader;
...@@ -858,6 +859,24 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, ...@@ -858,6 +859,24 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
regVal = REG_READ(ah, AR_PHY_CCK_DETECT); regVal = REG_READ(ah, AR_PHY_CCK_DETECT);
if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
/*
* If diversity combining is enabled,
* set MAIN to LNA1 and ALT to LNA2 initially.
*/
regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
regVal &= (~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF |
AR_PHY_9285_ANT_DIV_ALT_LNACONF));
regVal |= (ATH_ANT_DIV_COMB_LNA1 <<
AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S);
regVal |= (ATH_ANT_DIV_COMB_LNA2 <<
AR_PHY_9285_ANT_DIV_ALT_LNACONF_S);
regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS));
regVal |= (0 << AR_PHY_9285_FAST_DIV_BIAS_S);
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
}
} }
if (pModal->version >= 2) { if (pModal->version >= 2) {
......
...@@ -78,13 +78,16 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, ...@@ -78,13 +78,16 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
} }
static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
bool enable)
static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
{ {
if (ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv) if (ath9k_hw_ops(ah)->set_bt_ant_diversity)
ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv(ah, enable); ath9k_hw_ops(ah)->set_bt_ant_diversity(ah, enable);
} }
#endif
/* Private hardware call ops */ /* Private hardware call ops */
/* PHY ops */ /* PHY ops */
......
...@@ -1496,16 +1496,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ...@@ -1496,16 +1496,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
struct ath9k_channel *chan) struct ath9k_channel *chan)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
bool band_switch = false, mode_diff = false;
u8 ini_reloaded = 0;
u32 qnum; u32 qnum;
int r; int r;
bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
bool band_switch, mode_diff;
u8 ini_reloaded;
band_switch = (chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ)) != if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
(ah->curchan->channelFlags & (CHANNEL_2GHZ | u32 cur = ah->curchan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
CHANNEL_5GHZ)); u32 new = chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
mode_diff = (chan->chanmode != ah->curchan->chanmode); band_switch = (cur != new);
mode_diff = (chan->chanmode != ah->curchan->chanmode);
}
for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
if (ath9k_hw_numtxpending(ah, qnum)) { if (ath9k_hw_numtxpending(ah, qnum)) {
...@@ -1520,11 +1522,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ...@@ -1520,11 +1522,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
return false; return false;
} }
if (edma && (band_switch || mode_diff)) { if (band_switch || mode_diff) {
ath9k_hw_mark_phy_inactive(ah); ath9k_hw_mark_phy_inactive(ah);
udelay(5); udelay(5);
ath9k_hw_init_pll(ah, NULL); if (band_switch)
ath9k_hw_init_pll(ah, chan);
if (ath9k_hw_fast_chan_change(ah, chan, &ini_reloaded)) { if (ath9k_hw_fast_chan_change(ah, chan, &ini_reloaded)) {
ath_err(common, "Failed to do fast channel change\n"); ath_err(common, "Failed to do fast channel change\n");
...@@ -1541,22 +1544,21 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ...@@ -1541,22 +1544,21 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
} }
ath9k_hw_set_clockrate(ah); ath9k_hw_set_clockrate(ah);
ath9k_hw_apply_txpower(ah, chan, false); ath9k_hw_apply_txpower(ah, chan, false);
ath9k_hw_rfbus_done(ah);
if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
ath9k_hw_set_delta_slope(ah, chan); ath9k_hw_set_delta_slope(ah, chan);
ath9k_hw_spur_mitigate_freq(ah, chan); ath9k_hw_spur_mitigate_freq(ah, chan);
if (edma && (band_switch || mode_diff)) { if (band_switch || ini_reloaded)
ah->ah_flags |= AH_FASTCC; ah->eep_ops->set_board_values(ah, chan);
if (band_switch || ini_reloaded)
ah->eep_ops->set_board_values(ah, chan);
ath9k_hw_init_bb(ah, chan); ath9k_hw_init_bb(ah, chan);
ath9k_hw_rfbus_done(ah);
if (band_switch || ini_reloaded) if (band_switch || ini_reloaded) {
ath9k_hw_init_cal(ah, chan); ah->ah_flags |= AH_FASTCC;
ath9k_hw_init_cal(ah, chan);
ah->ah_flags &= ~AH_FASTCC; ah->ah_flags &= ~AH_FASTCC;
} }
...@@ -1778,16 +1780,11 @@ static void ath9k_hw_init_desc(struct ath_hw *ah) ...@@ -1778,16 +1780,11 @@ static void ath9k_hw_init_desc(struct ath_hw *ah)
/* /*
* Fast channel change: * Fast channel change:
* (Change synthesizer based on channel freq without resetting chip) * (Change synthesizer based on channel freq without resetting chip)
*
* Don't do FCC when
* - Flag is not set
* - Chip is just coming out of full sleep
* - Channel to be set is same as current channel
* - Channel flags are different, (eg.,moving from 2GHz to 5GHz channel)
*/ */
static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
int ret; int ret;
if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI)
...@@ -1806,9 +1803,21 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -1806,9 +1803,21 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
(CHANNEL_HALF | CHANNEL_QUARTER)) (CHANNEL_HALF | CHANNEL_QUARTER))
goto fail; goto fail;
if ((chan->channelFlags & CHANNEL_ALL) != /*
(ah->curchan->channelFlags & CHANNEL_ALL)) * If cross-band fcc is not supoprted, bail out if
goto fail; * either channelFlags or chanmode differ.
*
* chanmode will be different if the HT operating mode
* changes because of CSA.
*/
if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH)) {
if ((chan->channelFlags & CHANNEL_ALL) !=
(ah->curchan->channelFlags & CHANNEL_ALL))
goto fail;
if (chan->chanmode != ah->curchan->chanmode)
goto fail;
}
if (!ath9k_hw_check_alive(ah)) if (!ath9k_hw_check_alive(ah))
goto fail; goto fail;
...@@ -2047,7 +2056,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -2047,7 +2056,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_apply_gpio_override(ah); ath9k_hw_apply_gpio_override(ah);
if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv) if (AR_SREV_9565(ah) && common->bt_ant_diversity)
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
return 0; return 0;
...@@ -2504,7 +2513,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ...@@ -2504,7 +2513,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
else else
pCap->rts_aggr_limit = (8 * 1024); pCap->rts_aggr_limit = (8 * 1024);
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) #ifdef CONFIG_ATH9K_RFKILL
ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT);
if (ah->rfsilent & EEP_RFSILENT_ENABLED) { if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
ah->rfkill_gpio = ah->rfkill_gpio =
...@@ -2550,34 +2559,28 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ...@@ -2550,34 +2559,28 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah)) if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
pCap->hw_caps |= ATH9K_HW_CAP_SGI_20; pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
if (AR_SREV_9285(ah)) if (AR_SREV_9285(ah)) {
if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) { if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) {
ant_div_ctl1 = ant_div_ctl1 =
ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1)) if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1)) {
pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
ath_info(common, "Enable LNA combining\n");
}
} }
}
if (AR_SREV_9300_20_OR_LATER(ah)) { if (AR_SREV_9300_20_OR_LATER(ah)) {
if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE)) if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE))
pCap->hw_caps |= ATH9K_HW_CAP_APM; pCap->hw_caps |= ATH9K_HW_CAP_APM;
} }
if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) { if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
/* if ((ant_div_ctl1 >> 0x6) == 0x3) {
* enable the diversity-combining algorithm only when
* both enable_lna_div and enable_fast_div are set
* Table for Diversity
* ant_div_alt_lnaconf bit 0-1
* ant_div_main_lnaconf bit 2-3
* ant_div_alt_gaintb bit 4
* ant_div_main_gaintb bit 5
* enable_ant_div_lnadiv bit 6
* enable_ant_fast_div bit 7
*/
if ((ant_div_ctl1 >> 0x6) == 0x3)
pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
ath_info(common, "Enable LNA combining\n");
}
} }
if (ath9k_hw_dfs_tested(ah)) if (ath9k_hw_dfs_tested(ah))
...@@ -2610,6 +2613,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ...@@ -2610,6 +2613,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
/*
* Fast channel change across bands is available
* only for AR9462 and AR9565.
*/
if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH;
return 0; return 0;
} }
......
...@@ -247,6 +247,8 @@ enum ath9k_hw_caps { ...@@ -247,6 +247,8 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_DFS = BIT(16), ATH9K_HW_CAP_DFS = BIT(16),
ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17),
ATH9K_HW_CAP_PAPRD = BIT(18), ATH9K_HW_CAP_PAPRD = BIT(18),
ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(19),
ATH9K_HW_CAP_BT_ANT_DIV = BIT(20),
}; };
/* /*
...@@ -310,6 +312,7 @@ struct ath9k_ops_config { ...@@ -310,6 +312,7 @@ struct ath9k_ops_config {
/* Platform specific config */ /* Platform specific config */
u32 xlna_gpio; u32 xlna_gpio;
u32 ant_ctrl_comm2g_switch_enable;
bool xatten_margin_cfg; bool xatten_margin_cfg;
}; };
...@@ -716,11 +719,14 @@ struct ath_hw_ops { ...@@ -716,11 +719,14 @@ struct ath_hw_ops {
struct ath_hw_antcomb_conf *antconf); struct ath_hw_antcomb_conf *antconf);
void (*antdiv_comb_conf_set)(struct ath_hw *ah, void (*antdiv_comb_conf_set)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf); struct ath_hw_antcomb_conf *antconf);
void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
void (*spectral_scan_config)(struct ath_hw *ah, void (*spectral_scan_config)(struct ath_hw *ah,
struct ath_spec_scan *param); struct ath_spec_scan *param);
void (*spectral_scan_trigger)(struct ath_hw *ah); void (*spectral_scan_trigger)(struct ath_hw *ah);
void (*spectral_scan_wait)(struct ath_hw *ah); void (*spectral_scan_wait)(struct ath_hw *ah);
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable);
#endif
}; };
struct ath_nf_limits { struct ath_nf_limits {
...@@ -765,7 +771,6 @@ struct ath_hw { ...@@ -765,7 +771,6 @@ struct ath_hw {
bool aspm_enabled; bool aspm_enabled;
bool is_monitoring; bool is_monitoring;
bool need_an_top2_fixup; bool need_an_top2_fixup;
bool shared_chain_lnadiv;
u16 tx_trig_level; u16 tx_trig_level;
u32 nf_regs[6]; u32 nf_regs[6];
......
...@@ -53,9 +53,9 @@ static int ath9k_btcoex_enable; ...@@ -53,9 +53,9 @@ static int ath9k_btcoex_enable;
module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
static int ath9k_enable_diversity; static int ath9k_bt_ant_diversity;
module_param_named(enable_diversity, ath9k_enable_diversity, int, 0444); module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444);
MODULE_PARM_DESC(enable_diversity, "Enable Antenna diversity for AR9565"); MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity");
bool is_ath9k_unloaded; bool is_ath9k_unloaded;
/* We use the hw_value as an index into our private channel structure */ /* We use the hw_value as an index into our private channel structure */
...@@ -516,6 +516,7 @@ static void ath9k_init_misc(struct ath_softc *sc) ...@@ -516,6 +516,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
static void ath9k_init_platform(struct ath_softc *sc) static void ath9k_init_platform(struct ath_softc *sc)
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
if (common->bus_ops->ath_bus_type != ATH_PCI) if (common->bus_ops->ath_bus_type != ATH_PCI)
...@@ -525,12 +526,21 @@ static void ath9k_init_platform(struct ath_softc *sc) ...@@ -525,12 +526,21 @@ static void ath9k_init_platform(struct ath_softc *sc)
ATH9K_PCI_CUS230)) { ATH9K_PCI_CUS230)) {
ah->config.xlna_gpio = 9; ah->config.xlna_gpio = 9;
ah->config.xatten_margin_cfg = true; ah->config.xatten_margin_cfg = true;
ah->config.ant_ctrl_comm2g_switch_enable = 0x000BBB88;
sc->ant_comb.low_rssi_thresh = 20;
sc->ant_comb.fast_div_bias = 3;
ath_info(common, "Set parameters for %s\n", ath_info(common, "Set parameters for %s\n",
(sc->driver_data & ATH9K_PCI_CUS198) ? (sc->driver_data & ATH9K_PCI_CUS198) ?
"CUS198" : "CUS230"); "CUS198" : "CUS230");
} else if (sc->driver_data & ATH9K_PCI_CUS217) { }
if (sc->driver_data & ATH9K_PCI_CUS217)
ath_info(common, "CUS217 card detected\n"); ath_info(common, "CUS217 card detected\n");
if (sc->driver_data & ATH9K_PCI_BT_ANT_DIV) {
pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV;
ath_info(common, "Set BT/WLAN RX diversity capability\n");
} }
} }
...@@ -584,6 +594,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -584,6 +594,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
{ {
struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath9k_platform_data *pdata = sc->dev->platform_data;
struct ath_hw *ah = NULL; struct ath_hw *ah = NULL;
struct ath9k_hw_capabilities *pCap;
struct ath_common *common; struct ath_common *common;
int ret = 0, i; int ret = 0, i;
int csz = 0; int csz = 0;
...@@ -600,6 +611,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -600,6 +611,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ah->reg_ops.rmw = ath9k_reg_rmw; ah->reg_ops.rmw = ath9k_reg_rmw;
atomic_set(&ah->intr_ref_cnt, -1); atomic_set(&ah->intr_ref_cnt, -1);
sc->sc_ah = ah; sc->sc_ah = ah;
pCap = &ah->caps;
sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET); sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET);
...@@ -631,11 +643,15 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -631,11 +643,15 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ath9k_init_platform(sc); ath9k_init_platform(sc);
/* /*
* Enable Antenna diversity only when BTCOEX is disabled * Enable WLAN/BT RX Antenna diversity only when:
* and the user manually requests the feature. *
* - BTCOEX is disabled.
* - the user manually requests the feature.
* - the HW cap is set using the platform data.
*/ */
if (!common->btcoex_enabled && ath9k_enable_diversity) if (!common->btcoex_enabled && ath9k_bt_ant_diversity &&
common->antenna_diversity = 1; (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV))
common->bt_ant_diversity = 1;
spin_lock_init(&common->cc_lock); spin_lock_init(&common->cc_lock);
......
...@@ -238,9 +238,6 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ...@@ -238,9 +238,6 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
ath_restart_work(sc); ath_restart_work(sc);
} }
if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
ath_ant_comb_update(sc);
ieee80211_wake_queues(sc->hw); ieee80211_wake_queues(sc->hw);
return true; return true;
...@@ -966,6 +963,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ...@@ -966,6 +963,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_node *an = &avp->mcast_node;
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
...@@ -979,6 +978,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ...@@ -979,6 +978,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
if (ath9k_uses_beacons(vif->type)) if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif); ath9k_beacon_assign_slot(sc, vif);
an->sc = sc;
an->sta = NULL;
an->vif = vif;
an->no_ps_filter = true;
ath_tx_node_init(sc, an);
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
return 0; return 0;
} }
...@@ -1016,6 +1021,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ...@@ -1016,6 +1021,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
ath_dbg(common, CONFIG, "Detach Interface\n"); ath_dbg(common, CONFIG, "Detach Interface\n");
...@@ -1030,6 +1036,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ...@@ -1030,6 +1036,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
ath9k_calculate_summary_state(hw, NULL); ath9k_calculate_summary_state(hw, NULL);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
ath_tx_node_cleanup(sc, &avp->mcast_node);
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
} }
...@@ -1374,9 +1382,6 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, ...@@ -1374,9 +1382,6 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_node *an = (struct ath_node *) sta->drv_priv; struct ath_node *an = (struct ath_node *) sta->drv_priv;
if (!sta->ht_cap.ht_supported)
return;
switch (cmd) { switch (cmd) {
case STA_NOTIFY_SLEEP: case STA_NOTIFY_SLEEP:
an->sleeping = true; an->sleeping = true;
...@@ -2094,7 +2099,7 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc, ...@@ -2094,7 +2099,7 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc,
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath9k_wow_pattern *wow_pattern = NULL; struct ath9k_wow_pattern *wow_pattern = NULL;
struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns; struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
int mask_len; int mask_len;
s8 i = 0; s8 i = 0;
......
...@@ -29,6 +29,14 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { ...@@ -29,6 +29,14 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
/* AR9285 card for Asus */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x002B,
PCI_VENDOR_ID_AZWAVE,
0x2C37),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
...@@ -40,29 +48,101 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { ...@@ -40,29 +48,101 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
0x0032, 0x0032,
PCI_VENDOR_ID_AZWAVE, PCI_VENDOR_ID_AZWAVE,
0x2086), 0x2086),
.driver_data = ATH9K_PCI_CUS198 }, .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032, 0x0032,
PCI_VENDOR_ID_AZWAVE, PCI_VENDOR_ID_AZWAVE,
0x1237), 0x1237),
.driver_data = ATH9K_PCI_CUS198 }, .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032, 0x0032,
PCI_VENDOR_ID_AZWAVE, PCI_VENDOR_ID_AZWAVE,
0x2126), 0x2126),
.driver_data = ATH9K_PCI_CUS198 }, .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
/* PCI-E CUS230 */ /* PCI-E CUS230 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032, 0x0032,
PCI_VENDOR_ID_AZWAVE, PCI_VENDOR_ID_AZWAVE,
0x2152), 0x2152),
.driver_data = ATH9K_PCI_CUS230 }, .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032, 0x0032,
PCI_VENDOR_ID_FOXCONN, PCI_VENDOR_ID_FOXCONN,
0xE075), 0xE075),
.driver_data = ATH9K_PCI_CUS230 }, .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV },
/* WB225 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_ATHEROS,
0x3119),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_ATHEROS,
0x3122),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
0x185F, /* WNC */
0x3119),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
0x185F, /* WNC */
0x3027),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_SAMSUNG,
0x4105),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_SAMSUNG,
0x4106),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_SAMSUNG,
0x410D),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_SAMSUNG,
0x410E),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_SAMSUNG,
0x410F),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_SAMSUNG,
0xC706),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_SAMSUNG,
0xC680),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_SAMSUNG,
0xC708),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_LENOVO,
0x3218),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_LENOVO,
0x3219),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
{ PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */
{ PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */ { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */
......
...@@ -48,4 +48,11 @@ ...@@ -48,4 +48,11 @@
#define AR_PHY_PLL_CONTROL 0x16180 #define AR_PHY_PLL_CONTROL 0x16180
#define AR_PHY_PLL_MODE 0x16184 #define AR_PHY_PLL_MODE 0x16184
enum ath9k_ant_div_comb_lna_conf {
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
ATH_ANT_DIV_COMB_LNA2,
ATH_ANT_DIV_COMB_LNA1,
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
};
#endif #endif
...@@ -1275,6 +1275,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, ...@@ -1275,6 +1275,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
} }
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct cfg80211_chan_def *chandef,
struct ieee80211_sta *sta, void *priv_sta) struct ieee80211_sta *sta, void *priv_sta)
{ {
struct ath_softc *sc = priv; struct ath_softc *sc = priv;
...@@ -1313,6 +1314,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, ...@@ -1313,6 +1314,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
} }
static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
struct cfg80211_chan_def *chandef,
struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_sta *sta, void *priv_sta,
u32 changed) u32 changed)
{ {
......
...@@ -1157,6 +1157,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ...@@ -1157,6 +1157,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb; struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb;
struct ieee80211_rx_status *rxs; struct ieee80211_rx_status *rxs;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hw *hw = sc->hw; struct ieee80211_hw *hw = sc->hw;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
...@@ -1328,11 +1329,30 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ...@@ -1328,11 +1329,30 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
skb = hdr_skb; skb = hdr_skb;
} }
if (rxs->flag & RX_FLAG_MMIC_STRIPPED)
skb_trim(skb, skb->len - 8);
if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA)) ||
ath9k_check_auto_sleep(sc))
ath_rx_ps(sc, skb, rs.is_mybeacon);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
/*
* Run the LNA combining algorithm only in these cases:
*
* Standalone WLAN cards with both LNA/Antenna diversity
* enabled in the EEPROM.
*
* WLAN+BT cards which are in the supported card list
* in ath_pci_id_table and the user has loaded the
* driver with "bt_ant_diversity" set to true.
*/
if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
/* /*
* change the default rx antenna if rx diversity * Change the default rx antenna if rx diversity
* chooses the other antenna 3 times in a row. * chooses the other antenna 3 times in a row.
*/ */
if (sc->rx.defant != rs.rs_antenna) { if (sc->rx.defant != rs.rs_antenna) {
...@@ -1342,22 +1362,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ...@@ -1342,22 +1362,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
sc->rx.rxotherant = 0; sc->rx.rxotherant = 0;
} }
if (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV) {
if (common->bt_ant_diversity)
ath_ant_comb_scan(sc, &rs);
} else {
ath_ant_comb_scan(sc, &rs);
}
} }
if (rxs->flag & RX_FLAG_MMIC_STRIPPED)
skb_trim(skb, skb->len - 8);
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA)) ||
ath9k_check_auto_sleep(sc))
ath_rx_ps(sc, skb, rs.is_mybeacon);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
ath_ant_comb_scan(sc, &rs);
ath9k_apply_ampdu_details(sc, &rs, rxs); ath9k_apply_ampdu_details(sc, &rs, rxs);
ieee80211_rx(hw, skb); ieee80211_rx(hw, skb);
......
...@@ -11,9 +11,6 @@ wil6210-y += txrx.o ...@@ -11,9 +11,6 @@ wil6210-y += txrx.o
wil6210-y += debug.o wil6210-y += debug.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
subdir-ccflags-y += -Werror
endif
# for tracing framework to find trace.h # for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src) CFLAGS_trace.o := -I$(src)
......
...@@ -51,7 +51,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, ...@@ -51,7 +51,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
if ((i % 64) == 0 && (i != 0)) if ((i % 64) == 0 && (i != 0))
seq_printf(s, "\n"); seq_printf(s, "\n");
seq_printf(s, "%s", (d->dma.status & BIT(0)) ? seq_printf(s, "%s", (d->dma.status & BIT(0)) ?
"S" : (vring->ctx[i] ? "H" : "h")); "S" : (vring->ctx[i].skb ? "H" : "h"));
} }
seq_printf(s, "\n"); seq_printf(s, "\n");
} }
...@@ -406,7 +406,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) ...@@ -406,7 +406,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
volatile struct vring_tx_desc *d = volatile struct vring_tx_desc *d =
&(vring->va[dbg_txdesc_index].tx); &(vring->va[dbg_txdesc_index].tx);
volatile u32 *u = (volatile u32 *)d; volatile u32 *u = (volatile u32 *)d;
struct sk_buff *skb = vring->ctx[dbg_txdesc_index]; struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index);
seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
......
...@@ -127,6 +127,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ...@@ -127,6 +127,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
ndev->netdev_ops = &wil_netdev_ops; ndev->netdev_ops = &wil_netdev_ops;
ndev->ieee80211_ptr = wdev; ndev->ieee80211_ptr = wdev;
ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev; wdev->netdev = ndev;
......
...@@ -37,36 +37,40 @@ static inline void trace_ ## name(proto) {} ...@@ -37,36 +37,40 @@ static inline void trace_ ## name(proto) {}
#endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */ #endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */
DECLARE_EVENT_CLASS(wil6210_wmi, DECLARE_EVENT_CLASS(wil6210_wmi,
TP_PROTO(u16 id, void *buf, u16 buf_len), TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len), TP_ARGS(wmi, buf, buf_len),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u8, mid)
__field(u16, id) __field(u16, id)
__field(u32, timestamp)
__field(u16, buf_len) __field(u16, buf_len)
__dynamic_array(u8, buf, buf_len) __dynamic_array(u8, buf, buf_len)
), ),
TP_fast_assign( TP_fast_assign(
__entry->id = id; __entry->mid = wmi->mid;
__entry->id = le16_to_cpu(wmi->id);
__entry->timestamp = le32_to_cpu(wmi->timestamp);
__entry->buf_len = buf_len; __entry->buf_len = buf_len;
memcpy(__get_dynamic_array(buf), buf, buf_len); memcpy(__get_dynamic_array(buf), buf, buf_len);
), ),
TP_printk( TP_printk(
"id 0x%04x len %d", "MID %d id 0x%04x len %d timestamp %d",
__entry->id, __entry->buf_len __entry->mid, __entry->id, __entry->buf_len, __entry->timestamp
) )
); );
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd, DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd,
TP_PROTO(u16 id, void *buf, u16 buf_len), TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len) TP_ARGS(wmi, buf, buf_len)
); );
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event, DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event,
TP_PROTO(u16 id, void *buf, u16 buf_len), TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len) TP_ARGS(wmi, buf, buf_len)
); );
#define WIL6210_MSG_MAX (200) #define WIL6210_MSG_MAX (200)
......
...@@ -4164,9 +4164,7 @@ static struct cfg80211_ops wl_cfg80211_ops = { ...@@ -4164,9 +4164,7 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.stop_p2p_device = brcmf_p2p_stop_device, .stop_p2p_device = brcmf_p2p_stop_device,
.crit_proto_start = brcmf_cfg80211_crit_proto_start, .crit_proto_start = brcmf_cfg80211_crit_proto_start,
.crit_proto_stop = brcmf_cfg80211_crit_proto_stop, .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
#ifdef CONFIG_NL80211_TESTMODE CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
.testmode_cmd = brcmf_cfg80211_testmode
#endif
}; };
static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type) static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
......
...@@ -882,8 +882,8 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) ...@@ -882,8 +882,8 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
mcl = le16_to_cpu(txh->MacTxControlLow); mcl = le16_to_cpu(txh->MacTxControlLow);
if (txs->phyerr) if (txs->phyerr)
brcms_err(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n", brcms_dbg_tx(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n",
txs->phyerr, txh->MainRates); txs->phyerr, txh->MainRates);
if (txs->frameid != le16_to_cpu(txh->TxFrameID)) { if (txs->frameid != le16_to_cpu(txh->TxFrameID)) {
brcms_err(wlc->hw->d11core, "frameid != txh->TxFrameID\n"); brcms_err(wlc->hw->d11core, "frameid != txh->TxFrameID\n");
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册