提交 89c2af3c 编写于 作者: J John W. Linville

Merge branch 'master' of...

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

Conflicts:
	drivers/net/ethernet/broadcom/Kconfig
......@@ -4360,7 +4360,7 @@ F: drivers/net/wireless/iwlegacy/
INTEL WIRELESS WIFI LINK (iwlwifi)
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>
L: linux-wireless@vger.kernel.org
W: http://intellinuxwireless.org
......
......@@ -35,8 +35,14 @@ config BCMA_DRIVER_PCI_HOSTMODE
PCI core hostmode operation (external PCI bus).
config BCMA_HOST_SOC
bool
depends on BCMA_DRIVER_MIPS
bool "Support for BCMA in a SoC"
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
bool "BCMA Broadcom MIPS core driver"
......
......@@ -237,7 +237,7 @@ int bcma_bus_register(struct bcma_bus *bus)
err = bcma_bus_scan(bus);
if (err) {
bcma_err(bus, "Failed to scan: %d\n", err);
return -1;
return err;
}
/* Early init CC core */
......
......@@ -32,6 +32,18 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = {
{ BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
{ BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
{ 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_ALTA, "ALTA (I2S)" },
{ BCMA_CORE_INVALID, "Invalid" },
......@@ -201,7 +213,7 @@ static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
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 addrl, addrh, sizel, sizeh = 0;
......@@ -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_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
bcma_erom_push_ent(eromptr);
return -EINVAL;
return (u32)-EINVAL;
}
addrl = ent & SCAN_ADDR_ADDR;
......@@ -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 *core)
{
s32 tmp;
u32 tmp;
u8 i, j;
s32 cia, cib;
u8 ports[2], wrappers[2];
......@@ -339,11 +351,11 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
* the main register space for the core
*/
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 */
tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_BRIDGE, 0);
if (tmp <= 0) {
if (tmp == 0 || IS_ERR_VALUE(tmp)) {
return -EILSEQ;
} else {
bcma_info(bus, "Bridge found\n");
......@@ -357,7 +369,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_SLAVE, i);
if (tmp < 0) {
if (IS_ERR_VALUE(tmp)) {
/* no more entries for port _i_ */
/* pr_debug("erom: slave port %d "
* "has %d descriptors\n", i, j); */
......@@ -374,7 +386,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_MWRAP, i);
if (tmp < 0) {
if (IS_ERR_VALUE(tmp)) {
/* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d "
* "has %d descriptors\n", i, j); */
......@@ -392,7 +404,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_SWRAP, i + hack);
if (tmp < 0) {
if (IS_ERR_VALUE(tmp)) {
/* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d "
* has %d descriptors\n", i, j); */
......
......@@ -130,7 +130,7 @@ config BNX2X_SRIOV
config BGMAC
tristate "BCMA bus GBit core support"
depends on BCMA_HOST_SOC && HAS_DMA
depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
select PHYLIB
---help---
This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
......
......@@ -159,7 +159,7 @@ struct ath_common {
bool btcoex_enabled;
bool disable_ani;
bool antenna_diversity;
bool bt_ant_diversity;
};
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
......
......@@ -20,6 +20,12 @@
#include "debug.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)
{
struct bmi_cmd cmd;
......@@ -105,7 +111,8 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
&resp, &rxlen);
if (ret) {
ath10k_warn("unable to read from the device\n");
ath10k_warn("unable to read from the device (%d)\n",
ret);
return ret;
}
......@@ -149,7 +156,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
NULL, NULL);
if (ret) {
ath10k_warn("unable to write to the device\n");
ath10k_warn("unable to write to the device (%d)\n",
ret);
return ret;
}
......
......@@ -184,6 +184,7 @@ struct bmi_target_info {
#define BMI_CE_NUM_TO_TARG 0
#define BMI_CE_NUM_TO_HOST 1
void ath10k_bmi_start(struct ath10k *ar);
int ath10k_bmi_done(struct ath10k *ar);
int ath10k_bmi_get_target_info(struct ath10k *ar,
struct bmi_target_info *target_info);
......
......@@ -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);
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);
return;
}
......
......@@ -100,7 +100,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar)
goto conn_fail;
/* Start HTC */
status = ath10k_htc_start(ar->htc);
status = ath10k_htc_start(&ar->htc);
if (status)
goto conn_fail;
......@@ -116,7 +116,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar)
return 0;
timeout:
ath10k_htc_stop(ar->htc);
ath10k_htc_stop(&ar->htc);
conn_fail:
return status;
}
......@@ -247,19 +247,11 @@ static int ath10k_push_board_ext_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 address;
const struct firmware *fw;
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);
if (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)
}
exit:
release_firmware(fw);
return ret;
}
static int ath10k_download_and_run_otp(struct ath10k *ar)
{
const struct firmware *fw;
u32 address;
const struct firmware *fw = ar->otp;
u32 address = ar->hw_params.patch_load_addr;
u32 exec_param;
int ret;
/* OTP is optional */
if (ar->hw_params.fw.otp == NULL) {
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));
if (!ar->otp)
return 0;
}
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
if (ret) {
......@@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
}
exit:
release_firmware(fw);
return ret;
}
static int ath10k_download_fw(struct ath10k *ar)
{
const struct firmware *fw;
const struct firmware *fw = ar->firmware;
u32 address;
int ret;
if (ar->hw_params.fw.fw == NULL)
return -EINVAL;
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);
if (ret) {
ath10k_err("could not write fw (%d)\n", ret);
......@@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar)
}
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;
}
......@@ -440,8 +476,35 @@ static int ath10k_init_hw_params(struct ath10k *ar)
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,
enum ath10k_bus bus,
const struct ath10k_hif_ops *hif_ops)
{
struct ath10k *ar;
......@@ -458,9 +521,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
ar->hif.priv = hif_priv;
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.completed);
......@@ -487,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_waitqueue_head(&ar->event_queue);
INIT_WORK(&ar->restart_work, ath10k_core_restart);
return ar;
err_wq:
......@@ -504,24 +566,11 @@ void ath10k_core_destroy(struct ath10k *ar)
}
EXPORT_SYMBOL(ath10k_core_destroy);
int ath10k_core_register(struct ath10k *ar)
int ath10k_core_start(struct ath10k *ar)
{
struct ath10k_htc_ops htc_ops;
struct bmi_target_info target_info;
int status;
memset(&target_info, 0, sizeof(target_info));
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;
ath10k_bmi_start(ar);
if (ath10k_init_configure_target(ar)) {
status = -EINVAL;
......@@ -536,32 +585,32 @@ int ath10k_core_register(struct ath10k *ar)
if (status)
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);
if (IS_ERR(ar->htc)) {
status = PTR_ERR(ar->htc);
ath10k_err("could not create HTC (%d)\n", status);
status = ath10k_htc_init(ar);
if (status) {
ath10k_err("could not init HTC (%d)\n", status);
goto err;
}
status = ath10k_bmi_done(ar);
if (status)
goto err_htc_destroy;
goto err;
status = ath10k_wmi_attach(ar);
if (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)
goto err_wmi_detach;
ar->htt = ath10k_htt_attach(ar);
if (!ar->htt) {
status = -ENOMEM;
status = ath10k_htt_attach(ar);
if (status) {
ath10k_err("could not attach htt (%d)\n", status);
goto err_wmi_detach;
}
......@@ -588,77 +637,127 @@ int ath10k_core_register(struct ath10k *ar)
goto err_disconnect_htc;
}
status = ath10k_htt_attach_target(ar->htt);
if (status)
goto err_disconnect_htc;
status = ath10k_mac_register(ar);
status = ath10k_htt_attach_target(&ar->htt);
if (status)
goto err_disconnect_htc;
status = ath10k_debug_create(ar);
if (status) {
ath10k_err("unable to initialize debugfs\n");
goto err_unregister_mac;
}
ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
return 0;
err_unregister_mac:
ath10k_mac_unregister(ar);
err_disconnect_htc:
ath10k_htc_stop(ar->htc);
ath10k_htc_stop(&ar->htc);
err_htt_detach:
ath10k_htt_detach(ar->htt);
ath10k_htt_detach(&ar->htt);
err_wmi_detach:
ath10k_wmi_detach(ar);
err_htc_destroy:
ath10k_htc_destroy(ar->htc);
err:
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.
* Otherwise we will fail to submit commands to FW and mac80211 will be
* unhappy about callback failures. */
ath10k_mac_unregister(ar);
ath10k_htc_stop(ar->htc);
ath10k_htt_detach(ar->htt);
ath10k_htc_stop(&ar->htc);
ath10k_htt_detach(&ar->htt);
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);
if (ret)
ath10k_warn("could not suspend target (%d)\n", ret);
ar->target_version = target_info.version;
ar->hw->wiphy->hw_version = target_info.version;
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);
if (ret)
ath10k_warn("could not resume target (%d)\n", ret);
status = ath10k_mac_register(ar);
if (status) {
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_DESCRIPTION("Core module for QCA988X PCIe devices.");
......
......@@ -23,6 +23,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include "htt.h"
#include "htc.h"
#include "hw.h"
#include "targaddrs.h"
......@@ -43,10 +44,6 @@
struct ath10k;
enum ath10k_bus {
ATH10K_BUS_PCI,
};
struct ath10k_skb_cb {
dma_addr_t paddr;
bool is_mapped;
......@@ -250,6 +247,28 @@ struct ath10k_debug {
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 ath_common ath_common;
struct ieee80211_hw *hw;
......@@ -274,19 +293,16 @@ struct ath10k {
struct {
void *priv;
enum ath10k_bus bus;
const struct ath10k_hif_ops *ops;
} hif;
struct ath10k_wmi wmi;
wait_queue_head_t event_queue;
bool is_target_paused;
struct ath10k_bmi bmi;
struct ath10k_htc *htc;
struct ath10k_htt *htt;
struct ath10k_wmi wmi;
struct ath10k_htc htc;
struct ath10k_htt htt;
struct ath10k_hw_params {
u32 id;
......@@ -301,6 +317,10 @@ struct ath10k {
} fw;
} hw_params;
const struct firmware *board_data;
const struct firmware *otp;
const struct firmware *firmware;
struct {
struct completion started;
struct completion completed;
......@@ -350,20 +370,22 @@ struct ath10k {
struct completion offchan_tx_completed;
struct sk_buff *offchan_tx_skb;
enum ath10k_state state;
struct work_struct restart_work;
#ifdef CONFIG_ATH10K_DEBUGFS
struct ath10k_debug debug;
#endif
};
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
enum ath10k_bus bus,
const struct ath10k_hif_ops *hif_ops);
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);
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_ */
......@@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
struct wmi_pdev_stats *ps;
int i;
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
stats = &ar->debug.target_stats;
......@@ -259,6 +259,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
}
}
spin_unlock_bh(&ar->data_lock);
mutex_unlock(&ar->conf_mutex);
complete(&ar->debug.event_stats_compl);
}
......@@ -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_target_stats *fw_stats;
char *buf;
char *buf = NULL;
unsigned int len = 0, buf_len = 2500;
ssize_t ret_cnt;
ssize_t ret_cnt = 0;
long left;
int i;
int ret;
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);
if (!buf)
return -ENOMEM;
goto exit;
ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
if (ret) {
ath10k_warn("could not request stats (%d)\n", ret);
kfree(buf);
return -EIO;
goto exit;
}
left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
if (left <= 0)
goto exit;
if (left <= 0) {
kfree(buf);
return -ETIMEDOUT;
}
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s\n",
"ath10k PDEV stats");
......@@ -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);
len += scnprintf(buf + len, buf_len - len, "\n");
}
spin_unlock_bh(&ar->data_lock);
if (len > buf_len)
len = buf_len;
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
exit:
mutex_unlock(&ar->conf_mutex);
kfree(buf);
return ret_cnt;
}
......@@ -443,6 +445,60 @@ static const struct file_operations fops_fw_stats = {
.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)
{
ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
......@@ -459,6 +515,9 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_wmi_services);
debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_simulate_fw_crash);
return 0;
}
#endif /* CONFIG_ATH10K_DEBUGFS */
......
......@@ -46,8 +46,11 @@ struct ath10k_hif_ops {
void *request, u32 request_len,
void *response, u32 *response_len);
/* Post BMI phase, after FW is loaded. Starts regular operation */
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);
int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
......@@ -66,10 +69,20 @@ struct ath10k_hif_ops {
*/
void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force);
void (*init)(struct ath10k *ar,
struct ath10k_hif_cb *callbacks);
void (*set_callbacks)(struct ath10k *ar,
struct ath10k_hif_cb *callbacks);
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,
ar->hif.ops->send_complete_check(ar, pipe_id, force);
}
static inline void ath10k_hif_init(struct ath10k *ar,
struct ath10k_hif_cb *callbacks)
static inline void ath10k_hif_set_callbacks(struct ath10k *ar,
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,
......@@ -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);
}
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_ */
......@@ -246,15 +246,22 @@ int ath10k_htc_send(struct ath10k_htc *htc,
{
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
if (htc->ar->state == ATH10K_STATE_WEDGED)
return -ECOMM;
if (eid >= ATH10K_HTC_EP_COUNT) {
ath10k_warn("Invalid endpoint id: %d\n", eid);
return -ENOENT;
}
skb_push(skb, sizeof(struct ath10k_htc_hdr));
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_push(skb, sizeof(struct ath10k_htc_hdr));
spin_unlock_bh(&htc->tx_lock);
queue_work(htc->ar->workqueue, &ep->send_work);
......@@ -265,25 +272,19 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
struct sk_buff *skb,
unsigned int eid)
{
struct ath10k_htc *htc = ar->htc;
struct ath10k_htc *htc = &ar->htc;
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
bool stopping;
ath10k_htc_notify_tx_completion(ep, skb);
/* 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);
stopping = htc->stopping;
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
*/
if (!ep->tx_credit_flow_enabled && !htc->stopped)
queue_work(ar->workqueue, &ep->send_work);
spin_unlock_bh(&htc->tx_lock);
return 0;
}
......@@ -414,7 +415,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
u8 pipe_id)
{
int status = 0;
struct ath10k_htc *htc = ar->htc;
struct ath10k_htc *htc = &ar->htc;
struct ath10k_htc_hdr *hdr;
struct ath10k_htc_ep *ep;
u16 payload_len;
......@@ -751,8 +752,9 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
tx_alloc = ath10k_htc_get_credit_allocation(htc,
conn_req->service_id);
if (!tx_alloc)
ath10k_warn("HTC Service %s does not allocate target credits\n",
htc_service_name(conn_req->service_id));
ath10k_dbg(ATH10K_DBG_HTC,
"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);
if (!skb) {
......@@ -947,7 +949,7 @@ void ath10k_htc_stop(struct ath10k_htc *htc)
struct ath10k_htc_ep *ep;
spin_lock_bh(&htc->tx_lock);
htc->stopping = true;
htc->stopped = true;
spin_unlock_bh(&htc->tx_lock);
for (i = ATH10K_HTC_EP_0; i < ATH10K_HTC_EP_COUNT; i++) {
......@@ -956,26 +958,18 @@ void ath10k_htc_stop(struct ath10k_htc *htc)
}
ath10k_hif_stop(htc->ar);
ath10k_htc_reset_endpoint_states(htc);
}
/* registered target arrival callback from the HIF layer */
struct ath10k_htc *ath10k_htc_create(struct ath10k *ar,
struct ath10k_htc_ops *htc_ops)
int ath10k_htc_init(struct ath10k *ar)
{
struct ath10k_hif_cb htc_callbacks;
struct ath10k_htc_ep *ep = NULL;
struct ath10k_htc *htc = NULL;
/* FIXME: use struct ath10k instead */
htc = kzalloc(sizeof(struct ath10k_htc), GFP_KERNEL);
if (!htc)
return ERR_PTR(-ENOMEM);
struct ath10k_htc *htc = &ar->htc;
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);
/* setup HIF layer callbacks */
......@@ -986,15 +980,10 @@ struct ath10k_htc *ath10k_htc_create(struct ath10k *ar,
/* Get HIF default pipe for HTC message exchange */
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);
init_completion(&htc->ctl_resp);
return htc;
}
void ath10k_htc_destroy(struct ath10k_htc *htc)
{
kfree(htc);
return 0;
}
......@@ -335,7 +335,7 @@ struct ath10k_htc {
struct ath10k *ar;
struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
/* protects endpoint and stopping fields */
/* protects endpoint and stopped fields */
spinlock_t tx_lock;
struct ath10k_htc_ops htc_ops;
......@@ -349,11 +349,10 @@ struct ath10k_htc {
struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
int target_credit_size;
bool stopping;
bool stopped;
};
struct ath10k_htc *ath10k_htc_create(struct ath10k *ar,
struct ath10k_htc_ops *htc_ops);
int ath10k_htc_init(struct ath10k *ar);
int ath10k_htc_wait_target(struct ath10k_htc *htc);
int ath10k_htc_start(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,
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
struct sk_buff *packet);
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);
#endif
......@@ -16,6 +16,7 @@
*/
#include <linux/slab.h>
#include <linux/if_ether.h>
#include "htt.h"
#include "core.h"
......@@ -36,7 +37,7 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
/* connect to control service */
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);
if (status)
......@@ -47,15 +48,11 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
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;
htt = kzalloc(sizeof(*htt), GFP_KERNEL);
if (!htt)
return NULL;
htt->ar = ar;
htt->max_throughput_mbps = 800;
......@@ -65,8 +62,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
* since ath10k_htt_rx_attach involves sending a rx ring configure
* 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;
}
ret = ath10k_htt_tx_attach(htt);
if (ret) {
......@@ -74,8 +74,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
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;
}
/*
* Prefetch enough data to satisfy target
......@@ -89,13 +92,12 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
8 + /* llc snap */
2; /* ip4 dscp or ip6 priority */
return htt;
return 0;
err_rx_attach:
ath10k_htt_tx_detach(htt);
err_htc_attach:
kfree(htt);
return NULL;
return ret;
}
#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
......@@ -148,5 +150,4 @@ void ath10k_htt_detach(struct ath10k_htt *htt)
{
ath10k_htt_rx_detach(htt);
ath10k_htt_tx_detach(htt);
kfree(htt);
}
......@@ -20,7 +20,6 @@
#include <linux/bug.h>
#include "core.h"
#include "htc.h"
#include "rx_desc.h"
......@@ -1317,7 +1316,7 @@ struct htt_rx_desc {
#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)
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);
void ath10k_htt_detach(struct ath10k_htt *htt);
......
......@@ -15,6 +15,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "core.h"
#include "htc.h"
#include "htt.h"
#include "txrx.h"
......@@ -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)
{
struct ath10k_htt *htt = ar->htt;
struct ath10k_htt *htt = &ar->htt;
struct htt_resp *resp = (struct htt_resp *)skb->data;
/* confirm alignment */
......
......@@ -92,7 +92,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
/* At the beginning free queue number should hint us the maximum
* 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,
pipe);
......@@ -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)
{
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) {
dev_kfree_skb_any(skb);
......@@ -194,7 +194,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
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) {
dev_kfree_skb_any(skb);
return ret;
......@@ -281,7 +281,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
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) {
dev_kfree_skb_any(skb);
return ret;
......@@ -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.msdu = msdu;
res = ath10k_htc_send(htt->ar->htc, htt->eid, txdesc);
res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
if (res)
goto err;
......@@ -486,7 +486,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb->htt.txfrag = txfrag;
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)
goto err;
......
......@@ -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_offchan_tx_purge(struct ath10k *ar);
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)
{
......
......@@ -54,6 +54,8 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,
int num);
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_device_reset(struct ath10k *ar);
static int ath10k_pci_reset_target(struct ath10k *ar);
static const struct ce_attr host_ce_config_wlan[] = {
/* host->target HTC control and raw streams */
......@@ -718,6 +720,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
reg_dump_values[i + 1],
reg_dump_values[i + 2],
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,
......@@ -744,8 +748,8 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
ath10k_ce_per_engine_service(ar, pipe);
}
static void ath10k_pci_hif_post_init(struct ath10k *ar,
struct ath10k_hif_cb *callbacks)
static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
struct ath10k_hif_cb *callbacks)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
......@@ -1263,7 +1267,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_process_ce(ar);
ath10k_pci_cleanup_ce(ar);
ath10k_pci_buffer_cleanup(ar);
ath10k_pci_ce_deinit(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)
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 = {
.send_head = ath10k_pci_hif_send_head,
.exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
......@@ -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,
.get_default_pipe = ath10k_pci_hif_get_default_pipe,
.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,
.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)
......@@ -2059,9 +2177,9 @@ static int ath10k_pci_reset_target(struct ath10k *ar)
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;
int i;
u32 val;
......@@ -2118,7 +2236,7 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
case ATH10K_PCI_FEATURE_MSI_X:
ath10k_dbg(ATH10K_DBG_PCI, "device supports MSI-X\n");
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");
break;
}
......@@ -2145,7 +2263,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
switch (pci_dev->device) {
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;
case QCA988X_2_0_DEVICE_ID:
set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
......@@ -2158,8 +2276,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ath10k_pci_dump_features(ar_pci);
ar = ath10k_core_create(ar_pci, ar_pci->dev, ATH10K_BUS_PCI,
&ath10k_pci_hif_ops);
ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
if (!ar) {
ath10k_err("ath10k_core_create failed!\n");
ret = -EINVAL;
......@@ -2167,7 +2284,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
}
/* 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);
ar_pci->ar = ar;
......@@ -2247,54 +2364,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
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);
if (ret) {
ath10k_err("could not register driver core (%d)\n", ret);
goto err_ce;
goto err_intr;
}
return 0;
err_ce:
ath10k_pci_ce_deinit(ar);
err_intr:
ath10k_pci_stop_intr(ar);
err_iomap:
......@@ -2345,128 +2422,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
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);
static struct pci_driver ath10k_pci_driver = {
......@@ -2474,7 +2429,6 @@ static struct pci_driver ath10k_pci_driver = {
.id_table = ath10k_pci_id_table,
.probe = ath10k_pci_probe,
.remove = ath10k_pci_remove,
.driver.pm = ATH10K_PCI_PM_OPS,
};
static int __init ath10k_pci_init(void)
......
......@@ -152,7 +152,7 @@ struct service_to_pipe {
enum ath10k_pci_features {
ATH10K_PCI_FEATURE_MSI_X = 0,
ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND = 1,
ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND = 1,
/* keep last */
ATH10K_PCI_FEATURE_COUNT
......@@ -311,7 +311,7 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
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;
spin_lock_irqsave(&ar_pci->hw_v1_workaround_lock, irq_flags);
......
......@@ -27,6 +27,13 @@ void ath10k_wmi_flush_tx(struct ath10k *ar)
{
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,
atomic_read(&ar->wmi.pending_tx_count) == 0,
5*HZ);
......@@ -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);
status = ath10k_htc_send(ar->htc, ar->wmi.eid, skb);
status = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
if (status) {
dev_kfree_skb_any(skb);
atomic_dec(&ar->wmi.pending_tx_count);
......@@ -501,8 +508,8 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies,
(u8 *)skb_tail_pointer(bcn) - ies);
if (!ie) {
/* highly unlikely for mac80211 */
ath10k_warn("no tim ie found;\n");
if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
ath10k_warn("no tim ie found;\n");
return;
}
......@@ -1114,7 +1121,7 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar)
/* connect to control service */
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) {
ath10k_warn("failed to connect to WMI CONTROL service status: %d\n",
status);
......@@ -1748,6 +1755,9 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
if (arg->key_data)
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);
}
......@@ -2011,6 +2021,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
cmd->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);
}
......@@ -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);
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 {
WMI_PDEV_FTM_INTG_CMDID,
WMI_VDEV_SET_KEEPALIVE_CMDID,
WMI_VDEV_GET_KEEPALIVE_CMDID,
WMI_FORCE_FW_HANG_CMDID,
/* GPIO Configuration */
WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP(WMI_GRP_GPIO),
......@@ -2972,6 +2973,22 @@ struct wmi_sta_keepalive_cmd {
struct wmi_sta_keepalive_arp_resp arp_resp;
} __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_FRAGMT_THRESHOLD_MIN 540
#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);
int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
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_force_fw_hang(struct ath10k *ar,
enum wmi_force_fw_hang_type type, u32 delay_ms);
#endif /* _WMI_H_ */
......@@ -96,6 +96,16 @@ config ATH9K_LEGACY_RATE_CONTROL
has to be passed to mac80211 using the module parameter,
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
tristate "Atheros HTC based wireless cards support"
depends on USB && MAC80211
......
......@@ -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);
}
#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,
struct ath_spec_scan *param)
{
......@@ -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_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);
}
......@@ -317,13 +317,15 @@
#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_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_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_THRESH62 0x000000FF
#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)
return le16_to_cpu(ar9003_modal_header(ah, is2ghz)->switchcomspdt);
}
static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
{
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);
}
......@@ -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)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
int chain;
u32 regval, value, gpio;
......@@ -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);
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);
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)
regval &= (~AR_PHY_ANT_DIV_LNADIV);
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 (ah->shared_chain_lnadiv) {
if (common->bt_ant_diversity) {
regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S);
} else {
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)
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
/*enable fast_div */
/* enable fast_div */
regval = REG_READ(ah, AR_PHY_CCK_DETECT);
regval &= (~AR_FAST_DIV_ENABLE);
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);
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)
AR_PHY_ANT_DIV_ALT_GAINTB |
AR_PHY_ANT_DIV_MAIN_GAINTB));
/* 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);
regval |= (AR_PHY_ANT_DIV_LNA2 <<
regval |= (ATH_ANT_DIV_COMB_LNA2 <<
AR_PHY_ANT_DIV_ALT_LNACONF_S);
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
}
......
......@@ -334,6 +334,8 @@ struct ar9300_eeprom {
s32 ar9003_hw_get_tx_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);
......
......@@ -632,6 +632,22 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
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,
......@@ -814,29 +830,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
if (chan->channel == 2484)
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;
ar9003_hw_override_ini(ah);
ar9003_hw_set_channel_regs(ah, chan);
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
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;
}
......@@ -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);
}
static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
bool enable)
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
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;
u32 regval;
if (!AR_SREV_9565(ah))
if (!AR_SREV_9485(ah) && !AR_SREV_9565(ah))
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);
/*
* Set MAIN/ALT LNA conf.
* Set MAIN/ALT gain_tb.
*/
regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
regval &= (~AR_ANT_DIV_CTRL_ALL);
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);
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 (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);
if (AR_SREV_9485_11(ah)) {
/*
* Enable LNA diversity.
*/
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 |= (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);
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);
/*
* 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,
struct ath9k_channel *chan,
u8 *ini_reloaded)
......@@ -1518,6 +1563,18 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
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
* different modal values.
......@@ -1528,7 +1585,11 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
if (AR_SREV_9565(ah))
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;
*ini_reloaded = true;
......@@ -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_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_trigger = ar9003_hw_spectral_scan_trigger;
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_radar_conf(ah);
memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
......
......@@ -296,11 +296,6 @@
#define AR_PHY_ANT_DIV_MAIN_GAINTB 0x40000000
#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_EXT_CHN_WIN (AR_AGC_BASE + 0x30)
#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,
#define ATH_AGGR_ENCRYPTDELIM 10
/* minimum h/w qdepth to be sustained to maximize aggregation */
#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_MAX 4096
......@@ -174,12 +175,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#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
struct ath_txq {
int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
......@@ -212,8 +207,9 @@ struct ath_frame_info {
int framelen;
enum ath9k_key_type keytype;
u8 keyix;
u8 retries;
u8 rtscts_rate;
u8 retries : 7;
u8 baw_tracked : 1;
};
struct ath_buf_state {
......@@ -241,6 +237,7 @@ struct ath_buf {
struct ath_atx_tid {
struct list_head list;
struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_atx_ac *ac;
unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
......@@ -268,6 +265,7 @@ struct ath_node {
u8 mpdudensity;
bool sleeping;
bool no_ps_filter;
#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
struct dentry *node_stat;
......@@ -367,6 +365,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
/********/
struct ath_vif {
struct ath_node mcast_node;
int av_bslot;
bool primary_sta_vif;
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
......@@ -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_ALT_ANT_RATIO 30
#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_DELTA_HI -4
#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -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 {
u16 count;
u16 total_pkt_count;
......@@ -614,27 +608,35 @@ struct ath_ant_comb {
int rssi_first;
int rssi_second;
int rssi_third;
int ant_ratio;
int ant_ratio2;
bool alt_good;
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 second_quick_scan_conf;
bool first_ratio;
bool second_ratio;
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_update(struct ath_softc *sc);
/********************/
/* Main driver core */
/********************/
#define ATH9K_PCI_CUS198 0x0001
#define ATH9K_PCI_CUS230 0x0002
#define ATH9K_PCI_CUS217 0x0004
#define ATH9K_PCI_WOW 0x0008
#define ATH9K_PCI_CUS198 0x0001
#define ATH9K_PCI_CUS230 0x0002
#define ATH9K_PCI_CUS217 0x0004
#define ATH9K_PCI_WOW 0x0008
#define ATH9K_PCI_BT_ANT_DIV 0x0010
/*
* Default cache line size, in bytes.
......
......@@ -270,25 +270,29 @@ static const struct file_operations fops_ani = {
.llseek = default_llseek,
};
static ssize_t read_file_ant_diversity(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
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_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32];
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);
}
static ssize_t write_file_ant_diversity(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
static ssize_t write_file_bt_ant_diversity(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
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];
ssize_t len;
......@@ -296,26 +300,147 @@ static ssize_t write_file_ant_diversity(struct file *file,
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
if (!AR_SREV_9565(sc->sc_ah))
if (!(pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV))
goto exit;
buf[len] = '\0';
if (kstrtoul(buf, 0, &antenna_diversity))
if (kstrtoul(buf, 0, &bt_ant_diversity))
return -EINVAL;
common->antenna_diversity = !!antenna_diversity;
common->bt_ant_diversity = !!bt_ant_diversity;
ath9k_ps_wakeup(sc);
ath_ant_comb_update(sc);
ath_dbg(common, CONFIG, "Antenna diversity: %d\n",
common->antenna_diversity);
ath9k_hw_set_bt_ant_diversity(sc->sc_ah, common->bt_ant_diversity);
ath_dbg(common, CONFIG, "Enable WLAN/BT RX Antenna diversity: %d\n",
common->bt_ant_diversity);
ath9k_ps_restore(sc);
exit:
return count;
}
static const struct file_operations fops_ant_diversity = {
.read = read_file_ant_diversity,
.write = write_file_ant_diversity,
static const struct file_operations fops_bt_ant_diversity = {
.read = read_file_bt_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,
.owner = THIS_MODULE,
.llseek = default_llseek,
......@@ -607,6 +732,28 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
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,
size_t count, loff_t *ppos)
{
......@@ -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++) {
txq = sc->tx.txq_map[i];
len += snprintf(buf + len, size - len, "(%s): ", qname[i]);
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, "(%s): ", qname[i]);
len += print_queue(sc, txq, buf + len, size - len);
}
len += snprintf(buf + len, size - len, "(CAB): ");
len += print_queue(sc, sc->beacon.cabq, buf + len, size - len);
if (len > size)
len = size;
......@@ -1814,9 +1950,11 @@ int ath9k_init_debug(struct ath_hw *ah)
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
debugfs_create_file("diversity", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_ant_diversity);
debugfs_create_file("antenna_diversity", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_antenna_diversity);
#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,
&fops_btcoex);
#endif
......
......@@ -28,9 +28,13 @@ struct fft_sample_tlv;
#ifdef CONFIG_ATH9K_DEBUGFS
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
#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
#define TX_STAT_INC(q, c) 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
enum ath_reset_type {
......@@ -243,11 +247,22 @@ struct ath_rx_stats {
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_interrupt_stats istats;
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
struct ath_rx_stats rxstats;
struct ath_dfs_stats dfs_stats;
struct ath_antenna_stats ant_stats[2];
u32 reset[__RESET_TYPE_MAX];
};
......@@ -281,10 +296,11 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
void ath_debug_send_fft_sample(struct ath_softc *sc,
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
#define RX_STAT_INC(c) /* NOP */
......@@ -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 ath_debug_stat_interrupt(struct ath_softc *sc,
enum ath9k_int status)
{
}
static inline void ath_debug_stat_tx(struct ath_softc *sc,
struct ath_buf *bf,
struct ath_tx_status *ts,
......@@ -310,10 +324,15 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc,
unsigned int flags)
{
}
static inline void ath_debug_stat_rx(struct ath_softc *sc,
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 */
......
......@@ -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,
struct ath9k_channel *chan)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct modal_eep_4k_header *pModal;
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
struct base_eep_header_4k *pBase = &eep->baseEepHeader;
......@@ -858,6 +859,24 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
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) {
......
......@@ -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);
}
static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
bool enable)
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
{
if (ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv)
ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv(ah, enable);
if (ath9k_hw_ops(ah)->set_bt_ant_diversity)
ath9k_hw_ops(ah)->set_bt_ant_diversity(ah, enable);
}
#endif
/* Private hardware call ops */
/* PHY ops */
......
......@@ -1496,16 +1496,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
struct ath9k_channel *chan)
{
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;
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)) !=
(ah->curchan->channelFlags & (CHANNEL_2GHZ |
CHANNEL_5GHZ));
mode_diff = (chan->chanmode != ah->curchan->chanmode);
if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
u32 cur = ah->curchan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
u32 new = chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
band_switch = (cur != new);
mode_diff = (chan->chanmode != ah->curchan->chanmode);
}
for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
if (ath9k_hw_numtxpending(ah, qnum)) {
......@@ -1520,11 +1522,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
return false;
}
if (edma && (band_switch || mode_diff)) {
if (band_switch || mode_diff) {
ath9k_hw_mark_phy_inactive(ah);
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)) {
ath_err(common, "Failed to do fast channel change\n");
......@@ -1541,22 +1544,21 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
}
ath9k_hw_set_clockrate(ah);
ath9k_hw_apply_txpower(ah, chan, false);
ath9k_hw_rfbus_done(ah);
if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
ath9k_hw_set_delta_slope(ah, chan);
ath9k_hw_spur_mitigate_freq(ah, chan);
if (edma && (band_switch || mode_diff)) {
ah->ah_flags |= AH_FASTCC;
if (band_switch || ini_reloaded)
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)
ath9k_hw_init_cal(ah, chan);
if (band_switch || ini_reloaded) {
ah->ah_flags |= AH_FASTCC;
ath9k_hw_init_cal(ah, chan);
ah->ah_flags &= ~AH_FASTCC;
}
......@@ -1778,16 +1780,11 @@ static void ath9k_hw_init_desc(struct ath_hw *ah)
/*
* Fast channel change:
* (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)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
int ret;
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)
(CHANNEL_HALF | CHANNEL_QUARTER))
goto fail;
if ((chan->channelFlags & CHANNEL_ALL) !=
(ah->curchan->channelFlags & CHANNEL_ALL))
goto fail;
/*
* If cross-band fcc is not supoprted, bail out if
* 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))
goto fail;
......@@ -2047,7 +2056,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
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);
return 0;
......@@ -2504,7 +2513,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
else
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);
if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
ah->rfkill_gpio =
......@@ -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))
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) {
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;
ath_info(common, "Enable LNA combining\n");
}
}
}
if (AR_SREV_9300_20_OR_LATER(ah)) {
if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE))
pCap->hw_caps |= ATH9K_HW_CAP_APM;
}
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);
/*
* 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)
if ((ant_div_ctl1 >> 0x6) == 0x3) {
pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
ath_info(common, "Enable LNA combining\n");
}
}
if (ath9k_hw_dfs_tested(ah))
......@@ -2610,6 +2613,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
ah->eep_ops->get_eeprom(ah, EEP_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;
}
......
......@@ -247,6 +247,8 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_DFS = BIT(16),
ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17),
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 {
/* Platform specific config */
u32 xlna_gpio;
u32 ant_ctrl_comm2g_switch_enable;
bool xatten_margin_cfg;
};
......@@ -716,11 +719,14 @@ struct ath_hw_ops {
struct ath_hw_antcomb_conf *antconf);
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
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,
struct ath_spec_scan *param);
void (*spectral_scan_trigger)(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 {
......@@ -765,7 +771,6 @@ struct ath_hw {
bool aspm_enabled;
bool is_monitoring;
bool need_an_top2_fixup;
bool shared_chain_lnadiv;
u16 tx_trig_level;
u32 nf_regs[6];
......
......@@ -53,9 +53,9 @@ static int ath9k_btcoex_enable;
module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
static int ath9k_enable_diversity;
module_param_named(enable_diversity, ath9k_enable_diversity, int, 0444);
MODULE_PARM_DESC(enable_diversity, "Enable Antenna diversity for AR9565");
static int ath9k_bt_ant_diversity;
module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444);
MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity");
bool is_ath9k_unloaded;
/* 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)
static void ath9k_init_platform(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
if (common->bus_ops->ath_bus_type != ATH_PCI)
......@@ -525,12 +526,21 @@ static void ath9k_init_platform(struct ath_softc *sc)
ATH9K_PCI_CUS230)) {
ah->config.xlna_gpio = 9;
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",
(sc->driver_data & ATH9K_PCI_CUS198) ?
"CUS198" : "CUS230");
} else if (sc->driver_data & ATH9K_PCI_CUS217) {
}
if (sc->driver_data & ATH9K_PCI_CUS217)
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,
{
struct ath9k_platform_data *pdata = sc->dev->platform_data;
struct ath_hw *ah = NULL;
struct ath9k_hw_capabilities *pCap;
struct ath_common *common;
int ret = 0, i;
int csz = 0;
......@@ -600,6 +611,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ah->reg_ops.rmw = ath9k_reg_rmw;
atomic_set(&ah->intr_ref_cnt, -1);
sc->sc_ah = ah;
pCap = &ah->caps;
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,
ath9k_init_platform(sc);
/*
* Enable Antenna diversity only when BTCOEX is disabled
* and the user manually requests the feature.
* Enable WLAN/BT RX Antenna diversity only when:
*
* - 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)
common->antenna_diversity = 1;
if (!common->btcoex_enabled && ath9k_bt_ant_diversity &&
(pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV))
common->bt_ant_diversity = 1;
spin_lock_init(&common->cc_lock);
......
......@@ -238,9 +238,6 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
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);
return true;
......@@ -966,6 +963,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_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);
......@@ -979,6 +978,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
if (ath9k_uses_beacons(vif->type))
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);
return 0;
}
......@@ -1016,6 +1021,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
{
struct ath_softc *sc = hw->priv;
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");
......@@ -1030,6 +1036,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
ath9k_calculate_summary_state(hw, NULL);
ath9k_ps_restore(sc);
ath_tx_node_cleanup(sc, &avp->mcast_node);
mutex_unlock(&sc->mutex);
}
......@@ -1374,9 +1382,6 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
struct ath_node *an = (struct ath_node *) sta->drv_priv;
if (!sta->ht_cap.ht_supported)
return;
switch (cmd) {
case STA_NOTIFY_SLEEP:
an->sleeping = true;
......@@ -2094,7 +2099,7 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc,
{
struct ath_hw *ah = sc->sc_ah;
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;
s8 i = 0;
......
......@@ -29,6 +29,14 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ 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, 0x002C) }, /* PCI-E 802.11n bonded out */
{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
......@@ -40,29 +48,101 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
0x0032,
PCI_VENDOR_ID_AZWAVE,
0x2086),
.driver_data = ATH9K_PCI_CUS198 },
.driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_AZWAVE,
0x1237),
.driver_data = ATH9K_PCI_CUS198 },
.driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_AZWAVE,
0x2126),
.driver_data = ATH9K_PCI_CUS198 },
.driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
/* PCI-E CUS230 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_AZWAVE,
0x2152),
.driver_data = ATH9K_PCI_CUS230 },
.driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_FOXCONN,
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, 0x0033) }, /* PCI-E AR9580 */
......
......@@ -48,4 +48,11 @@
#define AR_PHY_PLL_CONTROL 0x16180
#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
......@@ -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,
struct cfg80211_chan_def *chandef,
struct ieee80211_sta *sta, void *priv_sta)
{
struct ath_softc *sc = priv;
......@@ -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,
struct cfg80211_chan_def *chandef,
struct ieee80211_sta *sta, void *priv_sta,
u32 changed)
{
......
......@@ -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 ieee80211_rx_status *rxs;
struct ath_hw *ah = sc->sc_ah;
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_hdr *hdr;
......@@ -1328,11 +1329,30 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
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.
*/
if (sc->rx.defant != rs.rs_antenna) {
......@@ -1342,22 +1362,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
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);
ieee80211_rx(hw, skb);
......
......@@ -11,9 +11,6 @@ wil6210-y += txrx.o
wil6210-y += debug.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
subdir-ccflags-y += -Werror
endif
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
......
......@@ -51,7 +51,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
if ((i % 64) == 0 && (i != 0))
seq_printf(s, "\n");
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");
}
......@@ -406,7 +406,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
volatile struct vring_tx_desc *d =
&(vring->va[dbg_txdesc_index].tx);
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, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
......
......@@ -127,6 +127,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
ndev->netdev_ops = &wil_netdev_ops;
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));
wdev->netdev = ndev;
......
......@@ -37,36 +37,40 @@ static inline void trace_ ## name(proto) {}
#endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */
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(
__field(u8, mid)
__field(u16, id)
__field(u32, timestamp)
__field(u16, buf_len)
__dynamic_array(u8, buf, buf_len)
),
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;
memcpy(__get_dynamic_array(buf), buf, buf_len);
),
TP_printk(
"id 0x%04x len %d",
__entry->id, __entry->buf_len
"MID %d id 0x%04x len %d timestamp %d",
__entry->mid, __entry->id, __entry->buf_len, __entry->timestamp
)
);
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd,
TP_PROTO(u16 id, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len)
TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
TP_ARGS(wmi, buf, buf_len)
);
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event,
TP_PROTO(u16 id, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len)
TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
TP_ARGS(wmi, buf, buf_len)
);
#define WIL6210_MSG_MAX (200)
......
......@@ -4164,9 +4164,7 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.stop_p2p_device = brcmf_p2p_stop_device,
.crit_proto_start = brcmf_cfg80211_crit_proto_start,
.crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd = brcmf_cfg80211_testmode
#endif
CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
};
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)
mcl = le16_to_cpu(txh->MacTxControlLow);
if (txs->phyerr)
brcms_err(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n",
txs->phyerr, txh->MainRates);
brcms_dbg_tx(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n",
txs->phyerr, txh->MainRates);
if (txs->frameid != le16_to_cpu(txh->TxFrameID)) {
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.
先完成此消息的编辑!
想要评论请 注册