summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS11
-rw-r--r--arch/mips/bcm47xx/setup.c4
-rw-r--r--drivers/bcma/Makefile1
-rw-r--r--drivers/bcma/bcma_private.h4
-rw-r--r--drivers/bcma/driver_chipcommon_b.c61
-rw-r--r--drivers/bcma/driver_mips.c62
-rw-r--r--drivers/bcma/host_pci.c4
-rw-r--r--drivers/bcma/host_soc.c18
-rw-r--r--drivers/bcma/main.c100
-rw-r--r--drivers/bcma/scan.c28
-rw-r--r--drivers/bluetooth/ath3k.c2
-rw-r--r--drivers/bluetooth/bluecard_cs.c35
-rw-r--r--drivers/bluetooth/bt3c_cs.c27
-rw-r--r--drivers/bluetooth/btuart_cs.c27
-rw-r--r--drivers/bluetooth/btusb.c10
-rw-r--r--drivers/bluetooth/dtl1_cs.c36
-rw-r--r--drivers/bluetooth/hci_h5.c2
-rw-r--r--drivers/net/wireless/at76c50x-usb.c3
-rw-r--r--drivers/net/wireless/ath/ath.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig1
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath10k/bmi.c52
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c185
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h28
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c246
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h66
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c339
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h34
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c115
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.h7
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c171
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c46
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h5
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c717
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.h6
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c1529
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h104
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.c561
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.h90
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c17
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c1089
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h699
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c96
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c1
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c1
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c1
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c21
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c48
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig9
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h154
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c73
-rw-r--r--drivers/net/wireless/ath/ath9k/channel.c1345
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c90
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c525
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c44
-rw-r--r--drivers/net/wireless/ath/ath9k/spectral.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/spectral.h71
-rw-r--r--drivers/net/wireless/ath/ath9k/tx99.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/wow.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c7
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c11
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c2
-rw-r--r--drivers/net/wireless/ath/spectral_common.h113
-rw-r--r--drivers/net/wireless/ath/wil6210/Kconfig9
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile3
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c132
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c389
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.c45
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.h149
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c495
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c33
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c207
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c25
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c46
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c29
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c69
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h11
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h60
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.c49
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.h34
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform_msm.c257
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform_msm.h24
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c89
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h22
-rw-r--r--drivers/net/wireless/atmel_cs.c22
-rw-r--r--drivers/net/wireless/b43/Makefile1
-rw-r--r--drivers/net/wireless/b43/b43.h18
-rw-r--r--drivers/net/wireless/b43/bus.c10
-rw-r--r--drivers/net/wireless/b43/bus.h15
-rw-r--r--drivers/net/wireless/b43/main.c34
-rw-r--r--drivers/net/wireless/b43/phy_a.c4
-rw-r--r--drivers/net/wireless/b43/phy_common.c25
-rw-r--r--drivers/net/wireless/b43/phy_g.c8
-rw-r--r--drivers/net/wireless/b43/phy_ht.c185
-rw-r--r--drivers/net/wireless/b43/phy_ht.h4
-rw-r--r--drivers/net/wireless/b43/phy_lcn.c20
-rw-r--r--drivers/net/wireless/b43/phy_lp.c20
-rw-r--r--drivers/net/wireless/b43/phy_n.c128
-rw-r--r--drivers/net/wireless/b43/phy_n.h4
-rw-r--r--drivers/net/wireless/b43/ppr.c199
-rw-r--r--drivers/net/wireless/b43/ppr.h45
-rw-r--r--drivers/net/wireless/b43/radio_2059.c27
-rw-r--r--drivers/net/wireless/b43/radio_2059.h14
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c128
-rw-r--r--drivers/net/wireless/b43/tables_nphy.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c18
-rw-r--r--drivers/net/wireless/cw1200/cw1200_spi.c4
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c6
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c2
-rw-r--r--drivers/net/wireless/libertas/cfg.c2
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c3
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c29
-rw-r--r--drivers/net/wireless/mwifiex/fw.h9
-rw-r--r--drivers/net/wireless/mwifiex/init.c4
-rw-r--r--drivers/net/wireless/mwifiex/main.h2
-rw-r--r--drivers/net/wireless/mwifiex/scan.c3
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c2
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c2
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c4
-rw-r--r--drivers/net/wireless/mwifiex/util.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c10
-rw-r--r--drivers/net/wireless/orinoco/scan.c14
-rw-r--r--drivers/net/wireless/ray_cs.h5
-rw-r--r--drivers/net/wireless/rayctl.h5
-rw-r--r--drivers/net/wireless/rndis_wlan.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c6
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h6
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c3888
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h185
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c3211
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h184
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c447
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h31
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c3010
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h188
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c3914
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h205
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c51
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h120
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c27
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h6
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/phy.c8
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c4
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h15
-rw-r--r--drivers/net/wireless/ti/wl1251/spi.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/spi.c20
-rw-r--r--drivers/ssb/b43_pci_bridge.c1
-rw-r--r--drivers/staging/rtl8723au/core/rtw_mlme_ext.c2
-rw-r--r--drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c5
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c1
-rw-r--r--drivers/usb/host/bcma-hcd.c2
-rw-r--r--include/linux/bcma/bcma.h4
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h8
-rw-r--r--include/linux/bcma/bcma_regs.h5
-rw-r--r--include/linux/bcma/bcma_soc.h1
-rw-r--r--include/linux/ieee80211.h65
-rw-r--r--include/net/bluetooth/hci_core.h24
-rw-r--r--include/net/bluetooth/l2cap.h35
-rw-r--r--include/net/cfg80211.h25
-rw-r--r--include/net/mac80211.h14
-rw-r--r--include/net/netns/ieee802154_6lowpan.h1
-rw-r--r--include/net/regulatory.h2
-rw-r--r--include/uapi/linux/nl80211.h16
-rw-r--r--net/bluetooth/6lowpan.c90
-rw-r--r--net/bluetooth/amp.c13
-rw-r--r--net/bluetooth/hci_conn.c57
-rw-r--r--net/bluetooth/hci_core.c104
-rw-r--r--net/bluetooth/hci_event.c48
-rw-r--r--net/bluetooth/hidp/core.c10
-rw-r--r--net/bluetooth/l2cap_core.c342
-rw-r--r--net/bluetooth/l2cap_sock.c23
-rw-r--r--net/bluetooth/mgmt.c161
-rw-r--r--net/bluetooth/smp.c873
-rw-r--r--net/bluetooth/smp.h12
-rw-r--r--net/ieee802154/6lowpan_rtnl.c12
-rw-r--r--net/ieee802154/reassembly.c15
-rw-r--r--net/mac80211/cfg.c13
-rw-r--r--net/mac80211/chan.c195
-rw-r--r--net/mac80211/debugfs_sta.c5
-rw-r--r--net/mac80211/ibss.c2
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/key.c12
-rw-r--r--net/mac80211/mesh_pathtbl.c4
-rw-r--r--net/mac80211/mesh_plink.c21
-rw-r--r--net/mac80211/mlme.c36
-rw-r--r--net/mac80211/rx.c2
-rw-r--r--net/mac80211/scan.c2
-rw-r--r--net/mac80211/sta_info.c11
-rw-r--r--net/mac80211/sta_info.h2
-rw-r--r--net/mac80211/tdls.c3
-rw-r--r--net/mac80211/tx.c11
-rw-r--r--net/mac80211/wme.c4
-rw-r--r--net/mac802154/rx.c5
-rw-r--r--net/mac802154/tx.c15
-rw-r--r--net/mac802154/wpan.c16
-rw-r--r--net/rfkill/rfkill-gpio.c1
-rw-r--r--net/wireless/core.c13
-rw-r--r--net/wireless/mlme.c4
-rw-r--r--net/wireless/nl80211.c16
-rw-r--r--net/wireless/scan.c21
212 files changed, 25286 insertions, 5065 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index f01f54f2..0b7007a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -152,8 +152,8 @@ F: drivers/scsi/53c700*
6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
M: Alexander Aring <alex.aring@gmail.com>
-L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
L: linux-bluetooth@vger.kernel.org
+L: linux-wpan@vger.kernel.org
S: Maintained
F: net/6lowpan/
F: include/net/6lowpan.h
@@ -4580,13 +4580,14 @@ F: drivers/idle/i7300_idle.c
IEEE 802.15.4 SUBSYSTEM
M: Alexander Aring <alex.aring@gmail.com>
-L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
-W: http://apps.sourceforge.net/trac/linux-zigbee
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
+L: linux-wpan@vger.kernel.org
+W: https://github.com/linux-wpan
+T: git git://github.com/linux-wpan/linux-wpan-next.git
S: Maintained
F: net/ieee802154/
F: net/mac802154/
F: drivers/net/ieee802154/
+F: Documentation/networking/ieee802154.txt
IGUANAWORKS USB IR TRANSCEIVER
M: Sean Young <sean@mess.org>
@@ -6356,7 +6357,7 @@ M: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
M: Samuel Ortiz <sameo@linux.intel.com>
L: linux-wireless@vger.kernel.org
-L: linux-nfc@lists.01.org (moderated for non-subscribers)
+L: linux-nfc@lists.01.org (subscribers-only)
S: Supported
F: net/nfc/
F: include/net/nfc/
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 2b63e7e..fff6ed4 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -202,6 +202,10 @@ static void __init bcm47xx_register_bcma(void)
err = bcma_host_soc_register(&bcm47xx_bus.bcma);
if (err)
+ panic("Failed to register BCMA bus (err %d)", err);
+
+ err = bcma_host_soc_init(&bcm47xx_bus.bcma);
+ if (err)
panic("Failed to initialize BCMA bus (err %d)", err);
bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL);
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 91290f7..838b4b9 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,5 +1,6 @@
bcma-y += main.o scan.o core.o sprom.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
+bcma-y += driver_chipcommon_b.o
bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
bcma-y += driver_pci.o
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 09b632a..b40be43 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -50,6 +50,10 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
extern struct platform_device bcma_pflash_dev;
#endif /* CONFIG_BCMA_DRIVER_MIPS */
+/* driver_chipcommon_b.c */
+int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
+void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb);
+
/* driver_chipcommon_pmu.c */
u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
diff --git a/drivers/bcma/driver_chipcommon_b.c b/drivers/bcma/driver_chipcommon_b.c
new file mode 100644
index 0000000..c20b5f4
--- /dev/null
+++ b/drivers/bcma/driver_chipcommon_b.c
@@ -0,0 +1,61 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon B Unit driver
+ *
+ * Copyright 2014, Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/export.h>
+#include <linux/bcma/bcma.h>
+
+static bool bcma_wait_reg(struct bcma_bus *bus, void __iomem *addr, u32 mask,
+ u32 value, int timeout)
+{
+ unsigned long deadline = jiffies + timeout;
+ u32 val;
+
+ do {
+ val = readl(addr);
+ if ((val & mask) == value)
+ return true;
+ cpu_relax();
+ udelay(10);
+ } while (!time_after_eq(jiffies, deadline));
+
+ bcma_err(bus, "Timeout waiting for register %p\n", addr);
+
+ return false;
+}
+
+void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
+{
+ struct bcma_bus *bus = ccb->core->bus;
+
+ writel(offset, ccb->mii + 0x00);
+ bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
+ writel(value, ccb->mii + 0x04);
+ bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);
+
+int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb)
+{
+ if (ccb->setup_done)
+ return 0;
+
+ ccb->setup_done = 1;
+ ccb->mii = ioremap_nocache(ccb->core->addr_s[1], BCMA_CORE_SIZE);
+ if (!ccb->mii)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb)
+{
+ if (ccb->mii)
+ iounmap(ccb->mii);
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 11115bbe..004d6aa 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -21,6 +21,14 @@
#include <linux/serial_reg.h>
#include <linux/time.h>
+enum bcma_boot_dev {
+ BCMA_BOOT_DEV_UNK = 0,
+ BCMA_BOOT_DEV_ROM,
+ BCMA_BOOT_DEV_PARALLEL,
+ BCMA_BOOT_DEV_SERIAL,
+ BCMA_BOOT_DEV_NAND,
+};
+
static const char * const part_probes[] = { "bcm47xxpart", NULL };
static struct physmap_flash_data bcma_pflash_data = {
@@ -229,11 +237,51 @@ u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
}
EXPORT_SYMBOL(bcma_cpu_clock);
+static enum bcma_boot_dev bcma_boot_dev(struct bcma_bus *bus)
+{
+ struct bcma_drv_cc *cc = &bus->drv_cc;
+ u8 cc_rev = cc->core->id.rev;
+
+ if (cc_rev == 42) {
+ struct bcma_device *core;
+
+ core = bcma_find_core(bus, BCMA_CORE_NS_ROM);
+ if (core) {
+ switch (bcma_aread32(core, BCMA_IOST) &
+ BCMA_NS_ROM_IOST_BOOT_DEV_MASK) {
+ case BCMA_NS_ROM_IOST_BOOT_DEV_NOR:
+ return BCMA_BOOT_DEV_SERIAL;
+ case BCMA_NS_ROM_IOST_BOOT_DEV_NAND:
+ return BCMA_BOOT_DEV_NAND;
+ case BCMA_NS_ROM_IOST_BOOT_DEV_ROM:
+ default:
+ return BCMA_BOOT_DEV_ROM;
+ }
+ }
+ } else {
+ if (cc_rev == 38) {
+ if (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT)
+ return BCMA_BOOT_DEV_NAND;
+ else if (cc->status & BIT(5))
+ return BCMA_BOOT_DEV_ROM;
+ }
+
+ if ((cc->capabilities & BCMA_CC_CAP_FLASHT) ==
+ BCMA_CC_FLASHT_PARA)
+ return BCMA_BOOT_DEV_PARALLEL;
+ else
+ return BCMA_BOOT_DEV_SERIAL;
+ }
+
+ return BCMA_BOOT_DEV_SERIAL;
+}
+
static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus = mcore->core->bus;
struct bcma_drv_cc *cc = &bus->drv_cc;
struct bcma_pflash *pflash = &cc->pflash;
+ enum bcma_boot_dev boot_dev;
switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
@@ -269,6 +317,20 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
bcma_nflash_init(cc);
}
}
+
+ /* Determine flash type this SoC boots from */
+ boot_dev = bcma_boot_dev(bus);
+ switch (boot_dev) {
+ case BCMA_BOOT_DEV_PARALLEL:
+ case BCMA_BOOT_DEV_SERIAL:
+ /* TODO: Init NVRAM using BCMA_SOC_FLASH2 window */
+ break;
+ case BCMA_BOOT_DEV_NAND:
+ /* TODO: Init NVRAM using BCMA_SOC_FLASH1 window */
+ break;
+ default:
+ break;
+ }
}
void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
index 294a7dd..1e5ac0a 100644
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -208,6 +208,9 @@ static int bcma_host_pci_probe(struct pci_dev *dev,
bus->boardinfo.vendor = bus->host_pci->subsystem_vendor;
bus->boardinfo.type = bus->host_pci->subsystem_device;
+ /* Initialize struct, detect chip */
+ bcma_init_bus(bus);
+
/* Register */
err = bcma_bus_register(bus);
if (err)
@@ -282,6 +285,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xA8DB */
{ 0, },
};
MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 3475e60..718e054 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -134,12 +134,16 @@ static void bcma_host_soc_block_write(struct bcma_device *core,
static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
{
+ if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n"))
+ return ~0;
return readl(core->io_wrap + offset);
}
static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
u32 value)
{
+ if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n"))
+ return;
writel(value, core->io_wrap + offset);
}
@@ -161,7 +165,6 @@ static const struct bcma_host_ops bcma_host_soc_ops = {
int __init bcma_host_soc_register(struct bcma_soc *soc)
{
struct bcma_bus *bus = &soc->bus;
- int err;
/* iomap only first core. We have to read some register on this core
* to scan the bus.
@@ -174,7 +177,18 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
bus->hosttype = BCMA_HOSTTYPE_SOC;
bus->ops = &bcma_host_soc_ops;
- /* Register */
+ /* Initialize struct, detect chip */
+ bcma_init_bus(bus);
+
+ return 0;
+}
+
+int __init bcma_host_soc_init(struct bcma_soc *soc)
+{
+ struct bcma_bus *bus = &soc->bus;
+ int err;
+
+ /* Scan bus and initialize it */
err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
if (err)
iounmap(bus->mmio);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 0ff8d58..c421403 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -120,16 +120,60 @@ static void bcma_release_core_dev(struct device *dev)
kfree(core);
}
-static int bcma_register_cores(struct bcma_bus *bus)
+static bool bcma_is_core_needed_early(u16 core_id)
+{
+ switch (core_id) {
+ case BCMA_CORE_NS_NAND:
+ case BCMA_CORE_NS_QSPI:
+ return true;
+ }
+
+ return false;
+}
+
+static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
+{
+ int err;
+
+ core->dev.release = bcma_release_core_dev;
+ core->dev.bus = &bcma_bus_type;
+ dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
+
+ switch (bus->hosttype) {
+ case BCMA_HOSTTYPE_PCI:
+ core->dev.parent = &bus->host_pci->dev;
+ core->dma_dev = &bus->host_pci->dev;
+ core->irq = bus->host_pci->irq;
+ break;
+ case BCMA_HOSTTYPE_SOC:
+ core->dev.dma_mask = &core->dev.coherent_dma_mask;
+ core->dma_dev = &core->dev;
+ break;
+ case BCMA_HOSTTYPE_SDIO:
+ break;
+ }
+
+ err = device_register(&core->dev);
+ if (err) {
+ bcma_err(bus, "Could not register dev for core 0x%03X\n",
+ core->id.id);
+ put_device(&core->dev);
+ return;
+ }
+ core->dev_registered = true;
+}
+
+static int bcma_register_devices(struct bcma_bus *bus)
{
struct bcma_device *core;
- int err, dev_id = 0;
+ int err;
list_for_each_entry(core, &bus->cores, list) {
/* We support that cores ourself */
switch (core->id.id) {
case BCMA_CORE_4706_CHIPCOMMON:
case BCMA_CORE_CHIPCOMMON:
+ case BCMA_CORE_NS_CHIPCOMMON_B:
case BCMA_CORE_PCI:
case BCMA_CORE_PCIE:
case BCMA_CORE_PCIE2:
@@ -138,39 +182,16 @@ static int bcma_register_cores(struct bcma_bus *bus)
continue;
}
+ /* Early cores were already registered */
+ if (bcma_is_core_needed_early(core->id.id))
+ continue;
+
/* Only first GMAC core on BCM4706 is connected and working */
if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
core->core_unit > 0)
continue;
- core->dev.release = bcma_release_core_dev;
- core->dev.bus = &bcma_bus_type;
- dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
-
- switch (bus->hosttype) {
- case BCMA_HOSTTYPE_PCI:
- core->dev.parent = &bus->host_pci->dev;
- core->dma_dev = &bus->host_pci->dev;
- core->irq = bus->host_pci->irq;
- break;
- case BCMA_HOSTTYPE_SOC:
- core->dev.dma_mask = &core->dev.coherent_dma_mask;
- core->dma_dev = &core->dev;
- break;
- case BCMA_HOSTTYPE_SDIO:
- break;
- }
-
- err = device_register(&core->dev);
- if (err) {
- bcma_err(bus,
- "Could not register dev for core 0x%03X\n",
- core->id.id);
- put_device(&core->dev);
- continue;
- }
- core->dev_registered = true;
- dev_id++;
+ bcma_register_core(bus, core);
}
#ifdef CONFIG_BCMA_DRIVER_MIPS
@@ -247,6 +268,12 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_early_init(&bus->drv_cc);
}
+ /* Cores providing flash access go before SPROM init */
+ list_for_each_entry(core, &bus->cores, list) {
+ if (bcma_is_core_needed_early(core->id.id))
+ bcma_register_core(bus, core);
+ }
+
/* Try to get SPROM */
err = bcma_sprom_get(bus);
if (err == -ENOENT) {
@@ -261,6 +288,13 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_init(&bus->drv_cc);
}
+ /* Init CC core */
+ core = bcma_find_core(bus, BCMA_CORE_NS_CHIPCOMMON_B);
+ if (core) {
+ bus->drv_cc_b.core = core;
+ bcma_core_chipcommon_b_init(&bus->drv_cc_b);
+ }
+
/* Init MIPS core */
core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
if (core) {
@@ -297,7 +331,7 @@ int bcma_bus_register(struct bcma_bus *bus)
}
/* Register found cores */
- bcma_register_cores(bus);
+ bcma_register_devices(bus);
bcma_info(bus, "Bus registered\n");
@@ -315,6 +349,8 @@ void bcma_bus_unregister(struct bcma_bus *bus)
else if (err)
bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
+ bcma_core_chipcommon_b_free(&bus->drv_cc_b);
+
cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
@@ -334,8 +370,6 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
struct bcma_device *core;
struct bcma_device_id match;
- bcma_init_bus(bus);
-
match.manuf = BCMA_MANUF_BCM;
match.id = bcma_cc_core_id(bus);
match.class = BCMA_CL_SIM;
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index b4764c6..b3a403c 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -276,7 +276,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
struct bcma_device *core)
{
u32 tmp;
- u8 i, j;
+ u8 i, j, k;
s32 cia, cib;
u8 ports[2], wrappers[2];
@@ -314,6 +314,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
/* Some specific cores don't need wrappers */
switch (core->id.id) {
case BCMA_CORE_4706_MAC_GBIT_COMMON:
+ case BCMA_CORE_NS_CHIPCOMMON_B:
/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
break;
default:
@@ -367,6 +368,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
core->addr = tmp;
/* get & parse slave ports */
+ k = 0;
for (i = 0; i < ports[1]; i++) {
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr,
@@ -376,9 +378,9 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
/* pr_debug("erom: slave port %d "
* "has %d descriptors\n", i, j); */
break;
- } else {
- if (i == 0 && j == 0)
- core->addr1 = tmp;
+ } else if (k < ARRAY_SIZE(core->addr_s)) {
+ core->addr_s[k] = tmp;
+ k++;
}
}
}
@@ -421,10 +423,13 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
if (!core->io_addr)
return -ENOMEM;
- core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
- if (!core->io_wrap) {
- iounmap(core->io_addr);
- return -ENOMEM;
+ if (core->wrap) {
+ core->io_wrap = ioremap_nocache(core->wrap,
+ BCMA_CORE_SIZE);
+ if (!core->io_wrap) {
+ iounmap(core->io_addr);
+ return -ENOMEM;
+ }
}
}
return 0;
@@ -435,9 +440,6 @@ void bcma_init_bus(struct bcma_bus *bus)
s32 tmp;
struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
- if (bus->init_done)
- return;
-
INIT_LIST_HEAD(&bus->cores);
bus->nr_cores = 0;
@@ -449,8 +451,6 @@ void bcma_init_bus(struct bcma_bus *bus)
chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
bcma_info(bus, "Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
chipinfo->id, chipinfo->rev, chipinfo->pkg);
-
- bus->init_done = true;
}
int bcma_bus_scan(struct bcma_bus *bus)
@@ -460,8 +460,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
int err, core_num = 0;
- bcma_init_bus(bus);
-
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index a0d7355..d85ced2 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -88,6 +88,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x04CA, 0x300b) },
{ USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0930, 0x0220) },
+ { USB_DEVICE(0x0930, 0x0227) },
{ USB_DEVICE(0x0b05, 0x17d0) },
{ USB_DEVICE(0x0CF3, 0x0036) },
{ USB_DEVICE(0x0CF3, 0x3004) },
@@ -138,6 +139,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index dfa5043..35e63aa 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
/* ======================== Local structures ======================== */
-typedef struct bluecard_info_t {
+struct bluecard_info {
struct pcmcia_device *p_dev;
struct hci_dev *hdev;
@@ -78,7 +78,7 @@ typedef struct bluecard_info_t {
unsigned char ctrl_reg;
unsigned long hw_state; /* Status of the hardware and LED control */
-} bluecard_info_t;
+};
static int bluecard_config(struct pcmcia_device *link);
@@ -157,7 +157,7 @@ static void bluecard_detach(struct pcmcia_device *p_dev);
static void bluecard_activity_led_timeout(u_long arg)
{
- bluecard_info_t *info = (bluecard_info_t *)arg;
+ struct bluecard_info *info = (struct bluecard_info *)arg;
unsigned int iobase = info->p_dev->resource[0]->start;
if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
@@ -173,7 +173,7 @@ static void bluecard_activity_led_timeout(u_long arg)
}
-static void bluecard_enable_activity_led(bluecard_info_t *info)
+static void bluecard_enable_activity_led(struct bluecard_info *info)
{
unsigned int iobase = info->p_dev->resource[0]->start;
@@ -215,7 +215,7 @@ static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, i
}
-static void bluecard_write_wakeup(bluecard_info_t *info)
+static void bluecard_write_wakeup(struct bluecard_info *info)
{
if (!info) {
BT_ERR("Unknown device");
@@ -368,7 +368,8 @@ static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, in
}
-static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
+static void bluecard_receive(struct bluecard_info *info,
+ unsigned int offset)
{
unsigned int iobase;
unsigned char buf[31];
@@ -497,7 +498,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
{
- bluecard_info_t *info = dev_inst;
+ struct bluecard_info *info = dev_inst;
unsigned int iobase;
unsigned char reg;
@@ -562,7 +563,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
{
- bluecard_info_t *info = hci_get_drvdata(hdev);
+ struct bluecard_info *info = hci_get_drvdata(hdev);
struct sk_buff *skb;
/* Ericsson baud rate command */
@@ -611,7 +612,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
static int bluecard_hci_flush(struct hci_dev *hdev)
{
- bluecard_info_t *info = hci_get_drvdata(hdev);
+ struct bluecard_info *info = hci_get_drvdata(hdev);
/* Drop TX queue */
skb_queue_purge(&(info->txq));
@@ -622,7 +623,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev)
static int bluecard_hci_open(struct hci_dev *hdev)
{
- bluecard_info_t *info = hci_get_drvdata(hdev);
+ struct bluecard_info *info = hci_get_drvdata(hdev);
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
@@ -643,7 +644,7 @@ static int bluecard_hci_open(struct hci_dev *hdev)
static int bluecard_hci_close(struct hci_dev *hdev)
{
- bluecard_info_t *info = hci_get_drvdata(hdev);
+ struct bluecard_info *info = hci_get_drvdata(hdev);
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
return 0;
@@ -663,7 +664,7 @@ static int bluecard_hci_close(struct hci_dev *hdev)
static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
- bluecard_info_t *info = hci_get_drvdata(hdev);
+ struct bluecard_info *info = hci_get_drvdata(hdev);
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
@@ -691,7 +692,7 @@ static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
/* ======================== Card services HCI interaction ======================== */
-static int bluecard_open(bluecard_info_t *info)
+static int bluecard_open(struct bluecard_info *info)
{
unsigned int iobase = info->p_dev->resource[0]->start;
struct hci_dev *hdev;
@@ -806,7 +807,7 @@ static int bluecard_open(bluecard_info_t *info)
}
-static int bluecard_close(bluecard_info_t *info)
+static int bluecard_close(struct bluecard_info *info)
{
unsigned int iobase = info->p_dev->resource[0]->start;
struct hci_dev *hdev = info->hdev;
@@ -833,7 +834,7 @@ static int bluecard_close(bluecard_info_t *info)
static int bluecard_probe(struct pcmcia_device *link)
{
- bluecard_info_t *info;
+ struct bluecard_info *info;
/* Create new info device */
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -857,7 +858,7 @@ static void bluecard_detach(struct pcmcia_device *link)
static int bluecard_config(struct pcmcia_device *link)
{
- bluecard_info_t *info = link->priv;
+ struct bluecard_info *info = link->priv;
int i, n;
link->config_index = 0x20;
@@ -897,7 +898,7 @@ failed:
static void bluecard_release(struct pcmcia_device *link)
{
- bluecard_info_t *info = link->priv;
+ struct bluecard_info *info = link->priv;
bluecard_close(info);
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 1d82721..4f7e8d4 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -67,7 +67,7 @@ MODULE_FIRMWARE("BT3CPCC.bin");
/* ======================== Local structures ======================== */
-typedef struct bt3c_info_t {
+struct bt3c_info {
struct pcmcia_device *p_dev;
struct hci_dev *hdev;
@@ -80,7 +80,7 @@ typedef struct bt3c_info_t {
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
-} bt3c_info_t;
+};
static int bt3c_config(struct pcmcia_device *link);
@@ -175,7 +175,7 @@ static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
}
-static void bt3c_write_wakeup(bt3c_info_t *info)
+static void bt3c_write_wakeup(struct bt3c_info *info)
{
if (!info) {
BT_ERR("Unknown device");
@@ -214,7 +214,7 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
}
-static void bt3c_receive(bt3c_info_t *info)
+static void bt3c_receive(struct bt3c_info *info)
{
unsigned int iobase;
int size = 0, avail;
@@ -336,7 +336,7 @@ static void bt3c_receive(bt3c_info_t *info)
static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
{
- bt3c_info_t *info = dev_inst;
+ struct bt3c_info *info = dev_inst;
unsigned int iobase;
int iir;
irqreturn_t r = IRQ_NONE;
@@ -388,7 +388,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
static int bt3c_hci_flush(struct hci_dev *hdev)
{
- bt3c_info_t *info = hci_get_drvdata(hdev);
+ struct bt3c_info *info = hci_get_drvdata(hdev);
/* Drop TX queue */
skb_queue_purge(&(info->txq));
@@ -418,7 +418,7 @@ static int bt3c_hci_close(struct hci_dev *hdev)
static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
- bt3c_info_t *info = hci_get_drvdata(hdev);
+ struct bt3c_info *info = hci_get_drvdata(hdev);
unsigned long flags;
switch (bt_cb(skb)->pkt_type) {
@@ -451,7 +451,8 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
/* ======================== Card services HCI interaction ======================== */
-static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware,
+static int bt3c_load_firmware(struct bt3c_info *info,
+ const unsigned char *firmware,
int count)
{
char *ptr = (char *) firmware;
@@ -536,7 +537,7 @@ error:
}
-static int bt3c_open(bt3c_info_t *info)
+static int bt3c_open(struct bt3c_info *info)
{
const struct firmware *firmware;
struct hci_dev *hdev;
@@ -603,7 +604,7 @@ error:
}
-static int bt3c_close(bt3c_info_t *info)
+static int bt3c_close(struct bt3c_info *info)
{
struct hci_dev *hdev = info->hdev;
@@ -620,7 +621,7 @@ static int bt3c_close(bt3c_info_t *info)
static int bt3c_probe(struct pcmcia_device *link)
{
- bt3c_info_t *info;
+ struct bt3c_info *info;
/* Create new info device */
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -683,7 +684,7 @@ static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
static int bt3c_config(struct pcmcia_device *link)
{
- bt3c_info_t *info = link->priv;
+ struct bt3c_info *info = link->priv;
int i;
unsigned long try;
@@ -724,7 +725,7 @@ failed:
static void bt3c_release(struct pcmcia_device *link)
{
- bt3c_info_t *info = link->priv;
+ struct bt3c_info *info = link->priv;
bt3c_close(info);
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index fb948f0..abb4d21 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -62,7 +62,7 @@ MODULE_LICENSE("GPL");
/* ======================== Local structures ======================== */
-typedef struct btuart_info_t {
+struct btuart_info {
struct pcmcia_device *p_dev;
struct hci_dev *hdev;
@@ -75,7 +75,7 @@ typedef struct btuart_info_t {
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
-} btuart_info_t;
+};
static int btuart_config(struct pcmcia_device *link);
@@ -127,7 +127,7 @@ static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
}
-static void btuart_write_wakeup(btuart_info_t *info)
+static void btuart_write_wakeup(struct btuart_info *info)
{
if (!info) {
BT_ERR("Unknown device");
@@ -172,7 +172,7 @@ static void btuart_write_wakeup(btuart_info_t *info)
}
-static void btuart_receive(btuart_info_t *info)
+static void btuart_receive(struct btuart_info *info)
{
unsigned int iobase;
int boguscount = 0;
@@ -286,7 +286,7 @@ static void btuart_receive(btuart_info_t *info)
static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
{
- btuart_info_t *info = dev_inst;
+ struct btuart_info *info = dev_inst;
unsigned int iobase;
int boguscount = 0;
int iir, lsr;
@@ -340,7 +340,8 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
}
-static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
+static void btuart_change_speed(struct btuart_info *info,
+ unsigned int speed)
{
unsigned long flags;
unsigned int iobase;
@@ -397,7 +398,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
static int btuart_hci_flush(struct hci_dev *hdev)
{
- btuart_info_t *info = hci_get_drvdata(hdev);
+ struct btuart_info *info = hci_get_drvdata(hdev);
/* Drop TX queue */
skb_queue_purge(&(info->txq));
@@ -427,7 +428,7 @@ static int btuart_hci_close(struct hci_dev *hdev)
static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
- btuart_info_t *info = hci_get_drvdata(hdev);
+ struct btuart_info *info = hci_get_drvdata(hdev);
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
@@ -455,7 +456,7 @@ static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
/* ======================== Card services HCI interaction ======================== */
-static int btuart_open(btuart_info_t *info)
+static int btuart_open(struct btuart_info *info)
{
unsigned long flags;
unsigned int iobase = info->p_dev->resource[0]->start;
@@ -521,7 +522,7 @@ static int btuart_open(btuart_info_t *info)
}
-static int btuart_close(btuart_info_t *info)
+static int btuart_close(struct btuart_info *info)
{
unsigned long flags;
unsigned int iobase = info->p_dev->resource[0]->start;
@@ -550,7 +551,7 @@ static int btuart_close(btuart_info_t *info)
static int btuart_probe(struct pcmcia_device *link)
{
- btuart_info_t *info;
+ struct btuart_info *info;
/* Create new info device */
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -613,7 +614,7 @@ static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
static int btuart_config(struct pcmcia_device *link)
{
- btuart_info_t *info = link->priv;
+ struct btuart_info *info = link->priv;
int i;
int try;
@@ -654,7 +655,7 @@ failed:
static void btuart_release(struct pcmcia_device *link)
{
- btuart_info_t *info = link->priv;
+ struct btuart_info *info = link->priv;
btuart_close(info);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 292c38e8..a79d657 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -165,6 +165,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -330,6 +331,9 @@ static void btusb_intr_complete(struct urb *urb)
BT_ERR("%s corrupted event packet", hdev->name);
hdev->stat.err_rx++;
}
+ } else if (urb->status == -ENOENT) {
+ /* Avoid suspend failed when usb_kill_urb */
+ return;
}
if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
@@ -418,6 +422,9 @@ static void btusb_bulk_complete(struct urb *urb)
BT_ERR("%s corrupted ACL packet", hdev->name);
hdev->stat.err_rx++;
}
+ } else if (urb->status == -ENOENT) {
+ /* Avoid suspend failed when usb_kill_urb */
+ return;
}
if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
@@ -512,6 +519,9 @@ static void btusb_isoc_complete(struct urb *urb)
hdev->stat.err_rx++;
}
}
+ } else if (urb->status == -ENOENT) {
+ /* Avoid suspend failed when usb_kill_urb */
+ return;
}
if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 2bd8fad..78e10f0 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -62,7 +62,7 @@ MODULE_LICENSE("GPL");
/* ======================== Local structures ======================== */
-typedef struct dtl1_info_t {
+struct dtl1_info {
struct pcmcia_device *p_dev;
struct hci_dev *hdev;
@@ -78,7 +78,7 @@ typedef struct dtl1_info_t {
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
-} dtl1_info_t;
+};
static int dtl1_config(struct pcmcia_device *link);
@@ -94,11 +94,11 @@ static int dtl1_config(struct pcmcia_device *link);
#define RECV_WAIT_DATA 1
-typedef struct {
+struct nsh {
u8 type;
u8 zero;
u16 len;
-} __packed nsh_t; /* Nokia Specific Header */
+} __packed; /* Nokia Specific Header */
#define NSHL 4 /* Nokia Specific Header Length */
@@ -126,7 +126,7 @@ static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
}
-static void dtl1_write_wakeup(dtl1_info_t *info)
+static void dtl1_write_wakeup(struct dtl1_info *info)
{
if (!info) {
BT_ERR("Unknown device");
@@ -176,7 +176,7 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
}
-static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
+static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb)
{
u8 flowmask = *(u8 *)skb->data;
int i;
@@ -199,10 +199,10 @@ static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
}
-static void dtl1_receive(dtl1_info_t *info)
+static void dtl1_receive(struct dtl1_info *info)
{
unsigned int iobase;
- nsh_t *nsh;
+ struct nsh *nsh;
int boguscount = 0;
if (!info) {
@@ -227,7 +227,7 @@ static void dtl1_receive(dtl1_info_t *info)
}
*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
- nsh = (nsh_t *)info->rx_skb->data;
+ nsh = (struct nsh *)info->rx_skb->data;
info->rx_count--;
@@ -287,7 +287,7 @@ static void dtl1_receive(dtl1_info_t *info)
static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
{
- dtl1_info_t *info = dev_inst;
+ struct dtl1_info *info = dev_inst;
unsigned int iobase;
unsigned char msr;
int boguscount = 0;
@@ -365,7 +365,7 @@ static int dtl1_hci_open(struct hci_dev *hdev)
static int dtl1_hci_flush(struct hci_dev *hdev)
{
- dtl1_info_t *info = hci_get_drvdata(hdev);
+ struct dtl1_info *info = hci_get_drvdata(hdev);
/* Drop TX queue */
skb_queue_purge(&(info->txq));
@@ -387,9 +387,9 @@ static int dtl1_hci_close(struct hci_dev *hdev)
static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
- dtl1_info_t *info = hci_get_drvdata(hdev);
+ struct dtl1_info *info = hci_get_drvdata(hdev);
struct sk_buff *s;
- nsh_t nsh;
+ struct nsh nsh;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
@@ -436,7 +436,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
/* ======================== Card services HCI interaction ======================== */
-static int dtl1_open(dtl1_info_t *info)
+static int dtl1_open(struct dtl1_info *info)
{
unsigned long flags;
unsigned int iobase = info->p_dev->resource[0]->start;
@@ -505,7 +505,7 @@ static int dtl1_open(dtl1_info_t *info)
}
-static int dtl1_close(dtl1_info_t *info)
+static int dtl1_close(struct dtl1_info *info)
{
unsigned long flags;
unsigned int iobase = info->p_dev->resource[0]->start;
@@ -534,7 +534,7 @@ static int dtl1_close(dtl1_info_t *info)
static int dtl1_probe(struct pcmcia_device *link)
{
- dtl1_info_t *info;
+ struct dtl1_info *info;
/* Create new info device */
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -552,7 +552,7 @@ static int dtl1_probe(struct pcmcia_device *link)
static void dtl1_detach(struct pcmcia_device *link)
{
- dtl1_info_t *info = link->priv;
+ struct dtl1_info *info = link->priv;
dtl1_close(info);
pcmcia_disable_device(link);
@@ -571,7 +571,7 @@ static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
static int dtl1_config(struct pcmcia_device *link)
{
- dtl1_info_t *info = link->priv;
+ struct dtl1_info *info = link->priv;
int ret;
/* Look for a generic full-sized window */
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index caacb42..a228386 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -237,7 +237,7 @@ static void h5_pkt_cull(struct h5 *h5)
break;
to_remove--;
- seq = (seq - 1) % 8;
+ seq = (seq - 1) & 0x07;
}
if (seq != h5->rx_ack)
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 334c2ec..da92bfa 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2423,8 +2423,6 @@ static void at76_delete_device(struct at76_priv *priv)
kfree_skb(priv->rx_skb);
- usb_put_dev(priv->udev);
-
at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/ieee80211_hw",
__func__);
ieee80211_free_hw(priv->hw);
@@ -2558,6 +2556,7 @@ static void at76_disconnect(struct usb_interface *interface)
wiphy_info(priv->hw->wiphy, "disconnecting\n");
at76_delete_device(priv);
+ usb_put_dev(priv->udev);
dev_info(&interface->dev, "disconnected\n");
}
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index fd9e530..c1a4ade 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -261,6 +261,7 @@ enum ATH_DEBUG {
ATH_DBG_MCI = 0x00008000,
ATH_DBG_DFS = 0x00010000,
ATH_DBG_WOW = 0x00020000,
+ ATH_DBG_CHAN_CTX = 0x00040000,
ATH_DBG_ANY = 0xffffffff
};
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index a6f5285..1053bb5 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -25,6 +25,7 @@ config ATH10K_DEBUG
config ATH10K_DEBUGFS
bool "Atheros ath10k debugfs support"
depends on ATH10K
+ select RELAY
---help---
Enabled debugfs support
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index a4179f4..2cfb63c 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -10,6 +10,7 @@ ath10k_core-y += mac.o \
wmi.o \
bmi.o
+ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c
index 17d221a..3d29b08 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.c
+++ b/drivers/net/wireless/ath/ath10k/bmi.c
@@ -22,7 +22,7 @@
void ath10k_bmi_start(struct ath10k *ar)
{
- ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n");
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
ar->bmi.done_sent = false;
}
@@ -33,10 +33,10 @@ int ath10k_bmi_done(struct ath10k *ar)
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n");
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
if (ar->bmi.done_sent) {
- ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n");
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
return 0;
}
@@ -45,7 +45,7 @@ int ath10k_bmi_done(struct ath10k *ar)
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
if (ret) {
- ath10k_warn("unable to write to the device: %d\n", ret);
+ ath10k_warn(ar, "unable to write to the device: %d\n", ret);
return ret;
}
@@ -61,10 +61,10 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
u32 resplen = sizeof(resp.get_target_info);
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n");
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
if (ar->bmi.done_sent) {
- ath10k_warn("BMI Get Target Info Command disallowed\n");
+ ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
return -EBUSY;
}
@@ -72,12 +72,12 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
if (ret) {
- ath10k_warn("unable to get target info from device\n");
+ ath10k_warn(ar, "unable to get target info from device\n");
return ret;
}
if (resplen < sizeof(resp.get_target_info)) {
- ath10k_warn("invalid get_target_info response length (%d)\n",
+ ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
resplen);
return -EIO;
}
@@ -97,11 +97,11 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
u32 rxlen;
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
address, length);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -115,7 +115,7 @@ 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 (%d)\n",
+ ath10k_warn(ar, "unable to read from the device (%d)\n",
ret);
return ret;
}
@@ -137,11 +137,11 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
u32 txlen;
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
address, length);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -159,7 +159,7 @@ 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 (%d)\n",
+ ath10k_warn(ar, "unable to write to the device (%d)\n",
ret);
return ret;
}
@@ -183,11 +183,11 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
u32 resplen = sizeof(resp.execute);
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
address, param);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -197,19 +197,19 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
if (ret) {
- ath10k_warn("unable to read from the device\n");
+ ath10k_warn(ar, "unable to read from the device\n");
return ret;
}
if (resplen < sizeof(resp.execute)) {
- ath10k_warn("invalid execute response length (%d)\n",
+ ath10k_warn(ar, "invalid execute response length (%d)\n",
resplen);
return -EIO;
}
*result = __le32_to_cpu(resp.execute.result);
- ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
return 0;
}
@@ -221,11 +221,11 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
u32 txlen;
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
buffer, length);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -241,7 +241,7 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
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(ar, "unable to write to the device\n");
return ret;
}
@@ -258,11 +258,11 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
address);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -271,7 +271,7 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
if (ret) {
- ath10k_warn("unable to Start LZ Stream to the device\n");
+ ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
return ret;
}
@@ -286,7 +286,7 @@ int ath10k_bmi_fast_download(struct ath10k *ar,
u32 trailer_len = length - head_len;
int ret;
- ath10k_dbg(ATH10K_DBG_BMI,
+ ath10k_dbg(ar, ATH10K_DBG_BMI,
"bmi fast download address 0x%x buffer 0x%p length %d\n",
address, buffer, length);
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 4333107..71eef23 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -284,13 +284,9 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
int ret = 0;
if (nbytes > ce_state->src_sz_max)
- ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n",
+ ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
__func__, nbytes, ce_state->src_sz_max);
- ret = ath10k_pci_wake(ar);
- if (ret)
- return ret;
-
if (unlikely(CE_RING_DELTA(nentries_mask,
write_index, sw_index - 1) <= 0)) {
ret = -ENOSR;
@@ -325,7 +321,6 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
src_ring->write_index = write_index;
exit:
- ath10k_pci_sleep(ar);
return ret;
}
@@ -390,49 +385,57 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe)
return delta;
}
-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
- void *per_recv_context,
- u32 buffer)
+
+int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe)
{
- struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
- u32 ctrl_addr = ce_state->ctrl_addr;
- struct ath10k *ar = ce_state->ar;
+ struct ath10k *ar = pipe->ar;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
unsigned int nentries_mask = dest_ring->nentries_mask;
- unsigned int write_index;
- unsigned int sw_index;
- int ret;
+ unsigned int write_index = dest_ring->write_index;
+ unsigned int sw_index = dest_ring->sw_index;
- spin_lock_bh(&ar_pci->ce_lock);
- write_index = dest_ring->write_index;
- sw_index = dest_ring->sw_index;
+ lockdep_assert_held(&ar_pci->ce_lock);
- ret = ath10k_pci_wake(ar);
- if (ret)
- goto out;
+ return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
+}
- if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {
- struct ce_desc *base = dest_ring->base_addr_owner_space;
- struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
+int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
+{
+ struct ath10k *ar = pipe->ar;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
+ unsigned int nentries_mask = dest_ring->nentries_mask;
+ unsigned int write_index = dest_ring->write_index;
+ unsigned int sw_index = dest_ring->sw_index;
+ struct ce_desc *base = dest_ring->base_addr_owner_space;
+ struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
+ u32 ctrl_addr = pipe->ctrl_addr;
- /* Update destination descriptor */
- desc->addr = __cpu_to_le32(buffer);
- desc->nbytes = 0;
+ lockdep_assert_held(&ar_pci->ce_lock);
- dest_ring->per_transfer_context[write_index] =
- per_recv_context;
+ if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0)
+ return -EIO;
- /* Update Destination Ring Write Index */
- write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
- ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
- dest_ring->write_index = write_index;
- ret = 0;
- } else {
- ret = -EIO;
- }
- ath10k_pci_sleep(ar);
+ desc->addr = __cpu_to_le32(paddr);
+ desc->nbytes = 0;
+
+ dest_ring->per_transfer_context[write_index] = ctx;
+ write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+ ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
+ dest_ring->write_index = write_index;
+
+ return 0;
+}
+
+int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
+{
+ struct ath10k *ar = pipe->ar;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int ret;
-out:
+ spin_lock_bh(&ar_pci->ce_lock);
+ ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr);
spin_unlock_bh(&ar_pci->ce_lock);
return ret;
@@ -588,7 +591,6 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
unsigned int sw_index = src_ring->sw_index;
struct ce_desc *sdesc, *sbase;
unsigned int read_index;
- int ret;
if (src_ring->hw_index == sw_index) {
/*
@@ -599,18 +601,12 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
* value of the HW index has become stale.
*/
- ret = ath10k_pci_wake(ar);
- if (ret)
- return ret;
-
read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
if (read_index == 0xffffffff)
return -ENODEV;
read_index &= nentries_mask;
src_ring->hw_index = read_index;
-
- ath10k_pci_sleep(ar);
}
read_index = src_ring->hw_index;
@@ -731,11 +727,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
u32 ctrl_addr = ce_state->ctrl_addr;
- int ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret)
- return;
spin_lock_bh(&ar_pci->ce_lock);
@@ -760,7 +751,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK);
spin_unlock_bh(&ar_pci->ce_lock);
- ath10k_pci_sleep(ar);
}
/*
@@ -771,13 +761,9 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
void ath10k_ce_per_engine_service_any(struct ath10k *ar)
{
- int ce_id, ret;
+ int ce_id;
u32 intr_summary;
- ret = ath10k_pci_wake(ar);
- if (ret)
- return;
-
intr_summary = CE_INTERRUPT_SUMMARY(ar);
for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) {
@@ -789,8 +775,6 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
ath10k_ce_per_engine_service(ar, ce_id);
}
-
- ath10k_pci_sleep(ar);
}
/*
@@ -800,16 +784,11 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
*
* Called with ce_lock held.
*/
-static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
- int disable_copy_compl_intr)
+static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state)
{
u32 ctrl_addr = ce_state->ctrl_addr;
struct ath10k *ar = ce_state->ar;
- int ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret)
- return;
+ bool disable_copy_compl_intr = ce_state->attr_flags & CE_ATTR_DIS_INTR;
if ((!disable_copy_compl_intr) &&
(ce_state->send_cb || ce_state->recv_cb))
@@ -818,17 +797,11 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
-
- ath10k_pci_sleep(ar);
}
int ath10k_ce_disable_interrupts(struct ath10k *ar)
{
- int ce_id, ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret)
- return ret;
+ int ce_id;
for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
u32 ctrl_addr = ath10k_ce_base_address(ce_id);
@@ -838,34 +811,16 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar)
ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
}
- ath10k_pci_sleep(ar);
-
return 0;
}
-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
- void (*send_cb)(struct ath10k_ce_pipe *),
- int disable_interrupts)
+void ath10k_ce_enable_interrupts(struct ath10k *ar)
{
- struct ath10k *ar = ce_state->ar;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int ce_id;
- spin_lock_bh(&ar_pci->ce_lock);
- ce_state->send_cb = send_cb;
- ath10k_ce_per_engine_handler_adjust(ce_state, disable_interrupts);
- spin_unlock_bh(&ar_pci->ce_lock);
-}
-
-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
- void (*recv_cb)(struct ath10k_ce_pipe *))
-{
- struct ath10k *ar = ce_state->ar;
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- spin_lock_bh(&ar_pci->ce_lock);
- ce_state->recv_cb = recv_cb;
- ath10k_ce_per_engine_handler_adjust(ce_state, 0);
- spin_unlock_bh(&ar_pci->ce_lock);
+ for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+ ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]);
}
static int ath10k_ce_init_src_ring(struct ath10k *ar,
@@ -898,7 +853,7 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot init ce src ring id %d entries %d base_addr %p\n",
ce_id, nentries, src_ring->base_addr_owner_space);
@@ -932,7 +887,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot ce dest ring id %d entries %d base_addr %p\n",
ce_id, nentries, dest_ring->base_addr_owner_space);
@@ -1067,7 +1022,9 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
* initialized by software/firmware.
*/
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
- const struct ce_attr *attr)
+ const struct ce_attr *attr,
+ void (*send_cb)(struct ath10k_ce_pipe *),
+ void (*recv_cb)(struct ath10k_ce_pipe *))
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
@@ -1084,39 +1041,37 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- ret = ath10k_pci_wake(ar);
- if (ret)
- return ret;
-
spin_lock_bh(&ar_pci->ce_lock);
ce_state->ar = ar;
ce_state->id = ce_id;
ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
ce_state->attr_flags = attr->flags;
ce_state->src_sz_max = attr->src_sz_max;
+ if (attr->src_nentries)
+ ce_state->send_cb = send_cb;
+ if (attr->dest_nentries)
+ ce_state->recv_cb = recv_cb;
spin_unlock_bh(&ar_pci->ce_lock);
if (attr->src_nentries) {
ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
if (ret) {
- ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
+ ath10k_err(ar, "Failed to initialize CE src ring for ID: %d (%d)\n",
ce_id, ret);
- goto out;
+ return ret;
}
}
if (attr->dest_nentries) {
ret = ath10k_ce_init_dest_ring(ar, ce_id, attr);
if (ret) {
- ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
+ ath10k_err(ar, "Failed to initialize CE dest ring for ID: %d (%d)\n",
ce_id, ret);
- goto out;
+ return ret;
}
}
-out:
- ath10k_pci_sleep(ar);
- return ret;
+ return 0;
}
static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
@@ -1140,16 +1095,8 @@ static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id)
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
{
- int ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret)
- return;
-
ath10k_ce_deinit_src_ring(ar, ce_id);
ath10k_ce_deinit_dest_ring(ar, ce_id);
-
- ath10k_pci_sleep(ar);
}
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
@@ -1163,7 +1110,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
if (IS_ERR(ce_state->src_ring)) {
ret = PTR_ERR(ce_state->src_ring);
- ath10k_err("failed to allocate copy engine source ring %d: %d\n",
+ ath10k_err(ar, "failed to allocate copy engine source ring %d: %d\n",
ce_id, ret);
ce_state->src_ring = NULL;
return ret;
@@ -1175,7 +1122,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
attr);
if (IS_ERR(ce_state->dest_ring)) {
ret = PTR_ERR(ce_state->dest_ring);
- ath10k_err("failed to allocate copy engine destination ring %d: %d\n",
+ ath10k_err(ar, "failed to allocate copy engine destination ring %d: %d\n",
ce_id, ret);
ce_state->dest_ring = NULL;
return ret;
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 7a5a36f..82d1f23 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -162,30 +162,13 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
- void (*send_cb)(struct ath10k_ce_pipe *),
- int disable_interrupts);
-
int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
/*==================Recv=======================*/
-/*
- * Make a buffer available to receive. The buffer must be at least of a
- * minimal size appropriate for this copy engine (src_sz_max attribute).
- * ce - which copy engine to use
- * per_transfer_recv_context - context passed back to caller's recv_cb
- * buffer - address of buffer in CE space
- * Returns 0 on success; otherwise an error status.
- *
- * Implemenation note: Pushes a buffer to Dest ring.
- */
-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
- void *per_transfer_recv_context,
- u32 buffer);
-
-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
- void (*recv_cb)(struct ath10k_ce_pipe *));
+int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe);
+int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
+int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
/* recv flags */
/* Data is byte-swapped */
@@ -214,7 +197,9 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
/*==================CE Engine Initialization=======================*/
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
- const struct ce_attr *attr);
+ const struct ce_attr *attr,
+ void (*send_cb)(struct ath10k_ce_pipe *),
+ void (*recv_cb)(struct ath10k_ce_pipe *));
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
const struct ce_attr *attr);
@@ -245,6 +230,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
void ath10k_ce_per_engine_service_any(struct ath10k *ar);
void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_disable_interrupts(struct ath10k *ar);
+void ath10k_ce_enable_interrupts(struct ath10k *ar);
/* ce_attr.flags values */
/* Use NonSnooping PCIe accesses? */
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 93adb8c..651a6da 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -53,7 +53,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
static void ath10k_send_suspend_complete(struct ath10k *ar)
{
- ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n");
complete(&ar->target_suspend);
}
@@ -67,14 +67,14 @@ static int ath10k_init_configure_target(struct ath10k *ar)
ret = ath10k_bmi_write32(ar, hi_app_host_interest,
HTC_PROTOCOL_VERSION);
if (ret) {
- ath10k_err("settings HTC version failed\n");
+ ath10k_err(ar, "settings HTC version failed\n");
return ret;
}
/* set the firmware mode to STA/IBSS/AP */
ret = ath10k_bmi_read32(ar, hi_option_flag, &param_host);
if (ret) {
- ath10k_err("setting firmware mode (1/2) failed\n");
+ ath10k_err(ar, "setting firmware mode (1/2) failed\n");
return ret;
}
@@ -93,14 +93,14 @@ static int ath10k_init_configure_target(struct ath10k *ar)
ret = ath10k_bmi_write32(ar, hi_option_flag, param_host);
if (ret) {
- ath10k_err("setting firmware mode (2/2) failed\n");
+ ath10k_err(ar, "setting firmware mode (2/2) failed\n");
return ret;
}
/* We do all byte-swapping on the host */
ret = ath10k_bmi_write32(ar, hi_be, 0);
if (ret) {
- ath10k_err("setting host CPU BE mode failed\n");
+ ath10k_err(ar, "setting host CPU BE mode failed\n");
return ret;
}
@@ -108,7 +108,7 @@ static int ath10k_init_configure_target(struct ath10k *ar)
ret = ath10k_bmi_write32(ar, hi_fw_swap, 0);
if (ret) {
- ath10k_err("setting FW data/desc swap flags failed\n");
+ ath10k_err(ar, "setting FW data/desc swap flags failed\n");
return ret;
}
@@ -146,11 +146,12 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr);
if (ret) {
- ath10k_err("could not read board ext data addr (%d)\n", ret);
+ ath10k_err(ar, "could not read board ext data addr (%d)\n",
+ ret);
return ret;
}
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot push board extended data addr 0x%x\n",
board_ext_data_addr);
@@ -158,7 +159,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
return 0;
if (ar->board_len != (board_data_size + board_ext_data_size)) {
- ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n",
+ ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",
ar->board_len, board_data_size, board_ext_data_size);
return -EINVAL;
}
@@ -167,14 +168,15 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
ar->board_data + board_data_size,
board_ext_data_size);
if (ret) {
- ath10k_err("could not write board ext data (%d)\n", ret);
+ ath10k_err(ar, "could not write board ext data (%d)\n", ret);
return ret;
}
ret = ath10k_bmi_write32(ar, hi_board_ext_data_config,
(board_ext_data_size << 16) | 1);
if (ret) {
- ath10k_err("could not write board ext data bit (%d)\n", ret);
+ ath10k_err(ar, "could not write board ext data bit (%d)\n",
+ ret);
return ret;
}
@@ -189,13 +191,13 @@ static int ath10k_download_board_data(struct ath10k *ar)
ret = ath10k_push_board_ext_data(ar);
if (ret) {
- ath10k_err("could not push board ext data (%d)\n", ret);
+ ath10k_err(ar, "could not push board ext data (%d)\n", ret);
goto exit;
}
ret = ath10k_bmi_read32(ar, hi_board_data, &address);
if (ret) {
- ath10k_err("could not read board data addr (%d)\n", ret);
+ ath10k_err(ar, "could not read board data addr (%d)\n", ret);
goto exit;
}
@@ -203,13 +205,13 @@ static int ath10k_download_board_data(struct ath10k *ar)
min_t(u32, board_data_size,
ar->board_len));
if (ret) {
- ath10k_err("could not write board data (%d)\n", ret);
+ ath10k_err(ar, "could not write board data (%d)\n", ret);
goto exit;
}
ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
if (ret) {
- ath10k_err("could not write board data bit (%d)\n", ret);
+ ath10k_err(ar, "could not write board data bit (%d)\n", ret);
goto exit;
}
@@ -225,30 +227,30 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
/* OTP is optional */
if (!ar->otp_data || !ar->otp_len) {
- ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
+ ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
ar->otp_data, ar->otp_len);
return 0;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
address, ar->otp_len);
ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
if (ret) {
- ath10k_err("could not write otp (%d)\n", ret);
+ ath10k_err(ar, "could not write otp (%d)\n", ret);
return ret;
}
ret = ath10k_bmi_execute(ar, address, 0, &result);
if (ret) {
- ath10k_err("could not execute otp (%d)\n", ret);
+ ath10k_err(ar, "could not execute otp (%d)\n", ret);
return ret;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
if (result != 0) {
- ath10k_err("otp calibration failed: %d", result);
+ ath10k_err(ar, "otp calibration failed: %d", result);
return -EINVAL;
}
@@ -265,7 +267,7 @@ static int ath10k_download_fw(struct ath10k *ar)
ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data,
ar->firmware_len);
if (ret) {
- ath10k_err("could not write fw (%d)\n", ret);
+ ath10k_err(ar, "could not write fw (%d)\n", ret);
goto exit;
}
@@ -302,12 +304,12 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
int ret = 0;
if (ar->hw_params.fw.fw == NULL) {
- ath10k_err("firmware file not defined\n");
+ ath10k_err(ar, "firmware file not defined\n");
return -EINVAL;
}
if (ar->hw_params.fw.board == NULL) {
- ath10k_err("board data file not defined");
+ ath10k_err(ar, "board data file not defined");
return -EINVAL;
}
@@ -316,7 +318,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
ar->hw_params.fw.board);
if (IS_ERR(ar->board)) {
ret = PTR_ERR(ar->board);
- ath10k_err("could not fetch board data (%d)\n", ret);
+ ath10k_err(ar, "could not fetch board data (%d)\n", ret);
goto err;
}
@@ -328,7 +330,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
ar->hw_params.fw.fw);
if (IS_ERR(ar->firmware)) {
ret = PTR_ERR(ar->firmware);
- ath10k_err("could not fetch firmware (%d)\n", ret);
+ ath10k_err(ar, "could not fetch firmware (%d)\n", ret);
goto err;
}
@@ -344,7 +346,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
ar->hw_params.fw.otp);
if (IS_ERR(ar->otp)) {
ret = PTR_ERR(ar->otp);
- ath10k_err("could not fetch otp (%d)\n", ret);
+ ath10k_err(ar, "could not fetch otp (%d)\n", ret);
goto err;
}
@@ -369,7 +371,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
/* first fetch the firmware file (firmware-*.bin) */
ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
if (IS_ERR(ar->firmware)) {
- ath10k_err("could not fetch firmware file '%s/%s': %ld\n",
+ ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n",
ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware));
return PTR_ERR(ar->firmware);
}
@@ -381,14 +383,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
if (len < magic_len) {
- ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n",
+ ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n",
ar->hw_params.fw.dir, name, len);
ret = -EINVAL;
goto err;
}
if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
- ath10k_err("invalid firmware magic\n");
+ ath10k_err(ar, "invalid firmware magic\n");
ret = -EINVAL;
goto err;
}
@@ -410,7 +412,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
data += sizeof(*hdr);
if (len < ie_len) {
- ath10k_err("invalid length for FW IE %d (%zu < %zu)\n",
+ ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
ie_id, len, ie_len);
ret = -EINVAL;
goto err;
@@ -424,7 +426,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
memcpy(ar->hw->wiphy->fw_version, data, ie_len);
ar->hw->wiphy->fw_version[ie_len] = '\0';
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"found fw version %s\n",
ar->hw->wiphy->fw_version);
break;
@@ -434,11 +436,11 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
timestamp = (__le32 *)data;
- ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n",
le32_to_cpup(timestamp));
break;
case ATH10K_FW_IE_FEATURES:
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"found firmware features ie (%zd B)\n",
ie_len);
@@ -450,19 +452,19 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
break;
if (data[index] & (1 << bit)) {
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"Enabling feature bit: %i\n",
i);
__set_bit(i, ar->fw_features);
}
}
- ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
+ ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",
ar->fw_features,
sizeof(ar->fw_features));
break;
case ATH10K_FW_IE_FW_IMAGE:
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"found fw image ie (%zd B)\n",
ie_len);
@@ -471,7 +473,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
break;
case ATH10K_FW_IE_OTP_IMAGE:
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"found otp image ie (%zd B)\n",
ie_len);
@@ -480,7 +482,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
break;
default:
- ath10k_warn("Unknown FW IE: %u\n",
+ ath10k_warn(ar, "Unknown FW IE: %u\n",
le32_to_cpu(hdr->id));
break;
}
@@ -493,15 +495,22 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
}
if (!ar->firmware_data || !ar->firmware_len) {
- ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
+ ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
ar->hw_params.fw.dir, name);
ret = -ENOMEDIUM;
goto err;
}
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
+ !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
+ ret = -EINVAL;
+ goto err;
+ }
+
/* now fetch the board file */
if (ar->hw_params.fw.board == NULL) {
- ath10k_err("board data file not defined");
+ ath10k_err(ar, "board data file not defined");
ret = -EINVAL;
goto err;
}
@@ -511,7 +520,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
ar->hw_params.fw.board);
if (IS_ERR(ar->board)) {
ret = PTR_ERR(ar->board);
- ath10k_err("could not fetch board data '%s/%s' (%d)\n",
+ ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n",
ar->hw_params.fw.dir, ar->hw_params.fw.board,
ret);
goto err;
@@ -531,22 +540,29 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
{
int ret;
+ ar->fw_api = 3;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
+ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE);
+ if (ret == 0)
+ goto success;
+
ar->fw_api = 2;
- ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
if (ret == 0)
goto success;
ar->fw_api = 1;
- ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
ret = ath10k_core_fetch_firmware_api_1(ar);
if (ret)
return ret;
success:
- ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
return 0;
}
@@ -557,19 +573,19 @@ static int ath10k_init_download_firmware(struct ath10k *ar)
ret = ath10k_download_board_data(ar);
if (ret) {
- ath10k_err("failed to download board data: %d\n", ret);
+ ath10k_err(ar, "failed to download board data: %d\n", ret);
return ret;
}
ret = ath10k_download_and_run_otp(ar);
if (ret) {
- ath10k_err("failed to run otp: %d\n", ret);
+ ath10k_err(ar, "failed to run otp: %d\n", ret);
return ret;
}
ret = ath10k_download_fw(ar);
if (ret) {
- ath10k_err("failed to download firmware: %d\n", ret);
+ ath10k_err(ar, "failed to download firmware: %d\n", ret);
return ret;
}
@@ -586,7 +602,7 @@ static int ath10k_init_uart(struct ath10k *ar)
*/
ret = ath10k_bmi_write32(ar, hi_serial_enable, 0);
if (ret) {
- ath10k_warn("could not disable UART prints (%d)\n", ret);
+ ath10k_warn(ar, "could not disable UART prints (%d)\n", ret);
return ret;
}
@@ -595,24 +611,24 @@ static int ath10k_init_uart(struct ath10k *ar)
ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
if (ret) {
- ath10k_warn("could not enable UART prints (%d)\n", ret);
+ ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
return ret;
}
ret = ath10k_bmi_write32(ar, hi_serial_enable, 1);
if (ret) {
- ath10k_warn("could not enable UART prints (%d)\n", ret);
+ ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
return ret;
}
/* Set the UART baud rate to 19200. */
ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200);
if (ret) {
- ath10k_warn("could not set the baud rate (%d)\n", ret);
+ ath10k_warn(ar, "could not set the baud rate (%d)\n", ret);
return ret;
}
- ath10k_info("UART prints enabled\n");
+ ath10k_info(ar, "UART prints enabled\n");
return 0;
}
@@ -629,14 +645,14 @@ static int ath10k_init_hw_params(struct ath10k *ar)
}
if (i == ARRAY_SIZE(ath10k_hw_params_list)) {
- ath10k_err("Unsupported hardware version: 0x%x\n",
+ ath10k_err(ar, "Unsupported hardware version: 0x%x\n",
ar->target_version);
return -EINVAL;
}
ar->hw_params = *hw_params;
- ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
ar->hw_params.name, ar->target_version);
return 0;
@@ -651,14 +667,14 @@ static void ath10k_core_restart(struct work_struct *work)
switch (ar->state) {
case ATH10K_STATE_ON:
ar->state = ATH10K_STATE_RESTARTING;
- del_timer_sync(&ar->scan.timeout);
- ath10k_reset_scan((unsigned long)ar);
+ ath10k_hif_stop(ar);
+ ath10k_scan_finish(ar);
ieee80211_restart_hw(ar->hw);
break;
case ATH10K_STATE_OFF:
/* this can happen if driver is being unloaded
* or if the crash happens during FW probing */
- ath10k_warn("cannot restart a device that hasn't been started\n");
+ ath10k_warn(ar, "cannot restart a device that hasn't been started\n");
break;
case ATH10K_STATE_RESTARTING:
/* hw restart might be requested from multiple places */
@@ -667,7 +683,7 @@ static void ath10k_core_restart(struct work_struct *work)
ar->state = ATH10K_STATE_WEDGED;
/* fall through */
case ATH10K_STATE_WEDGED:
- ath10k_warn("device is wedged, will not restart\n");
+ ath10k_warn(ar, "device is wedged, will not restart\n");
break;
}
@@ -700,7 +716,7 @@ int ath10k_core_start(struct ath10k *ar)
status = ath10k_htc_init(ar);
if (status) {
- ath10k_err("could not init HTC (%d)\n", status);
+ ath10k_err(ar, "could not init HTC (%d)\n", status);
goto err;
}
@@ -710,90 +726,91 @@ int ath10k_core_start(struct ath10k *ar)
status = ath10k_wmi_attach(ar);
if (status) {
- ath10k_err("WMI attach failed: %d\n", status);
+ ath10k_err(ar, "WMI attach failed: %d\n", status);
goto err;
}
status = ath10k_htt_init(ar);
if (status) {
- ath10k_err("failed to init htt: %d\n", status);
+ ath10k_err(ar, "failed to init htt: %d\n", status);
goto err_wmi_detach;
}
status = ath10k_htt_tx_alloc(&ar->htt);
if (status) {
- ath10k_err("failed to alloc htt tx: %d\n", status);
+ ath10k_err(ar, "failed to alloc htt tx: %d\n", status);
goto err_wmi_detach;
}
status = ath10k_htt_rx_alloc(&ar->htt);
if (status) {
- ath10k_err("failed to alloc htt rx: %d\n", status);
+ ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
goto err_htt_tx_detach;
}
status = ath10k_hif_start(ar);
if (status) {
- ath10k_err("could not start HIF: %d\n", status);
+ ath10k_err(ar, "could not start HIF: %d\n", status);
goto err_htt_rx_detach;
}
status = ath10k_htc_wait_target(&ar->htc);
if (status) {
- ath10k_err("failed to connect to HTC: %d\n", status);
+ ath10k_err(ar, "failed to connect to HTC: %d\n", status);
goto err_hif_stop;
}
status = ath10k_htt_connect(&ar->htt);
if (status) {
- ath10k_err("failed to connect htt (%d)\n", status);
+ ath10k_err(ar, "failed to connect htt (%d)\n", status);
goto err_hif_stop;
}
status = ath10k_wmi_connect(ar);
if (status) {
- ath10k_err("could not connect wmi: %d\n", status);
+ ath10k_err(ar, "could not connect wmi: %d\n", status);
goto err_hif_stop;
}
status = ath10k_htc_start(&ar->htc);
if (status) {
- ath10k_err("failed to start htc: %d\n", status);
+ ath10k_err(ar, "failed to start htc: %d\n", status);
goto err_hif_stop;
}
status = ath10k_wmi_wait_for_service_ready(ar);
if (status <= 0) {
- ath10k_warn("wmi service ready event not received");
+ ath10k_warn(ar, "wmi service ready event not received");
status = -ETIMEDOUT;
- goto err_htc_stop;
+ goto err_hif_stop;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",
ar->hw->wiphy->fw_version);
status = ath10k_wmi_cmd_init(ar);
if (status) {
- ath10k_err("could not send WMI init command (%d)\n", status);
- goto err_htc_stop;
+ ath10k_err(ar, "could not send WMI init command (%d)\n",
+ status);
+ goto err_hif_stop;
}
status = ath10k_wmi_wait_for_unified_ready(ar);
if (status <= 0) {
- ath10k_err("wmi unified ready event not received\n");
+ ath10k_err(ar, "wmi unified ready event not received\n");
status = -ETIMEDOUT;
- goto err_htc_stop;
+ goto err_hif_stop;
}
status = ath10k_htt_setup(&ar->htt);
if (status) {
- ath10k_err("failed to setup htt: %d\n", status);
- goto err_htc_stop;
+ ath10k_err(ar, "failed to setup htt: %d\n", status);
+ goto err_hif_stop;
}
status = ath10k_debug_start(ar);
if (status)
- goto err_htc_stop;
+ goto err_hif_stop;
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1;
@@ -802,28 +819,8 @@ int ath10k_core_start(struct ath10k *ar)
INIT_LIST_HEAD(&ar->arvifs);
- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) {
- ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
- ar->hw_params.name,
- ar->target_version,
- ar->chip_id,
- ar->hw->wiphy->fw_version,
- ar->fw_api,
- ar->htt.target_version_major,
- ar->htt.target_version_minor);
- ath10k_info("debug %d debugfs %d tracing %d dfs %d\n",
- config_enabled(CONFIG_ATH10K_DEBUG),
- config_enabled(CONFIG_ATH10K_DEBUGFS),
- config_enabled(CONFIG_ATH10K_TRACING),
- config_enabled(CONFIG_ATH10K_DFS_CERTIFIED));
- }
-
- __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags);
-
return 0;
-err_htc_stop:
- ath10k_htc_stop(&ar->htc);
err_hif_stop:
ath10k_hif_stop(ar);
err_htt_rx_detach:
@@ -845,14 +842,14 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
if (ret) {
- ath10k_warn("could not suspend target (%d)\n", ret);
+ ath10k_warn(ar, "could not suspend target (%d)\n", ret);
return ret;
}
ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
if (ret == 0) {
- ath10k_warn("suspend timed out - target pause event never came\n");
+ ath10k_warn(ar, "suspend timed out - target pause event never came\n");
return -ETIMEDOUT;
}
@@ -868,7 +865,6 @@ void ath10k_core_stop(struct ath10k *ar)
ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
ath10k_debug_stop(ar);
- ath10k_htc_stop(&ar->htc);
ath10k_hif_stop(ar);
ath10k_htt_tx_free(&ar->htt);
ath10k_htt_rx_free(&ar->htt);
@@ -887,14 +883,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_hif_power_up(ar);
if (ret) {
- ath10k_err("could not start pci hif (%d)\n", ret);
+ ath10k_err(ar, "could not start pci hif (%d)\n", ret);
return ret;
}
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_err(ar, "could not get target info (%d)\n", ret);
ath10k_hif_power_down(ar);
return ret;
}
@@ -904,14 +900,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_init_hw_params(ar);
if (ret) {
- ath10k_err("could not get hw params (%d)\n", ret);
+ ath10k_err(ar, "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_err(ar, "could not fetch firmware files (%d)\n", ret);
ath10k_hif_power_down(ar);
return ret;
}
@@ -920,13 +916,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_core_start(ar);
if (ret) {
- ath10k_err("could not init core (%d)\n", ret);
+ ath10k_err(ar, "could not init core (%d)\n", ret);
ath10k_core_free_firmware_files(ar);
ath10k_hif_power_down(ar);
mutex_unlock(&ar->conf_mutex);
return ret;
}
+ ath10k_print_driver_info(ar);
ath10k_core_stop(ar);
mutex_unlock(&ar->conf_mutex);
@@ -939,7 +936,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
{
u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
ar->chip_id, hw_revision);
/* Check that we are not using hw1.0 (some of them have same pci id
@@ -947,7 +944,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
* due to missing hw1.0 workarounds. */
switch (hw_revision) {
case QCA988X_HW_1_0_CHIP_ID_REV:
- ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
+ ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n");
return -EOPNOTSUPP;
case QCA988X_HW_2_0_CHIP_ID_REV:
@@ -955,7 +952,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
return 0;
default:
- ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
+ ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n",
ar->chip_id);
return 0;
}
@@ -970,25 +967,33 @@ static void ath10k_core_register_work(struct work_struct *work)
status = ath10k_core_probe_fw(ar);
if (status) {
- ath10k_err("could not probe fw (%d)\n", status);
+ ath10k_err(ar, "could not probe fw (%d)\n", status);
goto err;
}
status = ath10k_mac_register(ar);
if (status) {
- ath10k_err("could not register to mac80211 (%d)\n", status);
+ ath10k_err(ar, "could not register to mac80211 (%d)\n", status);
goto err_release_fw;
}
status = ath10k_debug_create(ar);
if (status) {
- ath10k_err("unable to initialize debugfs\n");
+ ath10k_err(ar, "unable to initialize debugfs\n");
goto err_unregister_mac;
}
+ status = ath10k_spectral_create(ar);
+ if (status) {
+ ath10k_err(ar, "failed to initialize spectral\n");
+ goto err_debug_destroy;
+ }
+
set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);
return;
+err_debug_destroy:
+ ath10k_debug_destroy(ar);
err_unregister_mac:
ath10k_mac_unregister(ar);
err_release_fw:
@@ -1008,7 +1013,7 @@ int ath10k_core_register(struct ath10k *ar, u32 chip_id)
status = ath10k_core_check_chip_id(ar);
if (status) {
- ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
+ ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id);
return status;
}
@@ -1025,6 +1030,12 @@ void ath10k_core_unregister(struct ath10k *ar)
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
return;
+ /* Stop spectral before unregistering from mac80211 to remove the
+ * relayfs debugfs file cleanly. Otherwise the parent debugfs tree
+ * would be already be free'd recursively, leading to a double free.
+ */
+ ath10k_spectral_destroy(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. */
@@ -1036,12 +1047,12 @@ void ath10k_core_unregister(struct ath10k *ar)
}
EXPORT_SYMBOL(ath10k_core_unregister);
-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
+struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
const struct ath10k_hif_ops *hif_ops)
{
struct ath10k *ar;
- ar = ath10k_mac_create();
+ ar = ath10k_mac_create(priv_size);
if (!ar)
return NULL;
@@ -1051,7 +1062,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
ar->p2p = !!ath10k_p2p;
ar->dev = dev;
- ar->hif.priv = hif_priv;
ar->hif.ops = hif_ops;
init_completion(&ar->scan.started);
@@ -1062,7 +1072,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done);
- setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
+ INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
ar->workqueue = create_singlethread_workqueue("ath10k_wq");
if (!ar->workqueue)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 83a5fa9..4ef4760 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -22,6 +22,8 @@
#include <linux/if_ether.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/uuid.h>
+#include <linux/time.h>
#include "htt.h"
#include "htc.h"
@@ -31,6 +33,7 @@
#include "../ath.h"
#include "../regd.h"
#include "../dfs_pattern_detector.h"
+#include "spectral.h"
#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -237,6 +240,7 @@ struct ath10k_vif {
bool is_started;
bool is_up;
+ bool spectral_enabled;
u32 aid;
u8 bssid[ETH_ALEN];
@@ -276,11 +280,20 @@ struct ath10k_vif_iter {
struct ath10k_vif *arvif;
};
+/* used for crash-dump storage, protected by data-lock */
+struct ath10k_fw_crash_data {
+ bool crashed_since_read;
+
+ uuid_le uuid;
+ struct timespec timestamp;
+ __le32 registers[REG_DUMP_COUNT_QCA988X];
+};
+
struct ath10k_debug {
struct dentry *debugfs_phy;
struct ath10k_target_stats target_stats;
- u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
+ DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_BM_SIZE);
struct completion event_stats_compl;
@@ -293,6 +306,8 @@ struct ath10k_debug {
u8 htt_max_amsdu;
u8 htt_max_ampdu;
+
+ struct ath10k_fw_crash_data *fw_crash_data;
};
enum ath10k_state {
@@ -330,6 +345,11 @@ enum ath10k_fw_features {
/* Firmware does not support P2P */
ATH10K_FW_FEATURE_NO_P2P = 3,
+ /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit
+ * is required to be set as well.
+ */
+ ATH10K_FW_FEATURE_WMI_10_2 = 4,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
@@ -337,10 +357,32 @@ enum ath10k_fw_features {
enum ath10k_dev_flags {
/* Indicates that ath10k device is during CAC phase of DFS */
ATH10K_CAC_RUNNING,
- ATH10K_FLAG_FIRST_BOOT_DONE,
ATH10K_FLAG_CORE_REGISTERED,
};
+enum ath10k_scan_state {
+ ATH10K_SCAN_IDLE,
+ ATH10K_SCAN_STARTING,
+ ATH10K_SCAN_RUNNING,
+ ATH10K_SCAN_ABORTING,
+};
+
+static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state)
+{
+ switch (state) {
+ case ATH10K_SCAN_IDLE:
+ return "idle";
+ case ATH10K_SCAN_STARTING:
+ return "starting";
+ case ATH10K_SCAN_RUNNING:
+ return "running";
+ case ATH10K_SCAN_ABORTING:
+ return "aborting";
+ }
+
+ return "unknown";
+}
+
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
@@ -368,7 +410,6 @@ struct ath10k {
bool p2p;
struct {
- void *priv;
const struct ath10k_hif_ops *ops;
} hif;
@@ -410,10 +451,9 @@ struct ath10k {
struct completion started;
struct completion completed;
struct completion on_channel;
- struct timer_list timeout;
+ struct delayed_work timeout;
+ enum ath10k_scan_state state;
bool is_roc;
- bool in_progress;
- bool aborting;
int vdev_id;
int roc_freq;
} scan;
@@ -494,9 +534,21 @@ struct ath10k {
#ifdef CONFIG_ATH10K_DEBUGFS
struct ath10k_debug debug;
#endif
+
+ struct {
+ /* relay(fs) channel for spectral scan */
+ struct rchan *rfs_chan_spec_scan;
+
+ /* spectral_mode and spec_config are protected by conf_mutex */
+ enum ath10k_spectral_mode mode;
+ struct ath10k_spec_scan config;
+ } spectral;
+
+ /* must be last */
+ u8 drv_priv[0] __aligned(sizeof(void *));
};
-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
+struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
const struct ath10k_hif_ops *hif_ops);
void ath10k_core_destroy(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 3030158..f3f0a80 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -17,6 +17,9 @@
#include <linux/module.h>
#include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/vermagic.h>
+#include <linux/vmalloc.h>
#include "core.h"
#include "debug.h"
@@ -24,25 +27,86 @@
/* ms */
#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
-static int ath10k_printk(const char *level, const char *fmt, ...)
-{
- struct va_format vaf;
- va_list args;
- int rtn;
+#define ATH10K_FW_CRASH_DUMP_VERSION 1
- va_start(args, fmt);
+/**
+ * enum ath10k_fw_crash_dump_type - types of data in the dump file
+ * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+ */
+enum ath10k_fw_crash_dump_type {
+ ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
- vaf.fmt = fmt;
- vaf.va = &args;
+ ATH10K_FW_CRASH_DUMP_MAX,
+};
- rtn = printk("%sath10k: %pV", level, &vaf);
+struct ath10k_tlv_dump_data {
+ /* see ath10k_fw_crash_dump_type above */
+ __le32 type;
- va_end(args);
+ /* in bytes */
+ __le32 tlv_len;
- return rtn;
-}
+ /* pad to 32-bit boundaries as needed */
+ u8 tlv_data[];
+} __packed;
+
+struct ath10k_dump_file_data {
+ /* dump file information */
+
+ /* "ATH10K-FW-DUMP" */
+ char df_magic[16];
+
+ __le32 len;
+
+ /* file dump version */
+ __le32 version;
+
+ /* some info we can get from ath10k struct that might help */
+
+ u8 uuid[16];
+
+ __le32 chip_id;
+
+ /* 0 for now, in place for later hardware */
+ __le32 bus_type;
+
+ __le32 target_version;
+ __le32 fw_version_major;
+ __le32 fw_version_minor;
+ __le32 fw_version_release;
+ __le32 fw_version_build;
+ __le32 phy_capability;
+ __le32 hw_min_tx_power;
+ __le32 hw_max_tx_power;
+ __le32 ht_cap_info;
+ __le32 vht_cap_info;
+ __le32 num_rf_chains;
+
+ /* firmware version string */
+ char fw_ver[ETHTOOL_FWVERS_LEN];
+
+ /* Kernel related information */
+
+ /* time-of-day stamp */
+ __le64 tv_sec;
-int ath10k_info(const char *fmt, ...)
+ /* time-of-day stamp, nano-seconds */
+ __le64 tv_nsec;
+
+ /* LINUX_VERSION_CODE */
+ __le32 kernel_ver_code;
+
+ /* VERMAGIC_STRING */
+ char kernel_ver[64];
+
+ /* room for growth w/out changing binary format */
+ u8 unused[128];
+
+ /* struct ath10k_tlv_dump_data + more */
+ u8 data[0];
+} __packed;
+
+int ath10k_info(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@@ -52,7 +116,7 @@ int ath10k_info(const char *fmt, ...)
va_start(args, fmt);
vaf.va = &args;
- ret = ath10k_printk(KERN_INFO, "%pV", &vaf);
+ ret = dev_info(ar->dev, "%pV", &vaf);
trace_ath10k_log_info(&vaf);
va_end(args);
@@ -60,7 +124,25 @@ int ath10k_info(const char *fmt, ...)
}
EXPORT_SYMBOL(ath10k_info);
-int ath10k_err(const char *fmt, ...)
+void ath10k_print_driver_info(struct ath10k *ar)
+{
+ ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
+ ar->hw_params.name,
+ ar->target_version,
+ ar->chip_id,
+ ar->hw->wiphy->fw_version,
+ ar->fw_api,
+ ar->htt.target_version_major,
+ ar->htt.target_version_minor);
+ ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d\n",
+ config_enabled(CONFIG_ATH10K_DEBUG),
+ config_enabled(CONFIG_ATH10K_DEBUGFS),
+ config_enabled(CONFIG_ATH10K_TRACING),
+ config_enabled(CONFIG_ATH10K_DFS_CERTIFIED));
+}
+EXPORT_SYMBOL(ath10k_print_driver_info);
+
+int ath10k_err(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@@ -70,7 +152,7 @@ int ath10k_err(const char *fmt, ...)
va_start(args, fmt);
vaf.va = &args;
- ret = ath10k_printk(KERN_ERR, "%pV", &vaf);
+ ret = dev_err(ar->dev, "%pV", &vaf);
trace_ath10k_log_err(&vaf);
va_end(args);
@@ -78,25 +160,21 @@ int ath10k_err(const char *fmt, ...)
}
EXPORT_SYMBOL(ath10k_err);
-int ath10k_warn(const char *fmt, ...)
+int ath10k_warn(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret = 0;
va_start(args, fmt);
vaf.va = &args;
-
- if (net_ratelimit())
- ret = ath10k_printk(KERN_WARNING, "%pV", &vaf);
-
+ dev_warn_ratelimited(ar->dev, "%pV", &vaf);
trace_ath10k_log_warn(&vaf);
va_end(args);
- return ret;
+ return 0;
}
EXPORT_SYMBOL(ath10k_warn);
@@ -115,9 +193,10 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
{
struct ath10k *ar = file->private_data;
char *buf;
- unsigned int len = 0, buf_len = 1500;
- const char *status;
+ unsigned int len = 0, buf_len = 4096;
+ const char *name;
ssize_t ret_cnt;
+ bool enabled;
int i;
buf = kzalloc(buf_len, GFP_KERNEL);
@@ -129,15 +208,22 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
if (len > buf_len)
len = buf_len;
- for (i = 0; i < WMI_SERVICE_LAST; i++) {
- if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i))
- status = "enabled";
- else
- status = "disabled";
+ for (i = 0; i < WMI_MAX_SERVICE; i++) {
+ enabled = test_bit(i, ar->debug.wmi_service_bitmap);
+ name = wmi_service_name(i);
+
+ if (!name) {
+ if (enabled)
+ len += scnprintf(buf + len, buf_len - len,
+ "%-40s %s (bit %d)\n",
+ "unknown", "enabled", i);
+
+ continue;
+ }
len += scnprintf(buf + len, buf_len - len,
- "0x%02x - %20s - %s\n",
- i, wmi_service_name(i), status);
+ "%-40s %s\n",
+ name, enabled ? "enabled" : "-");
}
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
@@ -309,7 +395,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
if (ret) {
- ath10k_warn("could not request stats (%d)\n", ret);
+ ath10k_warn(ar, "could not request stats (%d)\n", ret);
goto exit;
}
@@ -527,11 +613,14 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
}
if (!strcmp(buf, "soft")) {
- ath10k_info("simulating soft firmware crash\n");
+ ath10k_info(ar, "simulating soft firmware crash\n");
ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
} else if (!strcmp(buf, "hard")) {
- ath10k_info("simulating hard firmware crash\n");
- ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1,
+ ath10k_info(ar, "simulating hard firmware crash\n");
+ /* 0x7fff is vdev id, and it is always out of range for all
+ * firmware variants in order to force a firmware crash.
+ */
+ ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,
ar->wmi.vdev_param->rts_threshold, 0);
} else {
ret = -EINVAL;
@@ -539,7 +628,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
}
if (ret) {
- ath10k_warn("failed to simulate firmware crash: %d\n", ret);
+ ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);
goto exit;
}
@@ -577,6 +666,138 @@ static const struct file_operations fops_chip_id = {
.llseek = default_llseek,
};
+struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+{
+ struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ crash_data->crashed_since_read = true;
+ uuid_le_gen(&crash_data->uuid);
+ getnstimeofday(&crash_data->timestamp);
+
+ return crash_data;
+}
+EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
+
+static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+{
+ struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+ struct ath10k_dump_file_data *dump_data;
+ struct ath10k_tlv_dump_data *dump_tlv;
+ int hdr_len = sizeof(*dump_data);
+ unsigned int len, sofar = 0;
+ unsigned char *buf;
+
+ len = hdr_len;
+ len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+
+ sofar += hdr_len;
+
+ /* This is going to get big when we start dumping FW RAM and such,
+ * so go ahead and use vmalloc.
+ */
+ buf = vzalloc(len);
+ if (!buf)
+ return NULL;
+
+ spin_lock_bh(&ar->data_lock);
+
+ if (!crash_data->crashed_since_read) {
+ spin_unlock_bh(&ar->data_lock);
+ vfree(buf);
+ return NULL;
+ }
+
+ dump_data = (struct ath10k_dump_file_data *)(buf);
+ strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP",
+ sizeof(dump_data->df_magic));
+ dump_data->len = cpu_to_le32(len);
+
+ dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION);
+
+ memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid));
+ dump_data->chip_id = cpu_to_le32(ar->chip_id);
+ dump_data->bus_type = cpu_to_le32(0);
+ dump_data->target_version = cpu_to_le32(ar->target_version);
+ dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major);
+ dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor);
+ dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release);
+ dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build);
+ dump_data->phy_capability = cpu_to_le32(ar->phy_capability);
+ dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power);
+ dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power);
+ dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
+ dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
+ dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
+
+ strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
+ sizeof(dump_data->fw_ver));
+
+ dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE);
+ strlcpy(dump_data->kernel_ver, VERMAGIC_STRING,
+ sizeof(dump_data->kernel_ver));
+
+ dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
+ dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec);
+
+ /* Gather crash-dump */
+ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS);
+ dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers));
+ memcpy(dump_tlv->tlv_data, &crash_data->registers,
+ sizeof(crash_data->registers));
+ sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+
+ ar->debug.fw_crash_data->crashed_since_read = false;
+
+ spin_unlock_bh(&ar->data_lock);
+
+ return dump_data;
+}
+
+static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file)
+{
+ struct ath10k *ar = inode->i_private;
+ struct ath10k_dump_file_data *dump;
+
+ dump = ath10k_build_dump_file(ar);
+ if (!dump)
+ return -ENODATA;
+
+ file->private_data = dump;
+
+ return 0;
+}
+
+static ssize_t ath10k_fw_crash_dump_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k_dump_file_data *dump_file = file->private_data;
+
+ return simple_read_from_buffer(user_buf, count, ppos,
+ dump_file,
+ le32_to_cpu(dump_file->len));
+}
+
+static int ath10k_fw_crash_dump_release(struct inode *inode,
+ struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
+static const struct file_operations fops_fw_crash_dump = {
+ .open = ath10k_fw_crash_dump_open,
+ .read = ath10k_fw_crash_dump_read,
+ .release = ath10k_fw_crash_dump_release,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static int ath10k_debug_htt_stats_req(struct ath10k *ar)
{
u64 cookie;
@@ -596,7 +817,7 @@ static int ath10k_debug_htt_stats_req(struct ath10k *ar)
ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
cookie);
if (ret) {
- ath10k_warn("failed to send htt stats request: %d\n", ret);
+ ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
return ret;
}
@@ -770,7 +991,7 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file,
if (ar->state == ATH10K_STATE_ON) {
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
if (ret) {
- ath10k_warn("dbglog cfg failed from debugfs: %d\n",
+ ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
ret);
goto exit;
}
@@ -801,13 +1022,14 @@ int ath10k_debug_start(struct ath10k *ar)
ret = ath10k_debug_htt_stats_req(ar);
if (ret)
/* continue normally anyway, this isn't serious */
- ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
+ ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",
+ ret);
if (ar->debug.fw_dbglog_mask) {
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
if (ret)
/* not serious */
- ath10k_warn("failed to enable dbglog during start: %d",
+ ath10k_warn(ar, "failed to enable dbglog during start: %d",
ret);
}
@@ -910,11 +1132,20 @@ static const struct file_operations fops_dfs_stats = {
int ath10k_debug_create(struct ath10k *ar)
{
+ int ret;
+
+ ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
+ if (!ar->debug.fw_crash_data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
ar->hw->wiphy->debugfsdir);
-
- if (!ar->debug.debugfs_phy)
- return -ENOMEM;
+ if (!ar->debug.debugfs_phy) {
+ ret = -ENOMEM;
+ goto err_free_fw_crash_data;
+ }
INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
ath10k_debug_htt_stats_dwork);
@@ -930,6 +1161,9 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_simulate_fw_crash);
+ debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
+ ar, &fops_fw_crash_dump);
+
debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_chip_id);
@@ -958,17 +1192,25 @@ int ath10k_debug_create(struct ath10k *ar)
}
return 0;
+
+err_free_fw_crash_data:
+ vfree(ar->debug.fw_crash_data);
+
+err:
+ return ret;
}
void ath10k_debug_destroy(struct ath10k *ar)
{
+ vfree(ar->debug.fw_crash_data);
cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
}
#endif /* CONFIG_ATH10K_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
-void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
+void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
+ const char *fmt, ...)
{
struct va_format vaf;
va_list args;
@@ -979,7 +1221,7 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
vaf.va = &args;
if (ath10k_debug_mask & mask)
- ath10k_printk(KERN_DEBUG, "%pV", &vaf);
+ dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
trace_ath10k_log_dbg(mask, &vaf);
@@ -987,13 +1229,14 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
}
EXPORT_SYMBOL(ath10k_dbg);
-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+void ath10k_dbg_dump(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
const char *msg, const char *prefix,
const void *buf, size_t len)
{
if (ath10k_debug_mask & mask) {
if (msg)
- ath10k_dbg(mask, "%s\n", msg);
+ ath10k_dbg(ar, mask, "%s\n", msg);
print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
}
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index a582499..5674653 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -39,9 +39,10 @@ enum ath10k_debug_mask {
extern unsigned int ath10k_debug_mask;
-__printf(1, 2) int ath10k_info(const char *fmt, ...);
-__printf(1, 2) int ath10k_err(const char *fmt, ...);
-__printf(1, 2) int ath10k_warn(const char *fmt, ...);
+__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...);
+void ath10k_print_driver_info(struct ath10k *ar);
#ifdef CONFIG_ATH10K_DEBUGFS
int ath10k_debug_start(struct ath10k *ar);
@@ -53,6 +54,10 @@ void ath10k_debug_read_service_map(struct ath10k *ar,
size_t map_size);
void ath10k_debug_read_target_stats(struct ath10k *ar,
struct wmi_stats_event *ev);
+struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
+
+void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
@@ -86,25 +91,40 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
{
}
+static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
+ int len)
+{
+}
+
+static inline struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+{
+ return NULL;
+}
+
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
#endif /* CONFIG_ATH10K_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
-__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
+__printf(3, 4) void ath10k_dbg(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
const char *fmt, ...);
-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+void ath10k_dbg_dump(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
const char *msg, const char *prefix,
const void *buf, size_t len);
#else /* CONFIG_ATH10K_DEBUG */
-static inline int ath10k_dbg(enum ath10k_debug_mask dbg_mask,
+static inline int ath10k_dbg(struct ath10k *ar,
+ enum ath10k_debug_mask dbg_mask,
const char *fmt, ...)
{
return 0;
}
-static inline void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+static inline void ath10k_dbg_dump(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
const char *msg, const char *prefix,
const void *buf, size_t len)
{
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 5fdc40d..fd9a251 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -46,7 +46,7 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)
skb = dev_alloc_skb(ATH10K_HTC_CONTROL_BUFFER_SIZE);
if (!skb) {
- ath10k_warn("Unable to allocate ctrl skb\n");
+ ath10k_warn(ar, "Unable to allocate ctrl skb\n");
return NULL;
}
@@ -56,7 +56,7 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)
skb_cb = ATH10K_SKB_CB(skb);
memset(skb_cb, 0, sizeof(*skb_cb));
- ath10k_dbg(ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
return skb;
}
@@ -72,13 +72,15 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc,
static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
+ struct ath10k *ar = ep->htc->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
ep->eid, skb);
ath10k_htc_restore_tx_skb(ep->htc, skb);
if (!ep->ep_ops.ep_tx_complete) {
- ath10k_warn("no tx handler for eid %d\n", ep->eid);
+ ath10k_warn(ar, "no tx handler for eid %d\n", ep->eid);
dev_kfree_skb_any(skb);
return;
}
@@ -89,12 +91,14 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
/* assumes tx_lock is held */
static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep)
{
+ struct ath10k *ar = ep->htc->ar;
+
if (!ep->tx_credit_flow_enabled)
return false;
if (ep->tx_credits >= ep->tx_credits_per_max_message)
return false;
- ath10k_dbg(ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
ep->eid);
return true;
}
@@ -123,6 +127,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
enum ath10k_htc_ep_id eid,
struct sk_buff *skb)
{
+ struct ath10k *ar = htc->ar;
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
struct ath10k_hif_sg_item sg_item;
@@ -134,18 +139,10 @@ int ath10k_htc_send(struct ath10k_htc *htc,
return -ECOMM;
if (eid >= ATH10K_HTC_EP_COUNT) {
- ath10k_warn("Invalid endpoint id: %d\n", eid);
+ ath10k_warn(ar, "Invalid endpoint id: %d\n", eid);
return -ENOENT;
}
- /* FIXME: This looks ugly, can we fix it? */
- spin_lock_bh(&htc->tx_lock);
- if (htc->stopped) {
- spin_unlock_bh(&htc->tx_lock);
- return -ESHUTDOWN;
- }
- spin_unlock_bh(&htc->tx_lock);
-
skb_push(skb, sizeof(struct ath10k_htc_hdr));
if (ep->tx_credit_flow_enabled) {
@@ -157,7 +154,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
goto err_pull;
}
ep->tx_credits -= credits;
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"htc ep %d consumed %d credits (total %d)\n",
eid, credits, ep->tx_credits);
spin_unlock_bh(&htc->tx_lock);
@@ -188,7 +185,7 @@ err_credits:
if (ep->tx_credit_flow_enabled) {
spin_lock_bh(&htc->tx_lock);
ep->tx_credits += credits;
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"htc ep %d reverted %d credits back (total %d)\n",
eid, credits, ep->tx_credits);
spin_unlock_bh(&htc->tx_lock);
@@ -227,11 +224,12 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
int len,
enum ath10k_htc_ep_id eid)
{
+ struct ath10k *ar = htc->ar;
struct ath10k_htc_ep *ep;
int i, n_reports;
if (len % sizeof(*report))
- ath10k_warn("Uneven credit report len %d", len);
+ ath10k_warn(ar, "Uneven credit report len %d", len);
n_reports = len / sizeof(*report);
@@ -243,7 +241,7 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
ep = &htc->endpoint[report->eid];
ep->tx_credits += report->credits;
- ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
report->eid, report->credits, ep->tx_credits);
if (ep->ep_ops.ep_tx_credits) {
@@ -260,6 +258,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
int length,
enum ath10k_htc_ep_id src_eid)
{
+ struct ath10k *ar = htc->ar;
int status = 0;
struct ath10k_htc_record *record;
u8 *orig_buffer;
@@ -279,7 +278,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
if (record->hdr.len > length) {
/* no room left in buffer for record */
- ath10k_warn("Invalid record length: %d\n",
+ ath10k_warn(ar, "Invalid record length: %d\n",
record->hdr.len);
status = -EINVAL;
break;
@@ -289,7 +288,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
case ATH10K_HTC_RECORD_CREDITS:
len = sizeof(struct ath10k_htc_credit_report);
if (record->hdr.len < len) {
- ath10k_warn("Credit report too long\n");
+ ath10k_warn(ar, "Credit report too long\n");
status = -EINVAL;
break;
}
@@ -299,7 +298,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
src_eid);
break;
default:
- ath10k_warn("Unhandled record: id:%d length:%d\n",
+ ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
record->hdr.id, record->hdr.len);
break;
}
@@ -313,7 +312,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
}
if (status)
- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc rx bad trailer", "",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc rx bad trailer", "",
orig_buffer, orig_length);
return status;
@@ -339,8 +338,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
eid = hdr->eid;
if (eid >= ATH10K_HTC_EP_COUNT) {
- ath10k_warn("HTC Rx: invalid eid %d\n", eid);
- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "",
+ ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid);
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "",
hdr, sizeof(*hdr));
status = -EINVAL;
goto out;
@@ -360,19 +359,19 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
payload_len = __le16_to_cpu(hdr->len);
if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) {
- ath10k_warn("HTC rx frame too long, len: %zu\n",
+ ath10k_warn(ar, "HTC rx frame too long, len: %zu\n",
payload_len + sizeof(*hdr));
- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "",
hdr, sizeof(*hdr));
status = -EINVAL;
goto out;
}
if (skb->len < payload_len) {
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"HTC Rx: insufficient length, got %d, expected %d\n",
skb->len, payload_len);
- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len",
"", hdr, sizeof(*hdr));
status = -EINVAL;
goto out;
@@ -388,7 +387,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
if ((trailer_len < min_len) ||
(trailer_len > payload_len)) {
- ath10k_warn("Invalid trailer length: %d\n",
+ ath10k_warn(ar, "Invalid trailer length: %d\n",
trailer_len);
status = -EPROTO;
goto out;
@@ -421,7 +420,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
* this is a fatal error, target should not be
* sending unsolicited messages on the ep 0
*/
- ath10k_warn("HTC rx ctrl still processing\n");
+ ath10k_warn(ar, "HTC rx ctrl still processing\n");
status = -EINVAL;
complete(&htc->ctl_resp);
goto out;
@@ -442,7 +441,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
goto out;
}
- ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
eid, skb);
ep->ep_ops.ep_rx_complete(ar, skb);
@@ -459,7 +458,7 @@ static void ath10k_htc_control_rx_complete(struct ath10k *ar,
{
/* This is unexpected. FW is not supposed to send regular rx on this
* endpoint. */
- ath10k_warn("unexpected htc rx\n");
+ ath10k_warn(ar, "unexpected htc rx\n");
kfree_skb(skb);
}
@@ -546,6 +545,7 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc,
int ath10k_htc_wait_target(struct ath10k_htc *htc)
{
+ struct ath10k *ar = htc->ar;
int i, status = 0;
struct ath10k_htc_svc_conn_req conn_req;
struct ath10k_htc_svc_conn_resp conn_resp;
@@ -563,7 +563,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
* iomap writes unmasking PCI CE irqs aren't propagated
* properly in KVM PCI-passthrough sometimes.
*/
- ath10k_warn("failed to receive control response completion, polling..\n");
+ ath10k_warn(ar, "failed to receive control response completion, polling..\n");
for (i = 0; i < CE_COUNT; i++)
ath10k_hif_send_complete_check(htc->ar, i, 1);
@@ -576,12 +576,12 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
}
if (status < 0) {
- ath10k_err("ctl_resp never came in (%d)\n", status);
+ ath10k_err(ar, "ctl_resp never came in (%d)\n", status);
return status;
}
if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) {
- ath10k_err("Invalid HTC ready msg len:%d\n",
+ ath10k_err(ar, "Invalid HTC ready msg len:%d\n",
htc->control_resp_len);
return -ECOMM;
}
@@ -592,21 +592,21 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
credit_size = __le16_to_cpu(msg->ready.credit_size);
if (message_id != ATH10K_HTC_MSG_READY_ID) {
- ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id);
+ ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id);
return -ECOMM;
}
htc->total_transmit_credits = credit_count;
htc->target_credit_size = credit_size;
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"Target ready! transmit resources: %d size:%d\n",
htc->total_transmit_credits,
htc->target_credit_size);
if ((htc->total_transmit_credits == 0) ||
(htc->target_credit_size == 0)) {
- ath10k_err("Invalid credit size received\n");
+ ath10k_err(ar, "Invalid credit size received\n");
return -ECOMM;
}
@@ -623,7 +623,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
/* connect fake service */
status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
if (status) {
- ath10k_err("could not connect to htc service (%d)\n", status);
+ ath10k_err(ar, "could not connect to htc service (%d)\n",
+ status);
return status;
}
@@ -634,6 +635,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_req *conn_req,
struct ath10k_htc_svc_conn_resp *conn_resp)
{
+ struct ath10k *ar = htc->ar;
struct ath10k_htc_msg *msg;
struct ath10k_htc_conn_svc *req_msg;
struct ath10k_htc_conn_svc_response resp_msg_dummy;
@@ -659,13 +661,13 @@ 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_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot 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) {
- ath10k_err("Failed to allocate HTC packet\n");
+ ath10k_err(ar, "Failed to allocate HTC packet\n");
return -ENOMEM;
}
@@ -703,7 +705,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
if (status <= 0) {
if (status == 0)
status = -ETIMEDOUT;
- ath10k_err("Service connect timeout: %d\n", status);
+ ath10k_err(ar, "Service connect timeout: %d\n", status);
return status;
}
@@ -716,11 +718,11 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
if ((message_id != ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID) ||
(htc->control_resp_len < sizeof(msg->hdr) +
sizeof(msg->connect_service_response))) {
- ath10k_err("Invalid resp message ID 0x%x", message_id);
+ ath10k_err(ar, "Invalid resp message ID 0x%x", message_id);
return -EPROTO;
}
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"HTC Service %s connect response: status: 0x%x, assigned ep: 0x%x\n",
htc_service_name(service_id),
resp_msg->status, resp_msg->eid);
@@ -729,7 +731,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
/* check response status */
if (resp_msg->status != ATH10K_HTC_CONN_SVC_STATUS_SUCCESS) {
- ath10k_err("HTC Service %s connect request failed: 0x%x)\n",
+ ath10k_err(ar, "HTC Service %s connect request failed: 0x%x)\n",
htc_service_name(service_id),
resp_msg->status);
return -EPROTO;
@@ -780,18 +782,18 @@ setup:
if (status)
return status;
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
htc_service_name(ep->service_id), ep->ul_pipe_id,
ep->dl_pipe_id, ep->eid);
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot htc ep %d ul polled %d dl polled %d\n",
ep->eid, ep->ul_is_polled, ep->dl_is_polled);
if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
ep->tx_credit_flow_enabled = false;
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot htc service '%s' eid %d TX flow control disabled\n",
htc_service_name(ep->service_id), assigned_eid);
}
@@ -799,13 +801,13 @@ setup:
return status;
}
-struct sk_buff *ath10k_htc_alloc_skb(int size)
+struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size)
{
struct sk_buff *skb;
skb = dev_alloc_skb(size + sizeof(struct ath10k_htc_hdr));
if (!skb) {
- ath10k_warn("could not allocate HTC tx skb\n");
+ ath10k_warn(ar, "could not allocate HTC tx skb\n");
return NULL;
}
@@ -813,13 +815,14 @@ struct sk_buff *ath10k_htc_alloc_skb(int size)
/* FW/HTC requires 4-byte aligned streams */
if (!IS_ALIGNED((unsigned long)skb->data, 4))
- ath10k_warn("Unaligned HTC tx skb\n");
+ ath10k_warn(ar, "Unaligned HTC tx skb\n");
return skb;
}
int ath10k_htc_start(struct ath10k_htc *htc)
{
+ struct ath10k *ar = htc->ar;
struct sk_buff *skb;
int status = 0;
struct ath10k_htc_msg *msg;
@@ -835,7 +838,7 @@ int ath10k_htc_start(struct ath10k_htc *htc)
msg->hdr.message_id =
__cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID);
- ath10k_dbg(ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
if (status) {
@@ -846,13 +849,6 @@ int ath10k_htc_start(struct ath10k_htc *htc)
return 0;
}
-void ath10k_htc_stop(struct ath10k_htc *htc)
-{
- spin_lock_bh(&htc->tx_lock);
- htc->stopped = true;
- spin_unlock_bh(&htc->tx_lock);
-}
-
/* registered target arrival callback from the HIF layer */
int ath10k_htc_init(struct ath10k *ar)
{
@@ -862,7 +858,6 @@ int ath10k_htc_init(struct ath10k *ar)
spin_lock_init(&htc->tx_lock);
- htc->stopped = false;
ath10k_htc_reset_endpoint_states(htc);
/* setup HIF layer callbacks */
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index 4716d33..bf532f6 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -332,7 +332,7 @@ struct ath10k_htc {
struct ath10k *ar;
struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
- /* protects endpoint and stopped fields */
+ /* protects endpoints */
spinlock_t tx_lock;
struct ath10k_htc_ops htc_ops;
@@ -345,8 +345,6 @@ struct ath10k_htc {
int total_transmit_credits;
struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
int target_credit_size;
-
- bool stopped;
};
int ath10k_htc_init(struct ath10k *ar);
@@ -357,7 +355,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_resp *conn_resp);
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);
-struct sk_buff *ath10k_htc_alloc_skb(int size);
+struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
#endif
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 19c12cc..87daae1 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -74,12 +74,14 @@ int ath10k_htt_init(struct ath10k *ar)
static int ath10k_htt_verify_version(struct ath10k_htt *htt)
{
- ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n",
+ struct ath10k *ar = htt->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt target version %d.%d\n",
htt->target_version_major, htt->target_version_minor);
if (htt->target_version_major != 2 &&
htt->target_version_major != 3) {
- ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
+ ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n",
htt->target_version_major);
return -ENOTSUPP;
}
@@ -89,6 +91,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt)
int ath10k_htt_setup(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
int status;
init_completion(&htt->target_version_received);
@@ -100,7 +103,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt)
status = wait_for_completion_timeout(&htt->target_version_received,
HTT_TARGET_VERSION_TIMEOUT_HZ);
if (status <= 0) {
- ath10k_warn("htt version request timed out\n");
+ ath10k_warn(ar, "htt version request timed out\n");
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 80cdac1..30927b1 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -271,13 +271,14 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
int idx;
struct sk_buff *msdu;
lockdep_assert_held(&htt->rx_ring.lock);
if (htt->rx_ring.fill_cnt == 0) {
- ath10k_warn("tried to pop sk_buff from an empty rx ring\n");
+ ath10k_warn(ar, "tried to pop sk_buff from an empty rx ring\n");
return NULL;
}
@@ -311,6 +312,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
struct sk_buff **tail_msdu,
u32 *attention)
{
+ struct ath10k *ar = htt->ar;
int msdu_len, msdu_chaining = 0;
struct sk_buff *msdu;
struct htt_rx_desc *rx_desc;
@@ -318,7 +320,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
lockdep_assert_held(&htt->rx_ring.lock);
if (htt->rx_confused) {
- ath10k_warn("htt is confused. refusing rx\n");
+ ath10k_warn(ar, "htt is confused. refusing rx\n");
return -1;
}
@@ -331,7 +333,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu->len + skb_tailroom(msdu),
DMA_FROM_DEVICE);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
msdu->data, msdu->len + skb_tailroom(msdu));
rx_desc = (struct htt_rx_desc *)msdu->data;
@@ -354,7 +356,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
ath10k_htt_rx_free_msdu_chain(*head_msdu);
*head_msdu = NULL;
msdu = NULL;
- ath10k_err("htt rx stopped. cannot recover\n");
+ ath10k_err(ar, "htt rx stopped. cannot recover\n");
htt->rx_confused = true;
break;
}
@@ -429,7 +431,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
next->len + skb_tailroom(next),
DMA_FROM_DEVICE);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL,
"htt rx chained: ", next->data,
next->len + skb_tailroom(next));
@@ -483,13 +485,14 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr)
int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
dma_addr_t paddr;
void *vaddr;
struct timer_list *timer = &htt->rx_ring.refill_retry_timer;
htt->rx_ring.size = ath10k_htt_rx_ring_size(htt);
if (!is_power_of_2(htt->rx_ring.size)) {
- ath10k_warn("htt rx ring size is not power of 2\n");
+ ath10k_warn(ar, "htt rx ring size is not power of 2\n");
return -EINVAL;
}
@@ -550,7 +553,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
(unsigned long)htt);
- ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
htt->rx_ring.size, htt->rx_ring.fill_level);
return 0;
@@ -572,7 +575,8 @@ err_netbuf:
return -ENOMEM;
}
-static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type)
+static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar,
+ enum htt_rx_mpdu_encrypt_type type)
{
switch (type) {
case HTT_RX_MPDU_ENCRYPT_WEP40:
@@ -588,11 +592,12 @@ static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type)
return 0;
}
- ath10k_warn("unknown encryption type %d\n", type);
+ ath10k_warn(ar, "unknown encryption type %d\n", type);
return 0;
}
-static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type)
+static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
+ enum htt_rx_mpdu_encrypt_type type)
{
switch (type) {
case HTT_RX_MPDU_ENCRYPT_NONE:
@@ -608,7 +613,7 @@ static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type)
return 8;
}
- ath10k_warn("unknown encryption type %d\n", type);
+ ath10k_warn(ar, "unknown encryption type %d\n", type);
return 0;
}
@@ -819,19 +824,55 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
return true;
}
+static const char * const tid_to_ac[] = {
+ "BE",
+ "BK",
+ "BK",
+ "BE",
+ "VI",
+ "VI",
+ "VO",
+ "VO",
+};
+
+static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
+{
+ u8 *qc;
+ int tid;
+
+ if (!ieee80211_is_data_qos(hdr->frame_control))
+ return "";
+
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+ if (tid < 8)
+ snprintf(out, size, "tid %d (%s)", tid, tid_to_ac[tid]);
+ else
+ snprintf(out, size, "tid %d", tid);
+
+ return out;
+}
+
static void ath10k_process_rx(struct ath10k *ar,
struct ieee80211_rx_status *rx_status,
struct sk_buff *skb)
{
struct ieee80211_rx_status *status;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ char tid[32];
status = IEEE80211_SKB_RXCB(skb);
*status = *rx_status;
- ath10k_dbg(ATH10K_DBG_DATA,
- "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n",
+ ath10k_dbg(ar, ATH10K_DBG_DATA,
+ "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
skb,
skb->len,
+ ieee80211_get_SA(hdr),
+ ath10k_get_tid(hdr, tid, sizeof(tid)),
+ is_multicast_ether_addr(ieee80211_get_DA(hdr)) ?
+ "mcast" : "ucast",
+ (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4,
status->flag == 0 ? "legacy" : "",
status->flag & RX_FLAG_HT ? "ht" : "",
status->flag & RX_FLAG_VHT ? "vht" : "",
@@ -843,8 +884,9 @@ static void ath10k_process_rx(struct ath10k *ar,
status->freq,
status->band, status->flag,
!!(status->flag & RX_FLAG_FAILED_FCS_CRC),
- !!(status->flag & RX_FLAG_MMIC_ERROR));
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
+ !!(status->flag & RX_FLAG_MMIC_ERROR),
+ !!(status->flag & RX_FLAG_AMSDU_MORE));
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
skb->data, skb->len);
ieee80211_rx(ar->hw, skb);
@@ -860,13 +902,14 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
struct ieee80211_rx_status *rx_status,
struct sk_buff *skb_in)
{
+ struct ath10k *ar = htt->ar;
struct htt_rx_desc *rxd;
struct sk_buff *skb = skb_in;
struct sk_buff *first;
enum rx_msdu_decap_format fmt;
enum htt_rx_mpdu_encrypt_type enctype;
struct ieee80211_hdr *hdr;
- u8 hdr_buf[64], addr[ETH_ALEN], *qos;
+ u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos;
unsigned int hdr_len;
rxd = (void *)skb->data - sizeof(*rxd);
@@ -893,8 +936,8 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
/* First frame in an A-MSDU chain has more decapped data. */
if (skb == first) {
len = round_up(ieee80211_hdrlen(hdr->frame_control), 4);
- len += round_up(ath10k_htt_rx_crypto_param_len(enctype),
- 4);
+ len += round_up(ath10k_htt_rx_crypto_param_len(ar,
+ enctype), 4);
decap_hdr += len;
}
@@ -904,10 +947,11 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
skb_trim(skb, skb->len - FCS_LEN);
break;
case RX_MSDU_DECAP_NATIVE_WIFI:
- /* pull decapped header and copy DA */
+ /* pull decapped header and copy SA & DA */
hdr = (struct ieee80211_hdr *)skb->data;
hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
- memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN);
+ memcpy(da, ieee80211_get_DA(hdr), ETH_ALEN);
+ memcpy(sa, ieee80211_get_SA(hdr), ETH_ALEN);
skb_pull(skb, hdr_len);
/* push original 802.11 header */
@@ -921,8 +965,11 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
qos = ieee80211_get_qos_ctl(hdr);
qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
- /* original 802.11 header has a different DA */
- memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN);
+ /* original 802.11 header has a different DA and in
+ * case of 4addr it may also have different SA
+ */
+ memcpy(ieee80211_get_DA(hdr), da, ETH_ALEN);
+ memcpy(ieee80211_get_SA(hdr), sa, ETH_ALEN);
break;
case RX_MSDU_DECAP_ETHERNET2_DIX:
/* strip ethernet header and insert decapped 802.11
@@ -965,6 +1012,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
struct ieee80211_rx_status *rx_status,
struct sk_buff *skb)
{
+ struct ath10k *ar = htt->ar;
struct htt_rx_desc *rxd;
struct ieee80211_hdr *hdr;
enum rx_msdu_decap_format fmt;
@@ -974,7 +1022,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
/* This shouldn't happen. If it does than it may be a FW bug. */
if (skb->next) {
- ath10k_warn("htt rx received chained non A-MSDU frame\n");
+ ath10k_warn(ar, "htt rx received chained non A-MSDU frame\n");
ath10k_htt_rx_free_msdu_chain(skb->next);
skb->next = NULL;
}
@@ -1011,7 +1059,8 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
rfc1042 = hdr;
rfc1042 += roundup(hdr_len, 4);
- rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4);
+ rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(ar,
+ enctype), 4);
skb_pull(skb, sizeof(struct ethhdr));
memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)),
@@ -1120,27 +1169,29 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
bool channel_set,
u32 attention)
{
+ struct ath10k *ar = htt->ar;
+
if (head->len == 0) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx dropping due to zero-len\n");
return false;
}
if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx dropping due to decrypt-err\n");
return false;
}
if (!channel_set) {
- ath10k_warn("no channel configured; ignoring frame!\n");
+ ath10k_warn(ar, "no channel configured; ignoring frame!\n");
return false;
}
/* Skip mgmt frames while we handle this in WMI */
if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
attention & RX_ATTENTION_FLAGS_MGMT_TYPE) {
- ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
return false;
}
@@ -1148,14 +1199,14 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
!htt->ar->monitor_started) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx ignoring frame w/ status %d\n",
status);
return false;
}
if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx CAC running\n");
return false;
}
@@ -1166,6 +1217,7 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
struct htt_rx_indication *rx)
{
+ struct ath10k *ar = htt->ar;
struct ieee80211_rx_status *rx_status = &htt->rx_status;
struct htt_rx_indication_mpdu_range *mpdu_ranges;
struct htt_rx_desc *rxd;
@@ -1211,7 +1263,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
rx_status);
}
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
rx, sizeof(*rx) +
(sizeof(struct htt_rx_indication_mpdu_range) *
num_mpdu_ranges));
@@ -1233,7 +1285,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
&attention);
if (ret < 0) {
- ath10k_warn("failed to pop amsdu from htt rx ring %d\n",
+ ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n",
ret);
ath10k_htt_rx_free_msdu_chain(msdu_head);
continue;
@@ -1282,6 +1334,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
struct htt_rx_fragment_indication *frag)
{
+ struct ath10k *ar = htt->ar;
struct sk_buff *msdu_head, *msdu_tail;
enum htt_rx_mpdu_encrypt_type enctype;
struct htt_rx_desc *rxd;
@@ -1308,10 +1361,10 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
&attention);
spin_unlock_bh(&htt->rx_ring.lock);
- ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
+ ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
if (ret) {
- ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n",
+ ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n",
ret);
ath10k_htt_rx_free_msdu_chain(msdu_head);
return;
@@ -1328,7 +1381,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
RX_MSDU_START_INFO1_DECAP_FORMAT);
if (fmt != RX_MSDU_DECAP_RAW) {
- ath10k_warn("we dont support non-raw fragmented rx yet\n");
+ ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n");
dev_kfree_skb_any(msdu_head);
goto end;
}
@@ -1340,17 +1393,17 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
if (tkip_mic_err)
- ath10k_warn("tkip mic error\n");
+ ath10k_warn(ar, "tkip mic error\n");
if (decrypt_err) {
- ath10k_warn("decryption err in fragmented rx\n");
+ ath10k_warn(ar, "decryption err in fragmented rx\n");
dev_kfree_skb_any(msdu_head);
goto end;
}
if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {
hdrlen = ieee80211_hdrlen(hdr->frame_control);
- paramlen = ath10k_htt_rx_crypto_param_len(enctype);
+ paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype);
/* It is more efficient to move the header than the payload */
memmove((void *)msdu_head->data + paramlen,
@@ -1364,7 +1417,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
trim = 4;
/* remove crypto trailer */
- trim += ath10k_htt_rx_crypto_tail_len(enctype);
+ trim += ath10k_htt_rx_crypto_tail_len(ar, enctype);
/* last fragment of TKIP frags has MIC */
if (!ieee80211_has_morefrags(hdr->frame_control) &&
@@ -1372,20 +1425,20 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
trim += 8;
if (trim > msdu_head->len) {
- ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n");
+ ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n");
dev_kfree_skb_any(msdu_head);
goto end;
}
skb_trim(msdu_head, msdu_head->len - trim);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
msdu_head->data, msdu_head->len);
ath10k_process_rx(htt->ar, rx_status, msdu_head);
end:
if (fw_desc_len > 0) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"expecting more fragmented rx in one indication %d\n",
fw_desc_len);
}
@@ -1415,12 +1468,12 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
tx_done.discard = true;
break;
default:
- ath10k_warn("unhandled tx completion status %d\n", status);
+ ath10k_warn(ar, "unhandled tx completion status %d\n", status);
tx_done.discard = true;
break;
}
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
resp->data_tx_completion.num_msdus);
for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
@@ -1441,14 +1494,14 @@ static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp)
tid = MS(info0, HTT_RX_BA_INFO0_TID);
peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx addba tid %hu peer_id %hu size %hhu\n",
tid, peer_id, ev->window_size);
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, peer_id);
if (!peer) {
- ath10k_warn("received addba event for invalid peer_id: %hu\n",
+ ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
peer_id);
spin_unlock_bh(&ar->data_lock);
return;
@@ -1456,13 +1509,13 @@ static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp)
arvif = ath10k_get_arvif(ar, peer->vdev_id);
if (!arvif) {
- ath10k_warn("received addba event for invalid vdev_id: %u\n",
+ ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
peer->vdev_id);
spin_unlock_bh(&ar->data_lock);
return;
}
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx start rx ba session sta %pM tid %hu size %hhu\n",
peer->addr, tid, ev->window_size);
@@ -1481,14 +1534,14 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
tid = MS(info0, HTT_RX_BA_INFO0_TID);
peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx delba tid %hu peer_id %hu\n",
tid, peer_id);
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, peer_id);
if (!peer) {
- ath10k_warn("received addba event for invalid peer_id: %hu\n",
+ ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
peer_id);
spin_unlock_bh(&ar->data_lock);
return;
@@ -1496,13 +1549,13 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
arvif = ath10k_get_arvif(ar, peer->vdev_id);
if (!arvif) {
- ath10k_warn("received addba event for invalid vdev_id: %u\n",
+ ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
peer->vdev_id);
spin_unlock_bh(&ar->data_lock);
return;
}
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx stop rx ba session sta %pM tid %hu\n",
peer->addr, tid);
@@ -1517,9 +1570,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
/* confirm alignment */
if (!IS_ALIGNED((unsigned long)skb->data, 4))
- ath10k_warn("unaligned htt message, expect trouble\n");
+ ath10k_warn(ar, "unaligned htt message, expect trouble\n");
- ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
resp->hdr.msg_type);
switch (resp->hdr.msg_type) {
case HTT_T2H_MSG_TYPE_VERSION_CONF: {
@@ -1583,7 +1636,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
struct ath10k *ar = htt->ar;
struct htt_security_indication *ev = &resp->security_indication;
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"sec ind peer_id %d unicast %d type %d\n",
__le16_to_cpu(ev->peer_id),
!!(ev->flags & HTT_SECURITY_IS_UNICAST),
@@ -1592,7 +1645,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_RX_FRAG_IND: {
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
skb->data, skb->len);
ath10k_htt_rx_frag_handler(htt, &resp->rx_frag_ind);
break;
@@ -1609,7 +1662,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
* sends all tx frames as already inspected so this shouldn't
* happen unless fw has a bug.
*/
- ath10k_warn("received an unexpected htt tx inspect event\n");
+ ath10k_warn(ar, "received an unexpected htt tx inspect event\n");
break;
case HTT_T2H_MSG_TYPE_RX_ADDBA:
ath10k_htt_rx_addba(ar, resp);
@@ -1624,9 +1677,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
default:
- ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n",
resp->hdr.msg_type);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
skb->data, skb->len);
break;
};
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 8b27bfcc..eaa73aa 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -58,6 +58,7 @@ exit:
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
int msdu_id;
lockdep_assert_held(&htt->tx_lock);
@@ -67,24 +68,29 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
if (msdu_id == htt->max_num_pending_tx)
return -ENOBUFS;
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
__set_bit(msdu_id, htt->used_msdu_ids);
return msdu_id;
}
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
{
+ struct ath10k *ar = htt->ar;
+
lockdep_assert_held(&htt->tx_lock);
if (!test_bit(msdu_id, htt->used_msdu_ids))
- ath10k_warn("trying to free unallocated msdu_id %d\n", msdu_id);
+ ath10k_warn(ar, "trying to free unallocated msdu_id %d\n",
+ msdu_id);
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
__clear_bit(msdu_id, htt->used_msdu_ids);
}
int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
+
spin_lock_init(&htt->tx_lock);
init_waitqueue_head(&htt->empty_tx_wq);
@@ -93,7 +99,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
else
htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC;
- ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
htt->max_num_pending_tx);
htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
@@ -122,6 +128,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
struct htt_tx_done tx_done = {0};
int msdu_id;
@@ -130,7 +137,7 @@ static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
if (!test_bit(msdu_id, htt->used_msdu_ids))
continue;
- ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
msdu_id);
tx_done.discard = 1;
@@ -157,6 +164,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
struct sk_buff *skb;
struct htt_cmd *cmd;
int len = 0;
@@ -165,7 +173,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
len += sizeof(cmd->hdr);
len += sizeof(cmd->ver_req);
- skb = ath10k_htc_alloc_skb(len);
+ skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -184,6 +192,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
{
+ struct ath10k *ar = htt->ar;
struct htt_stats_req *req;
struct sk_buff *skb;
struct htt_cmd *cmd;
@@ -192,7 +201,7 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
len += sizeof(cmd->hdr);
len += sizeof(cmd->stats_req);
- skb = ath10k_htc_alloc_skb(len);
+ skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -214,7 +223,8 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
if (ret) {
- ath10k_warn("failed to send htt type stats request: %d", ret);
+ ath10k_warn(ar, "failed to send htt type stats request: %d",
+ ret);
dev_kfree_skb_any(skb);
return ret;
}
@@ -224,6 +234,7 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
struct sk_buff *skb;
struct htt_cmd *cmd;
struct htt_rx_ring_setup_ring *ring;
@@ -242,7 +253,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr)
+ (sizeof(*ring) * num_rx_ring);
- skb = ath10k_htc_alloc_skb(len);
+ skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -311,6 +322,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_ampdu,
u8 max_subfrms_amsdu)
{
+ struct ath10k *ar = htt->ar;
struct htt_aggr_conf *aggr_conf;
struct sk_buff *skb;
struct htt_cmd *cmd;
@@ -328,7 +340,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
len = sizeof(cmd->hdr);
len += sizeof(cmd->aggr_conf);
- skb = ath10k_htc_alloc_skb(len);
+ skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -340,7 +352,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu;
aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu;
- ath10k_dbg(ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
aggr_conf->max_num_amsdu_subframes,
aggr_conf->max_num_ampdu_subframes);
@@ -355,7 +367,8 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
{
- struct device *dev = htt->ar->dev;
+ struct ath10k *ar = htt->ar;
+ struct device *dev = ar->dev;
struct sk_buff *txdesc = NULL;
struct htt_cmd *cmd;
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
@@ -382,7 +395,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
htt->pending_tx[msdu_id] = msdu;
spin_unlock_bh(&htt->tx_lock);
- txdesc = ath10k_htc_alloc_skb(len);
+ txdesc = ath10k_htc_alloc_skb(ar, len);
if (!txdesc) {
res = -ENOMEM;
goto err_free_msdu_id;
@@ -429,7 +442,8 @@ err:
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
{
- struct device *dev = htt->ar->dev;
+ struct ath10k *ar = htt->ar;
+ struct device *dev = ar->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
struct ath10k_hif_sg_item sg_items[2];
@@ -545,11 +559,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
flags0, flags1, msdu->len, msdu_id, frags_paddr,
(u32)skb_cb->paddr, vdev_id, tid);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
msdu->data, msdu->len);
sg_items[0].transfer_id = 0;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 007e855..13568b0 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -28,16 +28,19 @@
#define QCA988X_HW_2_0_CHIP_ID_REV 0x2
#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0"
#define QCA988X_HW_2_0_FW_FILE "firmware.bin"
-#define QCA988X_HW_2_0_FW_2_FILE "firmware-2.bin"
+#define QCA988X_HW_2_0_FW_3_FILE "firmware-3.bin"
#define QCA988X_HW_2_0_OTP_FILE "otp.bin"
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
#define ATH10K_FW_API2_FILE "firmware-2.bin"
+#define ATH10K_FW_API3_FILE "firmware-3.bin"
/* includes also the null byte */
#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
+#define REG_DUMP_COUNT_QCA988X 60
+
struct ath10k_fw_ie {
__le32 id;
__le32 len;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 9d61bb1..b858c82 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -36,6 +36,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
enum set_key_cmd cmd,
const u8 *macaddr)
{
+ struct ath10k *ar = arvif->ar;
struct wmi_vdev_install_key_arg arg = {
.vdev_id = arvif->vdev_id,
.key_idx = key->keyidx,
@@ -73,7 +74,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
arg.key_flags = WMI_KEY_PAIRWISE;
break;
default:
- ath10k_warn("cipher %d is not supported\n", key->cipher);
+ ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
return -EOPNOTSUPP;
}
@@ -168,7 +169,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
first_errno = ret;
if (ret)
- ath10k_warn("failed to remove peer wep key %d: %d\n",
+ ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
i, ret);
peer->keys[i] = NULL;
@@ -216,7 +217,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
first_errno = ret;
if (ret)
- ath10k_warn("failed to remove key for %pM: %d\n",
+ ath10k_warn(ar, "failed to remove key for %pM: %d\n",
addr, ret);
}
@@ -327,14 +328,14 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
if (ret) {
- ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n",
+ ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
addr, vdev_id, ret);
return ret;
}
ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
if (ret) {
- ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n",
+ ath10k_warn(ar, "failed to wait for created wmi peer %pM on vdev %i: %i\n",
addr, vdev_id, ret);
return ret;
}
@@ -355,7 +356,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
ret = ath10k_wmi_pdev_set_param(ar, param,
ATH10K_KICKOUT_THRESHOLD);
if (ret) {
- ath10k_warn("failed to set kickout threshold on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set kickout threshold on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -364,7 +365,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
ATH10K_KEEPALIVE_MIN_IDLE);
if (ret) {
- ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set keepalive minimum idle time on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -373,7 +374,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
ATH10K_KEEPALIVE_MAX_IDLE);
if (ret) {
- ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set keepalive maximum idle time on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -382,7 +383,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
if (ret) {
- ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -449,7 +450,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
if (peer->vdev_id != vdev_id)
continue;
- ath10k_warn("removing stale peer %pM from vdev_id %d\n",
+ ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n",
peer->addr, vdev_id);
list_del(&peer->list);
@@ -496,7 +497,7 @@ static bool ath10k_monitor_is_enabled(struct ath10k *ar)
{
lockdep_assert_held(&ar->conf_mutex);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac monitor refs: promisc %d monitor %d cac %d\n",
ar->promisc, ar->monitor,
test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));
@@ -531,35 +532,35 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) {
- ath10k_warn("failed to request monitor vdev %i start: %d\n",
+ ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n",
vdev_id, ret);
return ret;
}
ret = ath10k_vdev_setup_sync(ar);
if (ret) {
- ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n",
+ ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i: %d\n",
vdev_id, ret);
return ret;
}
ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
if (ret) {
- ath10k_warn("failed to put up monitor vdev %i: %d\n",
+ ath10k_warn(ar, "failed to put up monitor vdev %i: %d\n",
vdev_id, ret);
goto vdev_stop;
}
ar->monitor_vdev_id = vdev_id;
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
ar->monitor_vdev_id);
return 0;
vdev_stop:
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n",
+ ath10k_warn(ar, "failed to stop monitor vdev %i after start failure: %d\n",
ar->monitor_vdev_id, ret);
return ret;
@@ -573,20 +574,20 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("failed to put down monitor vdev %i: %d\n",
+ ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n",
ar->monitor_vdev_id, ret);
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("failed to to request monitor vdev %i stop: %d\n",
+ ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n",
ar->monitor_vdev_id, ret);
ret = ath10k_vdev_setup_sync(ar);
if (ret)
- ath10k_warn("failed to synchronise monitor vdev %i: %d\n",
+ ath10k_warn(ar, "failed to synchronise monitor vdev %i: %d\n",
ar->monitor_vdev_id, ret);
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
ar->monitor_vdev_id);
return ret;
}
@@ -597,35 +598,29 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
- bit = ffs(ar->free_vdev_map);
- if (bit == 0) {
- ath10k_warn("failed to find free vdev id for monitor vdev\n");
+ if (ar->free_vdev_map == 0) {
+ ath10k_warn(ar, "failed to find free vdev id for monitor vdev\n");
return -ENOMEM;
}
+ bit = ffs(ar->free_vdev_map);
+
ar->monitor_vdev_id = bit - 1;
- ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
WMI_VDEV_TYPE_MONITOR,
0, ar->mac_addr);
if (ret) {
- ath10k_warn("failed to request monitor vdev %i creation: %d\n",
+ ath10k_warn(ar, "failed to request monitor vdev %i creation: %d\n",
ar->monitor_vdev_id, ret);
- goto vdev_fail;
+ return ret;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
+ ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
ar->monitor_vdev_id);
return 0;
-
-vdev_fail:
- /*
- * Restore the ID to the global map.
- */
- ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
- return ret;
}
static int ath10k_monitor_vdev_delete(struct ath10k *ar)
@@ -636,14 +631,14 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar)
ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id);
if (ret) {
- ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n",
+ ath10k_warn(ar, "failed to request wmi monitor vdev %i removal: %d\n",
ar->monitor_vdev_id, ret);
return ret;
}
- ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
+ ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
ar->monitor_vdev_id);
return ret;
}
@@ -655,30 +650,30 @@ static int ath10k_monitor_start(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
if (!ath10k_monitor_is_enabled(ar)) {
- ath10k_warn("trying to start monitor with no references\n");
+ ath10k_warn(ar, "trying to start monitor with no references\n");
return 0;
}
if (ar->monitor_started) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor already started\n");
return 0;
}
ret = ath10k_monitor_vdev_create(ar);
if (ret) {
- ath10k_warn("failed to create monitor vdev: %d\n", ret);
+ ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret);
return ret;
}
ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
if (ret) {
- ath10k_warn("failed to start monitor vdev: %d\n", ret);
+ ath10k_warn(ar, "failed to start monitor vdev: %d\n", ret);
ath10k_monitor_vdev_delete(ar);
return ret;
}
ar->monitor_started = true;
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor started\n");
return 0;
}
@@ -690,27 +685,27 @@ static void ath10k_monitor_stop(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
if (ath10k_monitor_is_enabled(ar)) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac monitor will be stopped later\n");
return;
}
if (!ar->monitor_started) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac monitor probably failed to start earlier\n");
return;
}
ret = ath10k_monitor_vdev_stop(ar);
if (ret)
- ath10k_warn("failed to stop monitor vdev: %d\n", ret);
+ ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret);
ret = ath10k_monitor_vdev_delete(ar);
if (ret)
- ath10k_warn("failed to delete monitor vdev: %d\n", ret);
+ ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret);
ar->monitor_started = false;
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n");
}
static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
@@ -743,12 +738,12 @@ static int ath10k_start_cac(struct ath10k *ar)
ret = ath10k_monitor_start(ar);
if (ret) {
- ath10k_warn("failed to start monitor (cac): %d\n", ret);
+ ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret);
clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
return ret;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
ar->monitor_vdev_id);
return 0;
@@ -765,7 +760,7 @@ static int ath10k_stop_cac(struct ath10k *ar)
clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
ath10k_monitor_stop(ar);
- ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac finished\n");
return 0;
}
@@ -791,12 +786,12 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar)
* radiation is not allowed, make this channel DFS_UNAVAILABLE
* by indicating that radar was detected.
*/
- ath10k_warn("failed to start CAC: %d\n", ret);
+ ath10k_warn(ar, "failed to start CAC: %d\n", ret);
ieee80211_radar_detected(ar->hw);
}
}
-static int ath10k_vdev_start(struct ath10k_vif *arvif)
+static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
{
struct ath10k *ar = arvif->ar;
struct cfg80211_chan_def *chandef = &ar->chandef;
@@ -833,21 +828,25 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
arg.ssid_len = arvif->vif->bss_conf.ssid_len;
}
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d start center_freq %d phymode %s\n",
arg.vdev_id, arg.channel.freq,
ath10k_wmi_phymode_str(arg.channel.mode));
- ret = ath10k_wmi_vdev_start(ar, &arg);
+ if (restart)
+ ret = ath10k_wmi_vdev_restart(ar, &arg);
+ else
+ ret = ath10k_wmi_vdev_start(ar, &arg);
+
if (ret) {
- ath10k_warn("failed to start WMI vdev %i: %d\n",
+ ath10k_warn(ar, "failed to start WMI vdev %i: %d\n",
arg.vdev_id, ret);
return ret;
}
ret = ath10k_vdev_setup_sync(ar);
if (ret) {
- ath10k_warn("failed to synchronise setup for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to synchronise setup for vdev %i: %d\n",
arg.vdev_id, ret);
return ret;
}
@@ -858,6 +857,16 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
return ret;
}
+static int ath10k_vdev_start(struct ath10k_vif *arvif)
+{
+ return ath10k_vdev_start_restart(arvif, false);
+}
+
+static int ath10k_vdev_restart(struct ath10k_vif *arvif)
+{
+ return ath10k_vdev_start_restart(arvif, true);
+}
+
static int ath10k_vdev_stop(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
@@ -869,14 +878,14 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
if (ret) {
- ath10k_warn("failed to stop WMI vdev %i: %d\n",
+ ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
ret = ath10k_vdev_setup_sync(ar);
if (ret) {
- ath10k_warn("failed to syncronise setup for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -894,6 +903,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
static void ath10k_control_beaconing(struct ath10k_vif *arvif,
struct ieee80211_bss_conf *info)
{
+ struct ath10k *ar = arvif->ar;
int ret = 0;
lockdep_assert_held(&arvif->ar->conf_mutex);
@@ -931,7 +941,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) {
- ath10k_warn("failed to bring up vdev %d: %i\n",
+ ath10k_warn(ar, "failed to bring up vdev %d: %i\n",
arvif->vdev_id, ret);
ath10k_vdev_stop(arvif);
return;
@@ -940,13 +950,14 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
arvif->is_started = true;
arvif->is_up = true;
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
}
static void ath10k_control_ibss(struct ath10k_vif *arvif,
struct ieee80211_bss_conf *info,
const u8 self_peer[ETH_ALEN])
{
+ struct ath10k *ar = arvif->ar;
u32 vdev_param;
int ret = 0;
@@ -955,7 +966,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
if (!info->ibss_joined) {
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);
if (ret)
- ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to delete IBSS self peer %pM for vdev %d: %d\n",
self_peer, arvif->vdev_id, ret);
if (is_zero_ether_addr(arvif->bssid))
@@ -964,7 +975,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
arvif->bssid);
if (ret) {
- ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
arvif->bssid, arvif->vdev_id, ret);
return;
}
@@ -976,7 +987,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
if (ret) {
- ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
self_peer, arvif->vdev_id, ret);
return;
}
@@ -985,7 +996,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
ATH10K_DEFAULT_ATIM);
if (ret)
- ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set IBSS ATIM for vdev %d: %d\n",
arvif->vdev_id, ret);
}
@@ -1012,7 +1023,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
conf->dynamic_ps_timeout);
if (ret) {
- ath10k_warn("failed to set inactivity time for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1020,12 +1031,12 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
psmode = WMI_STA_PS_MODE_DISABLED;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
arvif->vdev_id, psmode ? "enable" : "disable");
ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
if (ret) {
- ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set PS Mode %d for vdev %d: %d\n",
psmode, arvif->vdev_id, ret);
return ret;
}
@@ -1109,12 +1120,12 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
/* FIXME: base on RSN IE/WPA IE is a correct idea? */
if (rsnie || wpaie) {
- ath10k_dbg(ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
}
if (wpaie) {
- ath10k_dbg(ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
}
}
@@ -1223,7 +1234,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_num_spatial_streams = sta->rx_nss;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
arg->addr,
arg->peer_ht_rates.num_rates,
arg->peer_num_spatial_streams);
@@ -1240,7 +1251,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
lockdep_assert_held(&ar->conf_mutex);
if (sta->wme && sta->uapsd_queues) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
sta->uapsd_queues, sta->max_sp);
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
@@ -1265,7 +1276,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
WMI_AP_PS_PEER_PARAM_UAPSD,
uapsd);
if (ret) {
- ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set ap ps peer param uapsd for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1275,7 +1286,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
WMI_AP_PS_PEER_PARAM_MAX_SP,
max_sp);
if (ret) {
- ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set ap ps peer param max sp for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1287,7 +1298,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
if (ret) {
- ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1334,7 +1345,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
arg->peer_vht_rates.tx_mcs_set =
__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
- ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
sta->addr, arg->peer_max_mpdu, arg->peer_flags);
}
@@ -1407,7 +1418,7 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
break;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
sta->addr, ath10k_wmi_phymode_str(phymode));
arg->peer_phymode = phymode;
@@ -1480,7 +1491,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
if (!ap_sta) {
- ath10k_warn("failed to find station entry for bss %pM vdev %i\n",
+ ath10k_warn(ar, "failed to find station entry for bss %pM vdev %i\n",
bss_conf->bssid, arvif->vdev_id);
rcu_read_unlock();
return;
@@ -1493,7 +1504,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
bss_conf, &peer_arg);
if (ret) {
- ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n",
+ ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
bss_conf->bssid, arvif->vdev_id, ret);
rcu_read_unlock();
return;
@@ -1503,19 +1514,19 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
if (ret) {
- ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n",
+ ath10k_warn(ar, "failed to run peer assoc for %pM vdev %i: %d\n",
bss_conf->bssid, arvif->vdev_id, ret);
return;
}
ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
if (ret) {
- ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to setup peer SMPS for vdev %i: %d\n",
arvif->vdev_id, ret);
return;
}
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d up (associated) bssid %pM aid %d\n",
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
@@ -1524,7 +1535,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
if (ret) {
- ath10k_warn("failed to set vdev %d up: %d\n",
+ ath10k_warn(ar, "failed to set vdev %d up: %d\n",
arvif->vdev_id, ret);
return;
}
@@ -1550,7 +1561,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
* No idea why this happens, even though VDEV-DOWN is supposed
* to be analogous to link down, so just stop the VDEV.
*/
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
arvif->vdev_id);
/* FIXME: check return value */
@@ -1563,7 +1574,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
* interfaces as it expects there is no rx when no interface is
* running.
*/
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
/* FIXME: why don't we print error if wmi call fails? */
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
@@ -1584,7 +1595,7 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
if (ret) {
- ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
+ ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
@@ -1592,14 +1603,14 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
peer_arg.peer_reassoc = reassoc;
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
if (ret) {
- ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n",
+ ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
if (ret) {
- ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1608,7 +1619,7 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
arvif->num_legacy_stations++;
ret = ath10k_recalc_rtscts_prot(arvif);
if (ret) {
- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1616,14 +1627,14 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) {
- ath10k_warn("failed to install peer wep keys for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
if (ret) {
- ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
@@ -1642,7 +1653,7 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
arvif->num_legacy_stations--;
ret = ath10k_recalc_rtscts_prot(arvif);
if (ret) {
- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1650,7 +1661,7 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
ret = ath10k_clear_peer_keys(arvif, sta->addr);
if (ret) {
- ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to clear all peer wep keys for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1742,7 +1753,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
if (WARN_ON_ONCE(ch->mode == MODE_UNKNOWN))
continue;
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
ch - arg.channels, arg.n_channels,
ch->freq, ch->max_power, ch->max_reg_power,
@@ -1785,7 +1796,7 @@ static void ath10k_regd_update(struct ath10k *ar)
ret = ath10k_update_channel_list(ar);
if (ret)
- ath10k_warn("failed to update channel list: %d\n", ret);
+ ath10k_warn(ar, "failed to update channel list: %d\n", ret);
regpair = ar->ath_common.regulatory.regpair;
@@ -1806,7 +1817,7 @@ static void ath10k_regd_update(struct ath10k *ar)
regpair->reg_5ghz_ctl,
wmi_dfs_reg);
if (ret)
- ath10k_warn("failed to set pdev regdomain: %d\n", ret);
+ ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret);
}
static void ath10k_reg_notifier(struct wiphy *wiphy,
@@ -1819,12 +1830,12 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
request->dfs_region);
result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
request->dfs_region);
if (!result)
- ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n",
+ ath10k_warn(ar, "DFS region 0x%X not supported, will trigger radar for every pulse\n",
request->dfs_region);
}
@@ -1861,7 +1872,7 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
if (ar->monitor_started)
return ar->monitor_vdev_id;
- ath10k_warn("failed to resolve vdev id\n");
+ ath10k_warn(ar, "failed to resolve vdev id\n");
return 0;
}
@@ -1897,6 +1908,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
{
struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
wep_key_work);
+ struct ath10k *ar = arvif->ar;
int ret, keyidx = arvif->def_wep_key_newidx;
mutex_lock(&arvif->ar->conf_mutex);
@@ -1907,7 +1919,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
if (arvif->def_wep_key_idx == keyidx)
goto unlock;
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
arvif->vdev_id, keyidx);
ret = ath10k_wmi_vdev_set_param(arvif->ar,
@@ -1915,7 +1927,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
arvif->ar->wmi.vdev_param->def_keyid,
keyidx);
if (ret) {
- ath10k_warn("failed to update wep key index for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
arvif->vdev_id,
ret);
goto unlock;
@@ -1995,7 +2007,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
ar->fw_features)) {
if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
ATH10K_MAX_NUM_MGMT_PENDING) {
- ath10k_warn("reached WMI management tranmist queue limit\n");
+ ath10k_warn(ar, "reached WMI management transmit queue limit\n");
ret = -EBUSY;
goto exit;
}
@@ -2019,7 +2031,8 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
exit:
if (ret) {
- ath10k_warn("failed to transmit packet, dropping: %d\n", ret);
+ ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
+ ret);
ieee80211_free_txskb(ar->hw, skb);
}
}
@@ -2061,7 +2074,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
mutex_lock(&ar->conf_mutex);
- ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %p\n",
skb);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -2074,13 +2087,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
if (peer)
/* FIXME: should this use ath10k_warn()? */
- ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
peer_addr, vdev_id);
if (!peer) {
ret = ath10k_peer_create(ar, vdev_id, peer_addr);
if (ret)
- ath10k_warn("failed to create peer %pM on vdev %d: %d\n",
+ ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
peer_addr, vdev_id, ret);
}
@@ -2094,13 +2107,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
3 * HZ);
if (ret <= 0)
- ath10k_warn("timed out waiting for offchannel skb %p\n",
+ ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
skb);
if (!peer) {
ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
if (ret)
- ath10k_warn("failed to delete peer %pM on vdev %d: %d\n",
+ ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n",
peer_addr, vdev_id, ret);
}
@@ -2134,7 +2147,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
ret = ath10k_wmi_mgmt_tx(ar, skb);
if (ret) {
- ath10k_warn("failed to transmit management frame via WMI: %d\n",
+ ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
ret);
ieee80211_free_txskb(ar->hw, skb);
}
@@ -2145,34 +2158,40 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
/* Scanning */
/************/
-/*
- * This gets called if we dont get a heart-beat during scan.
- * This may indicate the FW has hung and we need to abort the
- * scan manually to prevent cancel_hw_scan() from deadlocking
- */
-void ath10k_reset_scan(unsigned long ptr)
+void __ath10k_scan_finish(struct ath10k *ar)
{
- struct ath10k *ar = (struct ath10k *)ptr;
+ lockdep_assert_held(&ar->data_lock);
- spin_lock_bh(&ar->data_lock);
- if (!ar->scan.in_progress) {
- spin_unlock_bh(&ar->data_lock);
- return;
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ break;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ if (ar->scan.is_roc)
+ ieee80211_remain_on_channel_expired(ar->hw);
+ else
+ ieee80211_scan_completed(ar->hw,
+ (ar->scan.state ==
+ ATH10K_SCAN_ABORTING));
+ /* fall through */
+ case ATH10K_SCAN_STARTING:
+ ar->scan.state = ATH10K_SCAN_IDLE;
+ ar->scan_channel = NULL;
+ ath10k_offchan_tx_purge(ar);
+ cancel_delayed_work(&ar->scan.timeout);
+ complete_all(&ar->scan.completed);
+ break;
}
+}
- ath10k_warn("scan timed out, firmware problem?\n");
-
- if (ar->scan.is_roc)
- ieee80211_remain_on_channel_expired(ar->hw);
- else
- ieee80211_scan_completed(ar->hw, 1 /* aborted */);
-
- ar->scan.in_progress = false;
- complete_all(&ar->scan.completed);
+void ath10k_scan_finish(struct ath10k *ar)
+{
+ spin_lock_bh(&ar->data_lock);
+ __ath10k_scan_finish(ar);
spin_unlock_bh(&ar->data_lock);
}
-static int ath10k_abort_scan(struct ath10k *ar)
+static int ath10k_scan_stop(struct ath10k *ar)
{
struct wmi_stop_scan_arg arg = {
.req_id = 1, /* FIXME */
@@ -2183,47 +2202,79 @@ static int ath10k_abort_scan(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
- del_timer_sync(&ar->scan.timeout);
+ ret = ath10k_wmi_stop_scan(ar, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to stop wmi scan: %d\n", ret);
+ goto out;
+ }
- spin_lock_bh(&ar->data_lock);
- if (!ar->scan.in_progress) {
- spin_unlock_bh(&ar->data_lock);
- return 0;
+ ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
+ if (ret == 0) {
+ ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n");
+ ret = -ETIMEDOUT;
+ } else if (ret > 0) {
+ ret = 0;
}
- ar->scan.aborting = true;
+out:
+ /* Scan state should be updated upon scan completion but in case
+ * firmware fails to deliver the event (for whatever reason) it is
+ * desired to clean up scan state anyway. Firmware may have just
+ * dropped the scan completion event delivery due to transport pipe
+ * being overflown with data and/or it can recover on its own before
+ * next scan request is submitted.
+ */
+ spin_lock_bh(&ar->data_lock);
+ if (ar->scan.state != ATH10K_SCAN_IDLE)
+ __ath10k_scan_finish(ar);
spin_unlock_bh(&ar->data_lock);
- ret = ath10k_wmi_stop_scan(ar, &arg);
- if (ret) {
- ath10k_warn("failed to stop wmi scan: %d\n", ret);
- spin_lock_bh(&ar->data_lock);
- ar->scan.in_progress = false;
- ath10k_offchan_tx_purge(ar);
- spin_unlock_bh(&ar->data_lock);
- return -EIO;
- }
+ return ret;
+}
- ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
- if (ret == 0)
- ath10k_warn("timed out while waiting for scan to stop\n");
+static void ath10k_scan_abort(struct ath10k *ar)
+{
+ int ret;
- /* scan completion may be done right after we timeout here, so let's
- * check the in_progress and tell mac80211 scan is completed. if we
- * don't do that and FW fails to send us scan completion indication
- * then userspace won't be able to scan anymore */
- ret = 0;
+ lockdep_assert_held(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
- if (ar->scan.in_progress) {
- ath10k_warn("failed to stop scan, it's still in progress\n");
- ar->scan.in_progress = false;
- ath10k_offchan_tx_purge(ar);
- ret = -ETIMEDOUT;
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ /* This can happen if timeout worker kicked in and called
+ * abortion while scan completion was being processed.
+ */
+ break;
+ case ATH10K_SCAN_STARTING:
+ case ATH10K_SCAN_ABORTING:
+ ath10k_warn(ar, "refusing scan abortion due to invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_RUNNING:
+ ar->scan.state = ATH10K_SCAN_ABORTING;
+ spin_unlock_bh(&ar->data_lock);
+
+ ret = ath10k_scan_stop(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to abort scan: %d\n", ret);
+
+ spin_lock_bh(&ar->data_lock);
+ break;
}
+
spin_unlock_bh(&ar->data_lock);
+}
- return ret;
+void ath10k_scan_timeout_work(struct work_struct *work)
+{
+ struct ath10k *ar = container_of(work, struct ath10k,
+ scan.timeout.work);
+
+ mutex_lock(&ar->conf_mutex);
+ ath10k_scan_abort(ar);
+ mutex_unlock(&ar->conf_mutex);
}
static int ath10k_start_scan(struct ath10k *ar,
@@ -2239,17 +2290,16 @@ static int ath10k_start_scan(struct ath10k *ar,
ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ);
if (ret == 0) {
- ath10k_abort_scan(ar);
- return ret;
+ ret = ath10k_scan_stop(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to stop scan: %d\n", ret);
+
+ return -ETIMEDOUT;
}
- /* the scan can complete earlier, before we even
- * start the timer. in that case the timer handler
- * checks ar->scan.in_progress and bails out if its
- * false. Add a 200ms margin to account event/command
- * processing. */
- mod_timer(&ar->scan.timeout, jiffies +
- msecs_to_jiffies(arg->max_scan_time+200));
+ /* Add a 200ms margin to account for event/command processing */
+ ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+ msecs_to_jiffies(arg->max_scan_time+200));
return 0;
}
@@ -2269,7 +2319,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/* We should disable CCK RATE due to P2P */
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
- ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
ATH10K_SKB_CB(skb)->htt.is_offchan = false;
ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
@@ -2289,7 +2339,8 @@ static void ath10k_tx(struct ieee80211_hw *hw,
ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
spin_unlock_bh(&ar->data_lock);
- ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
+ skb);
skb_queue_tail(&ar->offchan_tx_queue, skb);
ieee80211_queue_work(hw, &ar->offchan_tx_work);
@@ -2325,8 +2376,7 @@ void ath10k_halt(struct ath10k *ar)
ath10k_monitor_stop(ar);
}
- del_timer_sync(&ar->scan.timeout);
- ath10k_reset_scan((unsigned long)ar);
+ ath10k_scan_finish(ar);
ath10k_peer_cleanup_all(ar);
ath10k_core_stop(ar);
ath10k_hif_power_down(ar);
@@ -2380,7 +2430,7 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask,
tx_ant);
if (ret) {
- ath10k_warn("failed to set tx-chainmask: %d, req 0x%x\n",
+ ath10k_warn(ar, "failed to set tx-chainmask: %d, req 0x%x\n",
ret, tx_ant);
return ret;
}
@@ -2388,7 +2438,7 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask,
rx_ant);
if (ret) {
- ath10k_warn("failed to set rx-chainmask: %d, req 0x%x\n",
+ ath10k_warn(ar, "failed to set rx-chainmask: %d, req 0x%x\n",
ret, rx_ant);
return ret;
}
@@ -2439,25 +2489,25 @@ static int ath10k_start(struct ieee80211_hw *hw)
ret = ath10k_hif_power_up(ar);
if (ret) {
- ath10k_err("Could not init hif: %d\n", ret);
+ ath10k_err(ar, "Could not init hif: %d\n", ret);
goto err_off;
}
ret = ath10k_core_start(ar);
if (ret) {
- ath10k_err("Could not init core: %d\n", ret);
+ ath10k_err(ar, "Could not init core: %d\n", ret);
goto err_power_down;
}
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
if (ret) {
- ath10k_warn("failed to enable PMF QOS: %d\n", ret);
+ ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
goto err_core_stop;
}
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
if (ret) {
- ath10k_warn("failed to enable dynamic BW: %d\n", ret);
+ ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
goto err_core_stop;
}
@@ -2477,7 +2527,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
ret = ath10k_wmi_pdev_set_param(ar,
ar->wmi.pdev_param->arp_ac_override, 0);
if (ret) {
- ath10k_warn("failed to set arp ac override parameter: %d\n",
+ ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
ret);
goto err_core_stop;
}
@@ -2485,6 +2535,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
ar->num_started_vdevs = 0;
ath10k_regd_update(ar);
+ ath10k_spectral_start(ar);
+
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -2515,6 +2567,7 @@ static void ath10k_stop(struct ieee80211_hw *hw)
}
mutex_unlock(&ar->conf_mutex);
+ cancel_delayed_work_sync(&ar->scan.timeout);
cancel_work_sync(&ar->restart_work);
}
@@ -2528,7 +2581,7 @@ static int ath10k_config_ps(struct ath10k *ar)
list_for_each_entry(arvif, &ar->arvifs, list) {
ret = ath10k_mac_vif_setup_ps(arvif);
if (ret) {
- ath10k_warn("failed to setup powersave: %d\n", ret);
+ ath10k_warn(ar, "failed to setup powersave: %d\n", ret);
break;
}
}
@@ -2566,7 +2619,7 @@ static void ath10k_config_chan(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
ar->chandef.chan->center_freq,
ar->chandef.center_freq1,
@@ -2582,18 +2635,21 @@ static void ath10k_config_chan(struct ath10k *ar)
if (!arvif->is_started)
continue;
+ if (!arvif->is_up)
+ continue;
+
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
continue;
- ret = ath10k_vdev_stop(arvif);
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
if (ret) {
- ath10k_warn("failed to stop vdev %d: %d\n",
+ ath10k_warn(ar, "failed to down vdev %d: %d\n",
arvif->vdev_id, ret);
continue;
}
}
- /* all vdevs are now stopped - now attempt to restart them */
+ /* all vdevs are downed now - attempt to restart and re-up them */
list_for_each_entry(arvif, &ar->arvifs, list) {
if (!arvif->is_started)
@@ -2602,9 +2658,9 @@ static void ath10k_config_chan(struct ath10k *ar)
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
continue;
- ret = ath10k_vdev_start(arvif);
+ ret = ath10k_vdev_restart(arvif);
if (ret) {
- ath10k_warn("failed to start vdev %d: %d\n",
+ ath10k_warn(ar, "failed to restart vdev %d: %d\n",
arvif->vdev_id, ret);
continue;
}
@@ -2615,7 +2671,7 @@ static void ath10k_config_chan(struct ath10k *ar)
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) {
- ath10k_warn("failed to bring vdev up %d: %d\n",
+ ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
arvif->vdev_id, ret);
continue;
}
@@ -2635,7 +2691,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&ar->conf_mutex);
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac config channel %dMHz flags 0x%x radar %d\n",
conf->chandef.chan->center_freq,
conf->chandef.chan->flags,
@@ -2655,21 +2711,21 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n",
hw->conf.power_level);
param = ar->wmi.pdev_param->txpower_limit2g;
ret = ath10k_wmi_pdev_set_param(ar, param,
hw->conf.power_level * 2);
if (ret)
- ath10k_warn("failed to set 2g txpower %d: %d\n",
+ ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
hw->conf.power_level, ret);
param = ar->wmi.pdev_param->txpower_limit5g;
ret = ath10k_wmi_pdev_set_param(ar, param,
hw->conf.power_level * 2);
if (ret)
- ath10k_warn("failed to set 5g txpower %d: %d\n",
+ ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
hw->conf.power_level, ret);
}
@@ -2681,7 +2737,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
ar->monitor = true;
ret = ath10k_monitor_start(ar);
if (ret) {
- ath10k_warn("failed to start monitor (config): %d\n",
+ ath10k_warn(ar, "failed to start monitor (config): %d\n",
ret);
ar->monitor = false;
}
@@ -2724,11 +2780,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
INIT_LIST_HEAD(&arvif->list);
- bit = ffs(ar->free_vdev_map);
- if (bit == 0) {
+ if (ar->free_vdev_map == 0) {
+ ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
ret = -EBUSY;
goto err;
}
+ bit = ffs(ar->free_vdev_map);
arvif->vdev_id = bit - 1;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
@@ -2760,25 +2817,25 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
break;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
arvif->vdev_subtype, vif->addr);
if (ret) {
- ath10k_warn("failed to create WMI vdev %i: %d\n",
+ ath10k_warn(ar, "failed to create WMI vdev %i: %d\n",
arvif->vdev_id, ret);
goto err;
}
- ar->free_vdev_map &= ~BIT(arvif->vdev_id);
+ ar->free_vdev_map &= ~(1 << arvif->vdev_id);
list_add(&arvif->list, &ar->arvifs);
vdev_param = ar->wmi.vdev_param->def_keyid;
ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
arvif->def_wep_key_idx);
if (ret) {
- ath10k_warn("failed to set vdev %i default key id: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i default key id: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
@@ -2788,7 +2845,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ATH10K_HW_TXRX_NATIVE_WIFI);
/* 10.X firmware does not support this VDEV parameter. Do not warn */
if (ret && ret != -EOPNOTSUPP) {
- ath10k_warn("failed to set vdev %i TX encapsulation: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
@@ -2796,14 +2853,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
if (ret) {
- ath10k_warn("failed to create vdev %i peer for AP: %d\n",
+ ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
ret = ath10k_mac_set_kickout(arvif);
if (ret) {
- ath10k_warn("failed to set vdev %i kickout parameters: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2815,7 +2872,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("failed to set vdev %i RX wake policy: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i RX wake policy: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2825,7 +2882,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("failed to set vdev %i TX wake thresh: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2835,7 +2892,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("failed to set vdev %i PSPOLL count: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2843,14 +2900,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
if (ret) {
- ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
if (ret) {
- ath10k_warn("failed to set frag threshold for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2864,7 +2921,7 @@ err_peer_delete:
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
- ar->free_vdev_map &= ~BIT(arvif->vdev_id);
+ ar->free_vdev_map |= 1 << arvif->vdev_id;
list_del(&arvif->list);
err:
@@ -2892,26 +2949,32 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
dev_kfree_skb_any(arvif->beacon);
arvif->beacon = NULL;
}
+
spin_unlock_bh(&ar->data_lock);
- ar->free_vdev_map |= 1 << (arvif->vdev_id);
+ ret = ath10k_spectral_vif_stop(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+
+ ar->free_vdev_map |= 1 << arvif->vdev_id;
list_del(&arvif->list);
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
if (ret)
- ath10k_warn("failed to remove peer for AP vdev %i: %d\n",
+ ath10k_warn(ar, "failed to remove peer for AP vdev %i: %d\n",
arvif->vdev_id, ret);
kfree(arvif->u.ap.noa_data);
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
arvif->vdev_id);
ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
if (ret)
- ath10k_warn("failed to delete WMI vdev %i: %d\n",
+ ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
arvif->vdev_id, ret);
ath10k_peer_cleanup(ar, arvif->vdev_id);
@@ -2950,7 +3013,7 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
ar->promisc = true;
ret = ath10k_monitor_start(ar);
if (ret) {
- ath10k_warn("failed to start monitor (promisc): %d\n",
+ ath10k_warn(ar, "failed to start monitor (promisc): %d\n",
ret);
ar->promisc = false;
}
@@ -2982,17 +3045,17 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
vdev_param = ar->wmi.vdev_param->beacon_interval;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
arvif->beacon_interval);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d beacon_interval %d\n",
arvif->vdev_id, arvif->beacon_interval);
if (ret)
- ath10k_warn("failed to set beacon interval for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set beacon interval for vdev %d: %i\n",
arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_BEACON) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"vdev %d set beacon tx mode to staggered\n",
arvif->vdev_id);
@@ -3000,14 +3063,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
WMI_BEACON_STAGGERED_MODE);
if (ret)
- ath10k_warn("failed to set beacon mode for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n",
arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_BEACON_INFO) {
arvif->dtim_period = info->dtim_period;
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d dtim_period %d\n",
arvif->vdev_id, arvif->dtim_period);
@@ -3015,7 +3078,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
arvif->dtim_period);
if (ret)
- ath10k_warn("failed to set dtim period for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set dtim period for vdev %d: %i\n",
arvif->vdev_id, ret);
}
@@ -3034,14 +3097,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID &&
vif->type != NL80211_IFTYPE_AP) {
if (!is_zero_ether_addr(info->bssid)) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d create peer %pM\n",
arvif->vdev_id, info->bssid);
ret = ath10k_peer_create(ar, arvif->vdev_id,
info->bssid);
if (ret)
- ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n",
+ ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
info->bssid, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION) {
@@ -3051,13 +3114,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
*/
memcpy(arvif->bssid, info->bssid, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d start %pM\n",
arvif->vdev_id, info->bssid);
ret = ath10k_vdev_start(arvif);
if (ret) {
- ath10k_warn("failed to start vdev %i: %d\n",
+ ath10k_warn(ar, "failed to start vdev %i: %d\n",
arvif->vdev_id, ret);
goto exit;
}
@@ -3081,12 +3144,12 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
arvif->use_cts_prot = info->use_cts_prot;
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
arvif->vdev_id, info->use_cts_prot);
ret = ath10k_recalc_rtscts_prot(arvif);
if (ret)
- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
}
@@ -3098,14 +3161,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
else
slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
arvif->vdev_id, slottime);
vdev_param = ar->wmi.vdev_param->slot_time;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
slottime);
if (ret)
- ath10k_warn("failed to set erp slot for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set erp slot for vdev %d: %i\n",
arvif->vdev_id, ret);
}
@@ -3116,7 +3179,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
else
preamble = WMI_VDEV_PREAMBLE_LONG;
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d preamble %dn",
arvif->vdev_id, preamble);
@@ -3124,7 +3187,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
preamble);
if (ret)
- ath10k_warn("failed to set preamble for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set preamble for vdev %d: %i\n",
arvif->vdev_id, ret);
}
@@ -3151,20 +3214,26 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
- if (ar->scan.in_progress) {
- spin_unlock_bh(&ar->data_lock);
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ reinit_completion(&ar->scan.started);
+ reinit_completion(&ar->scan.completed);
+ ar->scan.state = ATH10K_SCAN_STARTING;
+ ar->scan.is_roc = false;
+ ar->scan.vdev_id = arvif->vdev_id;
+ ret = 0;
+ break;
+ case ATH10K_SCAN_STARTING:
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
ret = -EBUSY;
- goto exit;
+ break;
}
-
- reinit_completion(&ar->scan.started);
- reinit_completion(&ar->scan.completed);
- ar->scan.in_progress = true;
- ar->scan.aborting = false;
- ar->scan.is_roc = false;
- ar->scan.vdev_id = arvif->vdev_id;
spin_unlock_bh(&ar->data_lock);
+ if (ret)
+ goto exit;
+
memset(&arg, 0, sizeof(arg));
ath10k_wmi_start_scan_init(ar, &arg);
arg.vdev_id = arvif->vdev_id;
@@ -3196,9 +3265,9 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
ret = ath10k_start_scan(ar, &arg);
if (ret) {
- ath10k_warn("failed to start hw scan: %d\n", ret);
+ ath10k_warn(ar, "failed to start hw scan: %d\n", ret);
spin_lock_bh(&ar->data_lock);
- ar->scan.in_progress = false;
+ ar->scan.state = ATH10K_SCAN_IDLE;
spin_unlock_bh(&ar->data_lock);
}
@@ -3211,14 +3280,10 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath10k *ar = hw->priv;
- int ret;
mutex_lock(&ar->conf_mutex);
- ret = ath10k_abort_scan(ar);
- if (ret) {
- ath10k_warn("failed to abort scan: %d\n", ret);
- ieee80211_scan_completed(hw, 1 /* aborted */);
- }
+ cancel_delayed_work_sync(&ar->scan.timeout);
+ ath10k_scan_abort(ar);
mutex_unlock(&ar->conf_mutex);
}
@@ -3256,7 +3321,7 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
key->keyidx);
if (ret)
- ath10k_warn("failed to set vdev %i group key as default key: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i group key as default key: %d\n",
arvif->vdev_id, ret);
}
@@ -3294,7 +3359,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (!peer) {
if (cmd == SET_KEY) {
- ath10k_warn("failed to install key for non-existent peer %pM\n",
+ ath10k_warn(ar, "failed to install key for non-existent peer %pM\n",
peer_addr);
ret = -EOPNOTSUPP;
goto exit;
@@ -3317,7 +3382,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = ath10k_install_key(arvif, key, cmd, peer_addr);
if (ret) {
- ath10k_warn("failed to install key for vdev %i peer %pM: %d\n",
+ ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
arvif->vdev_id, peer_addr, ret);
goto exit;
}
@@ -3332,7 +3397,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
peer->keys[key->keyidx] = NULL;
else if (peer == NULL)
/* impossible unless FW goes crazy */
- ath10k_warn("Peer %pM disappeared!\n", peer_addr);
+ ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr);
spin_unlock_bh(&ar->data_lock);
exit:
@@ -3368,45 +3433,45 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_lock(&ar->conf_mutex);
if (changed & IEEE80211_RC_BW_CHANGED) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
sta->addr, bw);
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
WMI_PEER_CHAN_WIDTH, bw);
if (err)
- ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
+ ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n",
sta->addr, bw, err);
}
if (changed & IEEE80211_RC_NSS_CHANGED) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
sta->addr, nss);
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
WMI_PEER_NSS, nss);
if (err)
- ath10k_warn("failed to update STA %pM nss %d: %d\n",
+ ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n",
sta->addr, nss, err);
}
if (changed & IEEE80211_RC_SMPS_CHANGED) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
sta->addr, smps);
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
WMI_PEER_SMPS_STATE, smps);
if (err)
- ath10k_warn("failed to update STA %pM smps %d: %d\n",
+ ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n",
sta->addr, smps, err);
}
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
sta->addr);
err = ath10k_station_assoc(ar, arvif, sta, true);
if (err)
- ath10k_warn("failed to reassociate station: %pM\n",
+ ath10k_warn(ar, "failed to reassociate station: %pM\n",
sta->addr);
}
@@ -3451,31 +3516,31 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
max_num_peers = TARGET_NUM_PEERS;
if (ar->num_peers >= max_num_peers) {
- ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n",
+ ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n",
ar->num_peers, max_num_peers);
ret = -ENOBUFS;
goto exit;
}
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer create %pM (new sta) num_peers %d\n",
arvif->vdev_id, sta->addr, ar->num_peers);
ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
if (ret)
- ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n",
+ ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
sta->addr, arvif->vdev_id, ret);
} else if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)) {
/*
* Existing station deletion.
*/
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer delete %pM (sta gone)\n",
arvif->vdev_id, sta->addr);
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
if (ret)
- ath10k_warn("failed to delete peer %pM for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
sta->addr, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION)
@@ -3487,12 +3552,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/*
* New association.
*/
- ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
sta->addr);
ret = ath10k_station_assoc(ar, arvif, sta, false);
if (ret)
- ath10k_warn("failed to associate station %pM for vdev %i: %i\n",
+ ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH &&
@@ -3501,12 +3566,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/*
* Disassociation.
*/
- ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
sta->addr);
ret = ath10k_station_disassoc(ar, arvif, sta);
if (ret)
- ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n",
+ ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
}
exit:
@@ -3554,7 +3619,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
WMI_STA_PS_PARAM_UAPSD,
arvif->u.sta.uapsd);
if (ret) {
- ath10k_warn("failed to set uapsd params: %d\n", ret);
+ ath10k_warn(ar, "failed to set uapsd params: %d\n", ret);
goto exit;
}
@@ -3567,7 +3632,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
WMI_STA_PS_PARAM_RX_WAKE_POLICY,
value);
if (ret)
- ath10k_warn("failed to set rx wake param: %d\n", ret);
+ ath10k_warn(ar, "failed to set rx wake param: %d\n", ret);
exit:
return ret;
@@ -3617,13 +3682,13 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
/* FIXME: FW accepts wmm params per hw, not per vif */
ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
if (ret) {
- ath10k_warn("failed to set wmm params: %d\n", ret);
+ ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
goto exit;
}
ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
if (ret)
- ath10k_warn("failed to set sta uapsd: %d\n", ret);
+ ath10k_warn(ar, "failed to set sta uapsd: %d\n", ret);
exit:
mutex_unlock(&ar->conf_mutex);
@@ -3641,27 +3706,33 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_start_scan_arg arg;
- int ret;
+ int ret = 0;
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
- if (ar->scan.in_progress) {
- spin_unlock_bh(&ar->data_lock);
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ reinit_completion(&ar->scan.started);
+ reinit_completion(&ar->scan.completed);
+ reinit_completion(&ar->scan.on_channel);
+ ar->scan.state = ATH10K_SCAN_STARTING;
+ ar->scan.is_roc = true;
+ ar->scan.vdev_id = arvif->vdev_id;
+ ar->scan.roc_freq = chan->center_freq;
+ ret = 0;
+ break;
+ case ATH10K_SCAN_STARTING:
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
ret = -EBUSY;
- goto exit;
+ break;
}
-
- reinit_completion(&ar->scan.started);
- reinit_completion(&ar->scan.completed);
- reinit_completion(&ar->scan.on_channel);
- ar->scan.in_progress = true;
- ar->scan.aborting = false;
- ar->scan.is_roc = true;
- ar->scan.vdev_id = arvif->vdev_id;
- ar->scan.roc_freq = chan->center_freq;
spin_unlock_bh(&ar->data_lock);
+ if (ret)
+ goto exit;
+
memset(&arg, 0, sizeof(arg));
ath10k_wmi_start_scan_init(ar, &arg);
arg.vdev_id = arvif->vdev_id;
@@ -3676,17 +3747,21 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
ret = ath10k_start_scan(ar, &arg);
if (ret) {
- ath10k_warn("failed to start roc scan: %d\n", ret);
+ ath10k_warn(ar, "failed to start roc scan: %d\n", ret);
spin_lock_bh(&ar->data_lock);
- ar->scan.in_progress = false;
+ ar->scan.state = ATH10K_SCAN_IDLE;
spin_unlock_bh(&ar->data_lock);
goto exit;
}
ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ);
if (ret == 0) {
- ath10k_warn("failed to switch to channel for roc scan\n");
- ath10k_abort_scan(ar);
+ ath10k_warn(ar, "failed to switch to channel for roc scan\n");
+
+ ret = ath10k_scan_stop(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to stop scan: %d\n", ret);
+
ret = -ETIMEDOUT;
goto exit;
}
@@ -3702,7 +3777,8 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw)
struct ath10k *ar = hw->priv;
mutex_lock(&ar->conf_mutex);
- ath10k_abort_scan(ar);
+ cancel_delayed_work_sync(&ar->scan.timeout);
+ ath10k_scan_abort(ar);
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -3721,12 +3797,12 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
mutex_lock(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
arvif->vdev_id, value);
ret = ath10k_mac_set_rts(arvif, value);
if (ret) {
- ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
break;
}
@@ -3744,12 +3820,12 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
mutex_lock(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
arvif->vdev_id, value);
ret = ath10k_mac_set_rts(arvif, value);
if (ret) {
- ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
break;
}
@@ -3789,7 +3865,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}), ATH10K_FLUSH_TIMEOUT_HZ);
if (ret <= 0 || skip)
- ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n",
+ ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n",
skip, ar->state, ret);
skip:
@@ -3824,7 +3900,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
ret = ath10k_hif_suspend(ar);
if (ret) {
- ath10k_warn("failed to suspend hif: %d\n", ret);
+ ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
goto resume;
}
@@ -3833,7 +3909,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
resume:
ret = ath10k_wmi_pdev_resume_target(ar);
if (ret)
- ath10k_warn("failed to resume target: %d\n", ret);
+ ath10k_warn(ar, "failed to resume target: %d\n", ret);
ret = 1;
exit:
@@ -3850,14 +3926,14 @@ static int ath10k_resume(struct ieee80211_hw *hw)
ret = ath10k_hif_resume(ar);
if (ret) {
- ath10k_warn("failed to resume hif: %d\n", ret);
+ ath10k_warn(ar, "failed to resume hif: %d\n", ret);
ret = 1;
goto exit;
}
ret = ath10k_wmi_pdev_resume_target(ar);
if (ret) {
- ath10k_warn("failed to resume target: %d\n", ret);
+ ath10k_warn(ar, "failed to resume target: %d\n", ret);
ret = 1;
goto exit;
}
@@ -3878,7 +3954,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw)
/* If device failed to restart it will be in a different state, e.g.
* ATH10K_STATE_WEDGED */
if (ar->state == ATH10K_STATE_RESTARTED) {
- ath10k_info("device successfully recovered\n");
+ ath10k_info(ar, "device successfully recovered\n");
ar->state = ATH10K_STATE_ON;
}
@@ -4075,7 +4151,8 @@ ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask,
}
static bool
-ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
+ath10k_bitrate_mask_rate(struct ath10k *ar,
+ const struct cfg80211_bitrate_mask *mask,
enum ieee80211_band band,
u8 *fixed_rate,
u8 *fixed_nss)
@@ -4133,7 +4210,7 @@ ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
nss <<= 4;
pream <<= 6;
- ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
pream, nss, rate);
*fixed_rate = pream | nss | rate;
@@ -4141,7 +4218,8 @@ ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
return true;
}
-static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
+static bool ath10k_get_fixed_rate_nss(struct ath10k *ar,
+ const struct cfg80211_bitrate_mask *mask,
enum ieee80211_band band,
u8 *fixed_rate,
u8 *fixed_nss)
@@ -4151,7 +4229,7 @@ static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
return true;
/* Next Check single rate is set */
- return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss);
+ return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
}
static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
@@ -4171,16 +4249,16 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
goto exit;
if (fixed_rate == WMI_FIXED_RATE_NONE)
- ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
if (force_sgi)
- ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
vdev_param = ar->wmi.vdev_param->fixed_rate;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
vdev_param, fixed_rate);
if (ret) {
- ath10k_warn("failed to set fixed rate param 0x%02x: %d\n",
+ ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
fixed_rate, ret);
ret = -EINVAL;
goto exit;
@@ -4193,7 +4271,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
vdev_param, fixed_nss);
if (ret) {
- ath10k_warn("failed to set fixed nss param %d: %d\n",
+ ath10k_warn(ar, "failed to set fixed nss param %d: %d\n",
fixed_nss, ret);
ret = -EINVAL;
goto exit;
@@ -4206,7 +4284,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
force_sgi);
if (ret) {
- ath10k_warn("failed to set sgi param %d: %d\n",
+ ath10k_warn(ar, "failed to set sgi param %d: %d\n",
force_sgi, ret);
ret = -EINVAL;
goto exit;
@@ -4235,14 +4313,14 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
return -EINVAL;
if (!ath10k_default_bitrate_mask(ar, band, mask)) {
- if (!ath10k_get_fixed_rate_nss(mask, band,
+ if (!ath10k_get_fixed_rate_nss(ar, mask, band,
&fixed_rate,
&fixed_nss))
return -EINVAL;
}
if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
- ath10k_warn("failed to force SGI usage for default rate settings\n");
+ ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
return -EINVAL;
}
@@ -4261,7 +4339,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
spin_lock_bh(&ar->data_lock);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
sta->addr, changed, sta->bandwidth, sta->rx_nss,
sta->smps_mode);
@@ -4280,7 +4358,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
bw = WMI_PEER_CHWIDTH_80MHZ;
break;
case IEEE80211_STA_RX_BW_160:
- ath10k_warn("Invalid bandwith %d in rc update for %pM\n",
+ ath10k_warn(ar, "Invalid bandwith %d in rc update for %pM\n",
sta->bandwidth, sta->addr);
bw = WMI_PEER_CHWIDTH_20MHZ;
break;
@@ -4307,7 +4385,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
smps = WMI_PEER_SMPS_DYNAMIC;
break;
case IEEE80211_SMPS_NUM_MODES:
- ath10k_warn("Invalid smps %d in sta rc update for %pM\n",
+ ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n",
sta->smps_mode, sta->addr);
smps = WMI_PEER_SMPS_PS_NONE;
break;
@@ -4339,9 +4417,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size)
{
+ struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ath10k_dbg(ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
arvif->vdev_id, sta->addr, tid, action);
switch (action) {
@@ -4489,12 +4568,12 @@ static struct ieee80211_rate ath10k_rates[] = {
#define ath10k_g_rates (ath10k_rates + 0)
#define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
-struct ath10k *ath10k_mac_create(void)
+struct ath10k *ath10k_mac_create(size_t priv_size)
{
struct ieee80211_hw *hw;
struct ath10k *ar;
- hw = ieee80211_alloc_hw(sizeof(struct ath10k), &ath10k_ops);
+ hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops);
if (!hw)
return NULL;
@@ -4669,7 +4748,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id)
ath10k_get_arvif_iter,
&arvif_iter);
if (!arvif_iter.arvif) {
- ath10k_warn("No VIF found for vdev %d\n", vdev_id);
+ ath10k_warn(ar, "No VIF found for vdev %d\n", vdev_id);
return NULL;
}
@@ -4815,19 +4894,19 @@ int ath10k_mac_register(struct ath10k *ar)
NL80211_DFS_UNSET);
if (!ar->dfs_detector)
- ath10k_warn("failed to initialise DFS pattern detector\n");
+ ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
}
ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
ath10k_reg_notifier);
if (ret) {
- ath10k_err("failed to initialise regulatory: %i\n", ret);
+ ath10k_err(ar, "failed to initialise regulatory: %i\n", ret);
goto err_free;
}
ret = ieee80211_register_hw(ar->hw);
if (ret) {
- ath10k_err("failed to register ieee80211: %d\n", ret);
+ ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
goto err_free;
}
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index ef4f843..6c80eea 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -26,12 +26,14 @@ struct ath10k_generic_iter {
int ret;
};
-struct ath10k *ath10k_mac_create(void);
+struct ath10k *ath10k_mac_create(size_t priv_size);
void ath10k_mac_destroy(struct ath10k *ar);
int ath10k_mac_register(struct ath10k *ar);
void ath10k_mac_unregister(struct ath10k *ar);
struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
-void ath10k_reset_scan(unsigned long ptr);
+void __ath10k_scan_finish(struct ath10k *ar);
+void ath10k_scan_finish(struct ath10k *ar);
+void ath10k_scan_timeout_work(struct work_struct *work);
void ath10k_offchan_tx_purge(struct ath10k *ar);
void ath10k_offchan_tx_work(struct work_struct *work);
void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 3376963..056a35a 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -44,13 +44,9 @@ enum ath10k_pci_reset_mode {
ATH10K_PCI_RESET_WARM_ONLY = 1,
};
-static unsigned int ath10k_pci_target_ps;
static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
-module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644);
-MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option");
-
module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)");
@@ -71,10 +67,7 @@ static const struct pci_device_id ath10k_pci_id_table[] = {
static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
u32 *data);
-static int ath10k_pci_post_rx(struct ath10k *ar);
-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
- int num);
-static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
+static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
static int ath10k_pci_cold_reset(struct ath10k *ar);
static int ath10k_pci_warm_reset(struct ath10k *ar);
static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
@@ -156,79 +149,175 @@ static const struct ce_attr host_ce_config_wlan[] = {
static const struct ce_pipe_config target_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
{
- .pipenum = 0,
- .pipedir = PIPEDIR_OUT,
- .nentries = 32,
- .nbytes_max = 256,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(0),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(256),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE1: target->host HTT + HTC control */
{
- .pipenum = 1,
- .pipedir = PIPEDIR_IN,
- .nentries = 32,
- .nbytes_max = 512,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(1),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(512),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE2: target->host WMI */
{
- .pipenum = 2,
- .pipedir = PIPEDIR_IN,
- .nentries = 32,
- .nbytes_max = 2048,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(2),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE3: host->target WMI */
{
- .pipenum = 3,
- .pipedir = PIPEDIR_OUT,
- .nentries = 32,
- .nbytes_max = 2048,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(3),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE4: host->target HTT */
{
- .pipenum = 4,
- .pipedir = PIPEDIR_OUT,
- .nentries = 256,
- .nbytes_max = 256,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(4),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(256),
+ .nbytes_max = __cpu_to_le32(256),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* NB: 50% of src nentries, since tx has 2 frags */
/* CE5: unused */
{
- .pipenum = 5,
- .pipedir = PIPEDIR_OUT,
- .nentries = 32,
- .nbytes_max = 2048,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(5),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE6: Reserved for target autonomous hif_memcpy */
{
- .pipenum = 6,
- .pipedir = PIPEDIR_INOUT,
- .nentries = 32,
- .nbytes_max = 4096,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(6),
+ .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(4096),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE7 used only by Host */
};
+/*
+ * Map from service/endpoint to Copy Engine.
+ * This table is derived from the CE_PCI TABLE, above.
+ * It is passed to the Target at startup for use by firmware.
+ */
+static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(0),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(1),
+ },
+ { /* not used */
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(0),
+ },
+ { /* not used */
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(1),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(4),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(1),
+ },
+
+ /* (Additions here) */
+
+ { /* must be last */
+ __cpu_to_le32(0),
+ __cpu_to_le32(0),
+ __cpu_to_le32(0),
+ },
+};
+
static bool ath10k_pci_irq_pending(struct ath10k *ar)
{
u32 cause;
@@ -270,44 +359,111 @@ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
PCIE_INTR_ENABLE_ADDRESS);
}
-static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg)
+static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar)
{
- struct ath10k *ar = arg;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- if (ar_pci->num_msi_intrs == 0) {
- if (!ath10k_pci_irq_pending(ar))
- return IRQ_NONE;
-
- ath10k_pci_disable_and_clear_legacy_irq(ar);
- }
-
- tasklet_schedule(&ar_pci->early_irq_tasklet);
-
- return IRQ_HANDLED;
+ if (ar_pci->num_msi_intrs > 1)
+ return "msi-x";
+ else if (ar_pci->num_msi_intrs == 1)
+ return "msi";
+ else
+ return "legacy";
}
-static int ath10k_pci_request_early_irq(struct ath10k *ar)
+static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
{
+ struct ath10k *ar = pipe->hif_ce_state;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
+ struct sk_buff *skb;
+ dma_addr_t paddr;
int ret;
- /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first
- * interrupt from irq vector is triggered in all cases for FW
- * indication/errors */
- ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler,
- IRQF_SHARED, "ath10k_pci (early)", ar);
+ lockdep_assert_held(&ar_pci->ce_lock);
+
+ skb = dev_alloc_skb(pipe->buf_sz);
+ if (!skb)
+ return -ENOMEM;
+
+ WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
+
+ paddr = dma_map_single(ar->dev, skb->data,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(ar->dev, paddr))) {
+ ath10k_warn(ar, "failed to dma map pci rx buf\n");
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+
+ ATH10K_SKB_CB(skb)->paddr = paddr;
+
+ ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr);
if (ret) {
- ath10k_warn("failed to request early irq: %d\n", ret);
+ ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
+ dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
return ret;
}
return 0;
}
-static void ath10k_pci_free_early_irq(struct ath10k *ar)
+static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
+{
+ struct ath10k *ar = pipe->hif_ce_state;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
+ int ret, num;
+
+ lockdep_assert_held(&ar_pci->ce_lock);
+
+ if (pipe->buf_sz == 0)
+ return;
+
+ if (!ce_pipe->dest_ring)
+ return;
+
+ num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
+ while (num--) {
+ ret = __ath10k_pci_rx_post_buf(pipe);
+ if (ret) {
+ ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
+ mod_timer(&ar_pci->rx_post_retry, jiffies +
+ ATH10K_PCI_RX_POST_RETRY_MS);
+ break;
+ }
+ }
+}
+
+static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
+{
+ struct ath10k *ar = pipe->hif_ce_state;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+ spin_lock_bh(&ar_pci->ce_lock);
+ __ath10k_pci_rx_post_pipe(pipe);
+ spin_unlock_bh(&ar_pci->ce_lock);
+}
+
+static void ath10k_pci_rx_post(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int i;
+
+ spin_lock_bh(&ar_pci->ce_lock);
+ for (i = 0; i < CE_COUNT; i++)
+ __ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
+ spin_unlock_bh(&ar_pci->ce_lock);
+}
+
+static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
{
- free_irq(ath10k_pci_priv(ar)->pdev->irq, ar);
+ struct ath10k *ar = (void *)ptr;
+
+ ath10k_pci_rx_post(ar);
}
/*
@@ -376,7 +532,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
nbytes = min_t(unsigned int, remaining_bytes,
DIAG_TRANSFER_LIMIT);
- ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, ce_data);
+ ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
if (ret != 0)
goto done;
@@ -389,10 +545,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
* convert it from Target CPU virtual address space
* to CE address space
*/
- ath10k_pci_wake(ar);
address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
address);
- ath10k_pci_sleep(ar);
ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0,
0);
@@ -448,15 +602,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
}
done:
- if (ret == 0) {
- /* Copy data from allocated DMA buf to caller's buf */
- WARN_ON_ONCE(orig_nbytes & 3);
- for (i = 0; i < orig_nbytes / sizeof(__le32); i++) {
- ((u32 *)data)[i] =
- __le32_to_cpu(((__le32 *)data_buf)[i]);
- }
- } else
- ath10k_warn("failed to read diag value at 0x%x: %d\n",
+ if (ret == 0)
+ memcpy(data, data_buf, orig_nbytes);
+ else
+ ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
address, ret);
if (data_buf)
@@ -466,17 +615,54 @@ done:
return ret;
}
+static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value)
+{
+ __le32 val = 0;
+ int ret;
+
+ ret = ath10k_pci_diag_read_mem(ar, address, &val, sizeof(val));
+ *value = __le32_to_cpu(val);
+
+ return ret;
+}
+
+static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
+ u32 src, u32 len)
+{
+ u32 host_addr, addr;
+ int ret;
+
+ host_addr = host_interest_item_address(src);
+
+ ret = ath10k_pci_diag_read32(ar, host_addr, &addr);
+ if (ret != 0) {
+ ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n",
+ src, ret);
+ return ret;
+ }
+
+ ret = ath10k_pci_diag_read_mem(ar, addr, dest, len);
+ if (ret != 0) {
+ ath10k_warn(ar, "failed to memcpy firmware memory from %d (%d B): %d\n",
+ addr, len, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+#define ath10k_pci_diag_read_hi(ar, dest, src, len) \
+ __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len);
+
/* Read 4-byte aligned data from Target memory or register */
static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
u32 *data)
{
/* Assume range doesn't cross this boundary */
if (address >= DRAM_BASE_ADDRESS)
- return ath10k_pci_diag_read_mem(ar, address, data, sizeof(u32));
+ return ath10k_pci_diag_read32(ar, address, data);
- ath10k_pci_wake(ar);
*data = ath10k_pci_read32(ar, address);
- ath10k_pci_sleep(ar);
return 0;
}
@@ -514,9 +700,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
}
/* Copy caller's data to allocated DMA buf */
- WARN_ON_ONCE(orig_nbytes & 3);
- for (i = 0; i < orig_nbytes / sizeof(__le32); i++)
- ((__le32 *)data_buf)[i] = __cpu_to_le32(((u32 *)data)[i]);
+ memcpy(data_buf, data, orig_nbytes);
/*
* The address supplied by the caller is in the
@@ -528,9 +712,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
* to
* CE address space
*/
- ath10k_pci_wake(ar);
address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address);
- ath10k_pci_sleep(ar);
remaining_bytes = orig_nbytes;
ce_data = ce_data_base;
@@ -539,7 +721,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
/* Set up to receive directly into Target(!) address */
- ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, address);
+ ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address);
if (ret != 0)
goto done;
@@ -608,66 +790,46 @@ done:
}
if (ret != 0)
- ath10k_warn("failed to write diag value at 0x%x: %d\n",
+ ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
address, ret);
return ret;
}
+static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
+{
+ __le32 val = __cpu_to_le32(value);
+
+ return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val));
+}
+
/* Write 4B data to Target memory or register */
static int ath10k_pci_diag_write_access(struct ath10k *ar, u32 address,
u32 data)
{
/* Assume range doesn't cross this boundary */
if (address >= DRAM_BASE_ADDRESS)
- return ath10k_pci_diag_write_mem(ar, address, &data,
- sizeof(u32));
+ return ath10k_pci_diag_write32(ar, address, data);
- ath10k_pci_wake(ar);
ath10k_pci_write32(ar, address, data);
- ath10k_pci_sleep(ar);
return 0;
}
-static bool ath10k_pci_target_is_awake(struct ath10k *ar)
+static bool ath10k_pci_is_awake(struct ath10k *ar)
{
- void __iomem *mem = ath10k_pci_priv(ar)->mem;
- u32 val;
- val = ioread32(mem + PCIE_LOCAL_BASE_ADDRESS +
- RTC_STATE_ADDRESS);
- return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON);
+ u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS);
+
+ return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
}
-int ath10k_do_pci_wake(struct ath10k *ar)
+static int ath10k_pci_wake_wait(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- void __iomem *pci_addr = ar_pci->mem;
int tot_delay = 0;
int curr_delay = 5;
- if (atomic_read(&ar_pci->keep_awake_count) == 0) {
- /* Force AWAKE */
- iowrite32(PCIE_SOC_WAKE_V_MASK,
- pci_addr + PCIE_LOCAL_BASE_ADDRESS +
- PCIE_SOC_WAKE_ADDRESS);
- }
- atomic_inc(&ar_pci->keep_awake_count);
-
- if (ar_pci->verified_awake)
- return 0;
-
- for (;;) {
- if (ath10k_pci_target_is_awake(ar)) {
- ar_pci->verified_awake = true;
+ while (tot_delay < PCIE_WAKE_TIMEOUT) {
+ if (ath10k_pci_is_awake(ar))
return 0;
- }
-
- if (tot_delay > PCIE_WAKE_TIMEOUT) {
- ath10k_warn("target took longer %d us to wake up (awake count %d)\n",
- PCIE_WAKE_TIMEOUT,
- atomic_read(&ar_pci->keep_awake_count));
- return -ETIMEDOUT;
- }
udelay(curr_delay);
tot_delay += curr_delay;
@@ -675,20 +837,21 @@ int ath10k_do_pci_wake(struct ath10k *ar)
if (curr_delay < 50)
curr_delay += 5;
}
+
+ return -ETIMEDOUT;
}
-void ath10k_do_pci_sleep(struct ath10k *ar)
+static int ath10k_pci_wake(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- void __iomem *pci_addr = ar_pci->mem;
+ ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
+ PCIE_SOC_WAKE_V_MASK);
+ return ath10k_pci_wake_wait(ar);
+}
- if (atomic_dec_and_test(&ar_pci->keep_awake_count)) {
- /* Allow sleep */
- ar_pci->verified_awake = false;
- iowrite32(PCIE_SOC_WAKE_RESET,
- pci_addr + PCIE_LOCAL_BASE_ADDRESS +
- PCIE_SOC_WAKE_ADDRESS);
- }
+static void ath10k_pci_sleep(struct ath10k *ar)
+{
+ ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
+ PCIE_SOC_WAKE_RESET);
}
/* Called by lower (CE) layer when a send to Target completes. */
@@ -726,19 +889,17 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
unsigned int nbytes, max_nbytes;
unsigned int transfer_id;
unsigned int flags;
- int err, num_replenish = 0;
while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
&ce_data, &nbytes, &transfer_id,
&flags) == 0) {
- num_replenish++;
skb = transfer_context;
max_nbytes = skb->len + skb_tailroom(skb);
dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
max_nbytes, DMA_FROM_DEVICE);
if (unlikely(max_nbytes < nbytes)) {
- ath10k_warn("rxed more than expected (nbytes %d, max %d)",
+ ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)",
nbytes, max_nbytes);
dev_kfree_skb_any(skb);
continue;
@@ -748,12 +909,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
cb->rx_completion(ar, skb, pipe_info->pipe_num);
}
- err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish);
- if (unlikely(err)) {
- /* FIXME: retry */
- ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n",
- pipe_info->pipe_num, num_replenish, err);
- }
+ ath10k_pci_rx_post_pipe(pipe_info);
}
static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
@@ -781,10 +937,10 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
}
for (i = 0; i < n_items - 1; i++) {
- ath10k_dbg(ATH10K_DBG_PCI,
+ ath10k_dbg(ar, ATH10K_DBG_PCI,
"pci tx item %d paddr 0x%08x len %d n_items %d\n",
i, items[i].paddr, items[i].len, n_items);
- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
items[i].vaddr, items[i].len);
err = ath10k_ce_send_nolock(ce_pipe,
@@ -799,10 +955,10 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
/* `i` is equal to `n_items -1` after for() */
- ath10k_dbg(ATH10K_DBG_PCI,
+ ath10k_dbg(ar, ATH10K_DBG_PCI,
"pci tx item %d paddr 0x%08x len %d n_items %d\n",
i, items[i].paddr, items[i].len, n_items);
- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
items[i].vaddr, items[i].len);
err = ath10k_ce_send_nolock(ce_pipe,
@@ -829,52 +985,64 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get free queue number\n");
return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
}
-static void ath10k_pci_hif_dump_area(struct ath10k *ar)
+static void ath10k_pci_dump_registers(struct ath10k *ar,
+ struct ath10k_fw_crash_data *crash_data)
{
- u32 reg_dump_area = 0;
- u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
- u32 host_addr;
- int ret;
- u32 i;
+ __le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
+ int i, ret;
- ath10k_err("firmware crashed!\n");
- ath10k_err("hardware name %s version 0x%x\n",
- ar->hw_params.name, ar->target_version);
- ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
+ lockdep_assert_held(&ar->data_lock);
- host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
- ret = ath10k_pci_diag_read_mem(ar, host_addr,
- &reg_dump_area, sizeof(u32));
+ ret = ath10k_pci_diag_read_hi(ar, &reg_dump_values[0],
+ hi_failure_state,
+ REG_DUMP_COUNT_QCA988X * sizeof(__le32));
if (ret) {
- ath10k_err("failed to read FW dump area address: %d\n", ret);
- return;
- }
-
- ath10k_err("target register Dump Location: 0x%08X\n", reg_dump_area);
-
- ret = ath10k_pci_diag_read_mem(ar, reg_dump_area,
- &reg_dump_values[0],
- REG_DUMP_COUNT_QCA988X * sizeof(u32));
- if (ret != 0) {
- ath10k_err("failed to read FW dump area: %d\n", ret);
+ ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
return;
}
BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
- ath10k_err("target Register Dump\n");
+ ath10k_err(ar, "firmware register dump:\n");
for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4)
- ath10k_err("[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
+ ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
i,
- reg_dump_values[i],
- reg_dump_values[i + 1],
- reg_dump_values[i + 2],
- reg_dump_values[i + 3]);
+ __le32_to_cpu(reg_dump_values[i]),
+ __le32_to_cpu(reg_dump_values[i + 1]),
+ __le32_to_cpu(reg_dump_values[i + 2]),
+ __le32_to_cpu(reg_dump_values[i + 3]));
+
+ if (!crash_data)
+ return;
+
+ for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++)
+ crash_data->registers[i] = reg_dump_values[i];
+}
+
+static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+{
+ struct ath10k_fw_crash_data *crash_data;
+ char uuid[50];
+
+ spin_lock_bh(&ar->data_lock);
+
+ crash_data = ath10k_debug_get_new_fw_crash_data(ar);
+
+ if (crash_data)
+ scnprintf(uuid, sizeof(uuid), "%pUl", &crash_data->uuid);
+ else
+ scnprintf(uuid, sizeof(uuid), "n/a");
+
+ ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid);
+ ath10k_print_driver_info(ar);
+ ath10k_pci_dump_registers(ar, crash_data);
+
+ spin_unlock_bh(&ar->data_lock);
queue_work(ar->workqueue, &ar->restart_work);
}
@@ -882,7 +1050,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
int force)
{
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
if (!force) {
int resources;
@@ -910,43 +1078,12 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n");
memcpy(&ar_pci->msg_callbacks_current, callbacks,
sizeof(ar_pci->msg_callbacks_current));
}
-static int ath10k_pci_setup_ce_irq(struct ath10k *ar)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- const struct ce_attr *attr;
- struct ath10k_pci_pipe *pipe_info;
- int pipe_num, disable_interrupts;
-
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
-
- /* Handle Diagnostic CE specially */
- if (pipe_info->ce_hdl == ar_pci->ce_diag)
- continue;
-
- attr = &host_ce_config_wlan[pipe_num];
-
- if (attr->src_nentries) {
- disable_interrupts = attr->flags & CE_ATTR_DIS_INTR;
- ath10k_ce_send_cb_register(pipe_info->ce_hdl,
- ath10k_pci_ce_send_done,
- disable_interrupts);
- }
-
- if (attr->dest_nentries)
- ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
- ath10k_pci_ce_recv_data);
- }
-
- return 0;
-}
-
static void ath10k_pci_kill_tasklet(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -954,74 +1091,64 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
tasklet_kill(&ar_pci->intr_tq);
tasklet_kill(&ar_pci->msi_fw_err);
- tasklet_kill(&ar_pci->early_irq_tasklet);
for (i = 0; i < CE_COUNT; i++)
tasklet_kill(&ar_pci->pipe_info[i].intr);
+
+ del_timer_sync(&ar_pci->rx_post_retry);
}
-/* TODO - temporary mapping while we have too few CE's */
static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
u16 service_id, u8 *ul_pipe,
u8 *dl_pipe, int *ul_is_polled,
int *dl_is_polled)
{
- int ret = 0;
+ const struct service_to_pipe *entry;
+ bool ul_set = false, dl_set = false;
+ int i;
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n");
/* polling for received messages not supported */
*dl_is_polled = 0;
- switch (service_id) {
- case ATH10K_HTC_SVC_ID_HTT_DATA_MSG:
- /*
- * Host->target HTT gets its own pipe, so it can be polled
- * while other pipes are interrupt driven.
- */
- *ul_pipe = 4;
- /*
- * Use the same target->host pipe for HTC ctrl, HTC raw
- * streams, and HTT.
- */
- *dl_pipe = 1;
- break;
+ for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
+ entry = &target_service_to_ce_map_wlan[i];
- case ATH10K_HTC_SVC_ID_RSVD_CTRL:
- case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS:
- /*
- * Note: HTC_RAW_STREAMS_SVC is currently unused, and
- * HTC_CTRL_RSVD_SVC could share the same pipe as the
- * WMI services. So, if another CE is needed, change
- * this to *ul_pipe = 3, which frees up CE 0.
- */
- /* *ul_pipe = 3; */
- *ul_pipe = 0;
- *dl_pipe = 1;
- break;
-
- case ATH10K_HTC_SVC_ID_WMI_DATA_BK:
- case ATH10K_HTC_SVC_ID_WMI_DATA_BE:
- case ATH10K_HTC_SVC_ID_WMI_DATA_VI:
- case ATH10K_HTC_SVC_ID_WMI_DATA_VO:
+ if (__le32_to_cpu(entry->service_id) != service_id)
+ continue;
- case ATH10K_HTC_SVC_ID_WMI_CONTROL:
- *ul_pipe = 3;
- *dl_pipe = 2;
- break;
+ switch (__le32_to_cpu(entry->pipedir)) {
+ case PIPEDIR_NONE:
+ break;
+ case PIPEDIR_IN:
+ WARN_ON(dl_set);
+ *dl_pipe = __le32_to_cpu(entry->pipenum);
+ dl_set = true;
+ break;
+ case PIPEDIR_OUT:
+ WARN_ON(ul_set);
+ *ul_pipe = __le32_to_cpu(entry->pipenum);
+ ul_set = true;
+ break;
+ case PIPEDIR_INOUT:
+ WARN_ON(dl_set);
+ WARN_ON(ul_set);
+ *dl_pipe = __le32_to_cpu(entry->pipenum);
+ *ul_pipe = __le32_to_cpu(entry->pipenum);
+ dl_set = true;
+ ul_set = true;
+ break;
+ }
+ }
- /* pipe 5 unused */
- /* pipe 6 reserved */
- /* pipe 7 reserved */
+ if (WARN_ON(!ul_set || !dl_set))
+ return -ENOENT;
- default:
- ret = -1;
- break;
- }
*ul_is_polled =
(host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0;
- return ret;
+ return 0;
}
static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
@@ -1029,7 +1156,7 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
{
int ul_is_polled, dl_is_polled;
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
(void)ath10k_pci_hif_map_service_to_pipe(ar,
ATH10K_HTC_SVC_ID_RSVD_CTRL,
@@ -1039,141 +1166,48 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
&dl_is_polled);
}
-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
- int num)
+static void ath10k_pci_irq_disable(struct ath10k *ar)
{
- struct ath10k *ar = pipe_info->hif_ce_state;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl;
- struct sk_buff *skb;
- dma_addr_t ce_data;
- int i, ret = 0;
-
- if (pipe_info->buf_sz == 0)
- return 0;
-
- for (i = 0; i < num; i++) {
- skb = dev_alloc_skb(pipe_info->buf_sz);
- if (!skb) {
- ath10k_warn("failed to allocate skbuff for pipe %d\n",
- num);
- ret = -ENOMEM;
- goto err;
- }
-
- WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
-
- ce_data = dma_map_single(ar->dev, skb->data,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
-
- if (unlikely(dma_mapping_error(ar->dev, ce_data))) {
- ath10k_warn("failed to DMA map sk_buff\n");
- dev_kfree_skb_any(skb);
- ret = -EIO;
- goto err;
- }
-
- ATH10K_SKB_CB(skb)->paddr = ce_data;
-
- pci_dma_sync_single_for_device(ar_pci->pdev, ce_data,
- pipe_info->buf_sz,
- PCI_DMA_FROMDEVICE);
+ int i;
- ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb,
- ce_data);
- if (ret) {
- ath10k_warn("failed to enqueue to pipe %d: %d\n",
- num, ret);
- goto err;
- }
- }
+ ath10k_ce_disable_interrupts(ar);
- return ret;
+ /* Regardless how many interrupts were assigned for MSI the first one
+ * is always used for firmware indications (crashes). There's no way to
+ * mask the irq in the device so call disable_irq(). Legacy (shared)
+ * interrupts can be masked on the device though.
+ */
+ if (ar_pci->num_msi_intrs > 0)
+ disable_irq(ar_pci->pdev->irq);
+ else
+ ath10k_pci_disable_and_clear_legacy_irq(ar);
-err:
- ath10k_pci_rx_pipe_cleanup(pipe_info);
- return ret;
+ for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
+ synchronize_irq(ar_pci->pdev->irq + i);
}
-static int ath10k_pci_post_rx(struct ath10k *ar)
+static void ath10k_pci_irq_enable(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_pci_pipe *pipe_info;
- const struct ce_attr *attr;
- int pipe_num, ret = 0;
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
- attr = &host_ce_config_wlan[pipe_num];
-
- if (attr->dest_nentries == 0)
- continue;
-
- ret = ath10k_pci_post_rx_pipe(pipe_info,
- attr->dest_nentries - 1);
- if (ret) {
- ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
- pipe_num, ret);
-
- for (; pipe_num >= 0; pipe_num--) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
- ath10k_pci_rx_pipe_cleanup(pipe_info);
- }
- return ret;
- }
- }
+ ath10k_ce_enable_interrupts(ar);
- return 0;
+ /* See comment in ath10k_pci_irq_disable() */
+ if (ar_pci->num_msi_intrs > 0)
+ enable_irq(ar_pci->pdev->irq);
+ else
+ ath10k_pci_enable_legacy_irq(ar);
}
static int ath10k_pci_hif_start(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- int ret, ret_early;
-
- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n");
-
- ath10k_pci_free_early_irq(ar);
- ath10k_pci_kill_tasklet(ar);
-
- ret = ath10k_pci_request_irq(ar);
- if (ret) {
- ath10k_warn("failed to post RX buffers for all pipes: %d\n",
- ret);
- goto err_early_irq;
- }
-
- ret = ath10k_pci_setup_ce_irq(ar);
- if (ret) {
- ath10k_warn("failed to setup CE interrupts: %d\n", ret);
- goto err_stop;
- }
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
- /* Post buffers once to start things off. */
- ret = ath10k_pci_post_rx(ar);
- if (ret) {
- ath10k_warn("failed to post RX buffers for all pipes: %d\n",
- ret);
- goto err_stop;
- }
+ ath10k_pci_irq_enable(ar);
+ ath10k_pci_rx_post(ar);
- ar_pci->started = 1;
return 0;
-
-err_stop:
- ath10k_ce_disable_interrupts(ar);
- ath10k_pci_free_irq(ar);
- ath10k_pci_kill_tasklet(ar);
-err_early_irq:
- /* Though there should be no interrupts (device was reset)
- * power_down() expects the early IRQ to be installed as per the
- * driver lifecycle. */
- ret_early = ath10k_pci_request_early_irq(ar);
- if (ret_early)
- ath10k_warn("failed to re-enable early irq: %d\n", ret_early);
-
- return ret;
}
static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
@@ -1193,10 +1227,6 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
ar = pipe_info->hif_ce_state;
ar_pci = ath10k_pci_priv(ar);
-
- if (!ar_pci->started)
- return;
-
ce_hdl = pipe_info->ce_hdl;
while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf,
@@ -1227,10 +1257,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
ar = pipe_info->hif_ce_state;
ar_pci = ath10k_pci_priv(ar);
-
- if (!ar_pci->started)
- return;
-
ce_hdl = pipe_info->ce_hdl;
while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf,
@@ -1275,41 +1301,24 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
ath10k_ce_deinit_pipe(ar, i);
}
-static void ath10k_pci_hif_stop(struct ath10k *ar)
+static void ath10k_pci_flush(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- int ret;
-
- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n");
-
- if (WARN_ON(!ar_pci->started))
- return;
-
- ret = ath10k_ce_disable_interrupts(ar);
- if (ret)
- ath10k_warn("failed to disable CE interrupts: %d\n", ret);
-
- ath10k_pci_free_irq(ar);
ath10k_pci_kill_tasklet(ar);
+ ath10k_pci_buffer_cleanup(ar);
+}
- ret = ath10k_pci_request_early_irq(ar);
- if (ret)
- ath10k_warn("failed to re-enable early irq: %d\n", ret);
-
- /* At this point, asynchronous threads are stopped, the target should
- * not DMA nor interrupt. We process the leftovers and then free
- * everything else up. */
+static void ath10k_pci_hif_stop(struct ath10k *ar)
+{
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
- ath10k_pci_buffer_cleanup(ar);
+ ath10k_pci_irq_disable(ar);
+ ath10k_pci_flush(ar);
- /* Make the sure the device won't access any structures on the host by
- * resetting it. The device was fed with PCI CE ringbuffer
- * configuration during init. If ringbuffers are freed and the device
- * were to access them this could lead to memory corruption on the
- * host. */
+ /* Most likely the device has HTT Rx ring configured. The only way to
+ * prevent the device from accessing (and possible corrupting) host
+ * memory is to reset the chip now.
+ */
ath10k_pci_warm_reset(ar);
-
- ar_pci->started = 0;
}
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
@@ -1360,7 +1369,7 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
xfer.wait_for_resp = true;
xfer.resp_len = 0;
- ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr);
+ ath10k_ce_rx_post_buf(ce_rx, &xfer, resp_paddr);
}
ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0);
@@ -1418,6 +1427,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)
static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
{
+ struct ath10k *ar = ce_state->ar;
struct bmi_xfer *xfer;
u32 ce_data;
unsigned int nbytes;
@@ -1429,7 +1439,7 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
return;
if (!xfer->wait_for_resp) {
- ath10k_warn("unexpected: BMI data received; ignoring\n");
+ ath10k_warn(ar, "unexpected: BMI data received; ignoring\n");
return;
}
@@ -1457,102 +1467,6 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
}
/*
- * Map from service/endpoint to Copy Engine.
- * This table is derived from the CE_PCI TABLE, above.
- * It is passed to the Target at startup for use by firmware.
- */
-static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_VO,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_VO,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_BK,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_BK,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_BE,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_BE,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_VI,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_VI,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_CONTROL,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_CONTROL,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_RSVD_CTRL,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 0, /* could be moved to 3 (share with WMI) */
- },
- {
- ATH10K_HTC_SVC_ID_RSVD_CTRL,
- PIPEDIR_IN, /* in = DL = target -> host */
- 1,
- },
- {
- ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */
- PIPEDIR_OUT, /* out = UL = host -> target */
- 0,
- },
- {
- ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */
- PIPEDIR_IN, /* in = DL = target -> host */
- 1,
- },
- {
- ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 4,
- },
- {
- ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
- PIPEDIR_IN, /* in = DL = target -> host */
- 1,
- },
-
- /* (Additions here) */
-
- { /* Must be last */
- 0,
- 0,
- 0,
- },
-};
-
-/*
* Send an interrupt to the device to wake up the Target CPU
* so it has an opportunity to notice any changed state.
*/
@@ -1565,7 +1479,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
CORE_CTRL_ADDRESS,
&core_ctrl);
if (ret) {
- ath10k_warn("failed to read core_ctrl: %d\n", ret);
+ ath10k_warn(ar, "failed to read core_ctrl: %d\n", ret);
return ret;
}
@@ -1576,7 +1490,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
CORE_CTRL_ADDRESS,
core_ctrl);
if (ret) {
- ath10k_warn("failed to set target CPU interrupt mask: %d\n",
+ ath10k_warn(ar, "failed to set target CPU interrupt mask: %d\n",
ret);
return ret;
}
@@ -1605,13 +1519,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_read_access(ar, interconnect_targ_addr,
&pcie_state_targ_addr);
if (ret != 0) {
- ath10k_err("Failed to get pcie state addr: %d\n", ret);
+ ath10k_err(ar, "Failed to get pcie state addr: %d\n", ret);
return ret;
}
if (pcie_state_targ_addr == 0) {
ret = -EIO;
- ath10k_err("Invalid pcie state addr\n");
+ ath10k_err(ar, "Invalid pcie state addr\n");
return ret;
}
@@ -1620,13 +1534,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
pipe_cfg_addr),
&pipe_cfg_targ_addr);
if (ret != 0) {
- ath10k_err("Failed to get pipe cfg addr: %d\n", ret);
+ ath10k_err(ar, "Failed to get pipe cfg addr: %d\n", ret);
return ret;
}
if (pipe_cfg_targ_addr == 0) {
ret = -EIO;
- ath10k_err("Invalid pipe cfg addr\n");
+ ath10k_err(ar, "Invalid pipe cfg addr\n");
return ret;
}
@@ -1635,7 +1549,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
sizeof(target_ce_config_wlan));
if (ret != 0) {
- ath10k_err("Failed to write pipe cfg: %d\n", ret);
+ ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret);
return ret;
}
@@ -1644,13 +1558,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
svc_to_pipe_map),
&svc_to_pipe_map);
if (ret != 0) {
- ath10k_err("Failed to get svc/pipe map: %d\n", ret);
+ ath10k_err(ar, "Failed to get svc/pipe map: %d\n", ret);
return ret;
}
if (svc_to_pipe_map == 0) {
ret = -EIO;
- ath10k_err("Invalid svc_to_pipe map\n");
+ ath10k_err(ar, "Invalid svc_to_pipe map\n");
return ret;
}
@@ -1658,7 +1572,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
target_service_to_ce_map_wlan,
sizeof(target_service_to_ce_map_wlan));
if (ret != 0) {
- ath10k_err("Failed to write svc/pipe map: %d\n", ret);
+ ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret);
return ret;
}
@@ -1667,18 +1581,17 @@ static int ath10k_pci_init_config(struct ath10k *ar)
config_flags),
&pcie_config_flags);
if (ret != 0) {
- ath10k_err("Failed to get pcie config_flags: %d\n", ret);
+ ath10k_err(ar, "Failed to get pcie config_flags: %d\n", ret);
return ret;
}
pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1;
- ret = ath10k_pci_diag_write_mem(ar, pcie_state_targ_addr +
+ ret = ath10k_pci_diag_write_access(ar, pcie_state_targ_addr +
offsetof(struct pcie_state, config_flags),
- &pcie_config_flags,
- sizeof(pcie_config_flags));
+ pcie_config_flags);
if (ret != 0) {
- ath10k_err("Failed to write pcie config_flags: %d\n", ret);
+ ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret);
return ret;
}
@@ -1687,7 +1600,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_read_access(ar, ealloc_targ_addr, &ealloc_value);
if (ret != 0) {
- ath10k_err("Faile to get early alloc val: %d\n", ret);
+ ath10k_err(ar, "Faile to get early alloc val: %d\n", ret);
return ret;
}
@@ -1699,7 +1612,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_write_access(ar, ealloc_targ_addr, ealloc_value);
if (ret != 0) {
- ath10k_err("Failed to set early alloc val: %d\n", ret);
+ ath10k_err(ar, "Failed to set early alloc val: %d\n", ret);
return ret;
}
@@ -1708,7 +1621,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_read_access(ar, flag2_targ_addr, &flag2_value);
if (ret != 0) {
- ath10k_err("Failed to get option val: %d\n", ret);
+ ath10k_err(ar, "Failed to get option val: %d\n", ret);
return ret;
}
@@ -1716,7 +1629,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_write_access(ar, flag2_targ_addr, flag2_value);
if (ret != 0) {
- ath10k_err("Failed to set option val: %d\n", ret);
+ ath10k_err(ar, "Failed to set option val: %d\n", ret);
return ret;
}
@@ -1730,7 +1643,7 @@ static int ath10k_pci_alloc_ce(struct ath10k *ar)
for (i = 0; i < CE_COUNT; i++) {
ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
if (ret) {
- ath10k_err("failed to allocate copy engine pipe %d: %d\n",
+ ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
i, ret);
return ret;
}
@@ -1761,9 +1674,11 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
pipe_info->hif_ce_state = ar;
attr = &host_ce_config_wlan[pipe_num];
- ret = ath10k_ce_init_pipe(ar, pipe_num, attr);
+ ret = ath10k_ce_init_pipe(ar, pipe_num, attr,
+ ath10k_pci_ce_send_done,
+ ath10k_pci_ce_recv_data);
if (ret) {
- ath10k_err("failed to initialize copy engine pipe %d: %d\n",
+ ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
pipe_num, ret);
return ret;
}
@@ -1783,32 +1698,19 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
return 0;
}
-static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
+static bool ath10k_pci_has_fw_crashed(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- u32 fw_indicator;
-
- ath10k_pci_wake(ar);
-
- fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
-
- if (fw_indicator & FW_IND_EVENT_PENDING) {
- /* ACK: clear Target-side pending event */
- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
- fw_indicator & ~FW_IND_EVENT_PENDING);
+ return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) &
+ FW_IND_EVENT_PENDING;
+}
- if (ar_pci->started) {
- ath10k_pci_hif_dump_area(ar);
- } else {
- /*
- * Probable Target failure before we're prepared
- * to handle it. Generally unexpected.
- */
- ath10k_warn("early firmware event indicated\n");
- }
- }
+static void ath10k_pci_fw_crashed_clear(struct ath10k *ar)
+{
+ u32 val;
- ath10k_pci_sleep(ar);
+ val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
+ val &= ~FW_IND_EVENT_PENDING;
+ ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
}
/* this function effectively clears target memory controller assert line */
@@ -1833,25 +1735,19 @@ static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
static int ath10k_pci_warm_reset(struct ath10k *ar)
{
- int ret = 0;
u32 val;
- ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n");
-
- ret = ath10k_do_pci_wake(ar);
- if (ret) {
- ath10k_err("failed to wake up target: %d\n", ret);
- return ret;
- }
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n");
/* debug */
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_CAUSE_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n",
+ val);
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
CPU_INTR_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
val);
/* disable pending irqs */
@@ -1894,11 +1790,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
/* debug */
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_CAUSE_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n",
+ val);
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
CPU_INTR_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
val);
/* CPU warm reset */
@@ -1909,20 +1806,18 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
SOC_RESET_CONTROL_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n",
+ val);
msleep(100);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n");
- ath10k_do_pci_sleep(ar);
- return ret;
+ return 0;
}
static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- const char *irq_mode;
int ret;
/*
@@ -1941,80 +1836,39 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
ret = ath10k_pci_warm_reset(ar);
if (ret) {
- ath10k_err("failed to reset target: %d\n", ret);
+ ath10k_err(ar, "failed to reset target: %d\n", ret);
goto err;
}
- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- /* Force AWAKE forever */
- ath10k_do_pci_wake(ar);
-
ret = ath10k_pci_ce_init(ar);
if (ret) {
- ath10k_err("failed to initialize CE: %d\n", ret);
- goto err_ps;
- }
-
- ret = ath10k_ce_disable_interrupts(ar);
- if (ret) {
- ath10k_err("failed to disable CE interrupts: %d\n", ret);
- goto err_ce;
- }
-
- ret = ath10k_pci_init_irq(ar);
- if (ret) {
- ath10k_err("failed to init irqs: %d\n", ret);
- goto err_ce;
- }
-
- ret = ath10k_pci_request_early_irq(ar);
- if (ret) {
- ath10k_err("failed to request early irq: %d\n", ret);
- goto err_deinit_irq;
+ ath10k_err(ar, "failed to initialize CE: %d\n", ret);
+ goto err;
}
ret = ath10k_pci_wait_for_target_init(ar);
if (ret) {
- ath10k_err("failed to wait for target to init: %d\n", ret);
- goto err_free_early_irq;
+ ath10k_err(ar, "failed to wait for target to init: %d\n", ret);
+ goto err_ce;
}
ret = ath10k_pci_init_config(ar);
if (ret) {
- ath10k_err("failed to setup init config: %d\n", ret);
- goto err_free_early_irq;
+ ath10k_err(ar, "failed to setup init config: %d\n", 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_free_early_irq;
+ ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
+ goto err_ce;
}
- if (ar_pci->num_msi_intrs > 1)
- irq_mode = "MSI-X";
- else if (ar_pci->num_msi_intrs == 1)
- irq_mode = "MSI";
- else
- irq_mode = "legacy";
-
- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
- ath10k_info("pci irq %s irq_mode %d reset_mode %d\n",
- irq_mode, ath10k_pci_irq_mode,
- ath10k_pci_reset_mode);
-
return 0;
-err_free_early_irq:
- ath10k_pci_free_early_irq(ar);
-err_deinit_irq:
- ath10k_pci_deinit_irq(ar);
err_ce:
ath10k_pci_ce_deinit(ar);
ath10k_pci_warm_reset(ar);
-err_ps:
- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- ath10k_do_pci_sleep(ar);
err:
return ret;
}
@@ -2034,7 +1888,7 @@ static int ath10k_pci_hif_power_up_warm(struct ath10k *ar)
if (ret == 0)
break;
- ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n",
+ ath10k_warn(ar, "failed to warm reset (attempt %d out of %d): %d\n",
i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret);
}
@@ -2045,7 +1899,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
{
int ret;
- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
/*
* Hardware CUS232 version 2 has some issues with cold reset and the
@@ -2057,17 +1911,17 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
*/
ret = ath10k_pci_hif_power_up_warm(ar);
if (ret) {
- ath10k_warn("failed to power up target using warm reset: %d\n",
+ ath10k_warn(ar, "failed to power up target using warm reset: %d\n",
ret);
if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY)
return ret;
- ath10k_warn("trying cold reset\n");
+ ath10k_warn(ar, "trying cold reset\n");
ret = __ath10k_pci_hif_power_up(ar, true);
if (ret) {
- ath10k_err("failed to power up target using cold reset too (%d)\n",
+ ath10k_err(ar, "failed to power up target using cold reset too (%d)\n",
ret);
return ret;
}
@@ -2078,18 +1932,9 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
static void ath10k_pci_hif_power_down(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
- ath10k_pci_free_early_irq(ar);
- ath10k_pci_kill_tasklet(ar);
- ath10k_pci_deinit_irq(ar);
- ath10k_pci_ce_deinit(ar);
ath10k_pci_warm_reset(ar);
-
- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- ath10k_do_pci_sleep(ar);
}
#ifdef CONFIG_PM
@@ -2171,7 +2016,13 @@ static void ath10k_msi_err_tasklet(unsigned long data)
{
struct ath10k *ar = (struct ath10k *)data;
- ath10k_pci_fw_interrupt_handler(ar);
+ if (!ath10k_pci_has_fw_crashed(ar)) {
+ ath10k_warn(ar, "received unsolicited fw crash interrupt\n");
+ return;
+ }
+
+ ath10k_pci_fw_crashed_clear(ar);
+ ath10k_pci_fw_crashed_dump(ar);
}
/*
@@ -2185,7 +2036,8 @@ static irqreturn_t ath10k_pci_per_engine_handler(int irq, void *arg)
int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL;
if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) {
- ath10k_warn("unexpected/invalid irq %d ce_id %d\n", irq, ce_id);
+ ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
+ ce_id);
return IRQ_HANDLED;
}
@@ -2232,36 +2084,17 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-static void ath10k_pci_early_irq_tasklet(unsigned long data)
+static void ath10k_pci_tasklet(unsigned long data)
{
struct ath10k *ar = (struct ath10k *)data;
- u32 fw_ind;
- int ret;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_warn("failed to wake target in early irq tasklet: %d\n",
- ret);
+ if (ath10k_pci_has_fw_crashed(ar)) {
+ ath10k_pci_fw_crashed_clear(ar);
+ ath10k_pci_fw_crashed_dump(ar);
return;
}
- fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
- if (fw_ind & FW_IND_EVENT_PENDING) {
- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
- fw_ind & ~FW_IND_EVENT_PENDING);
- ath10k_pci_hif_dump_area(ar);
- }
-
- ath10k_pci_sleep(ar);
- ath10k_pci_enable_legacy_irq(ar);
-}
-
-static void ath10k_pci_tasklet(unsigned long data)
-{
- struct ath10k *ar = (struct ath10k *)data;
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */
ath10k_ce_per_engine_service_any(ar);
/* Re-enable legacy irq that was disabled in the irq handler */
@@ -2278,7 +2111,7 @@ static int ath10k_pci_request_irq_msix(struct ath10k *ar)
ath10k_pci_msi_fw_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
- ath10k_warn("failed to request MSI-X fw irq %d: %d\n",
+ ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n",
ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
return ret;
}
@@ -2288,7 +2121,7 @@ static int ath10k_pci_request_irq_msix(struct ath10k *ar)
ath10k_pci_per_engine_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
- ath10k_warn("failed to request MSI-X ce irq %d: %d\n",
+ ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n",
ar_pci->pdev->irq + i, ret);
for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
@@ -2311,7 +2144,7 @@ static int ath10k_pci_request_irq_msi(struct ath10k *ar)
ath10k_pci_interrupt_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
- ath10k_warn("failed to request MSI irq %d: %d\n",
+ ath10k_warn(ar, "failed to request MSI irq %d: %d\n",
ar_pci->pdev->irq, ret);
return ret;
}
@@ -2328,7 +2161,7 @@ static int ath10k_pci_request_irq_legacy(struct ath10k *ar)
ath10k_pci_interrupt_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
- ath10k_warn("failed to request legacy irq %d: %d\n",
+ ath10k_warn(ar, "failed to request legacy irq %d: %d\n",
ar_pci->pdev->irq, ret);
return ret;
}
@@ -2349,7 +2182,7 @@ static int ath10k_pci_request_irq(struct ath10k *ar)
return ath10k_pci_request_irq_msix(ar);
}
- ath10k_warn("unknown irq configuration upon request\n");
+ ath10k_warn(ar, "unknown irq configuration upon request\n");
return -EINVAL;
}
@@ -2372,8 +2205,6 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
(unsigned long)ar);
- tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet,
- (unsigned long)ar);
for (i = 0; i < CE_COUNT; i++) {
ar_pci->pipe_info[i].ar_pci = ar_pci;
@@ -2385,18 +2216,16 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
static int ath10k_pci_init_irq(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X,
- ar_pci->features);
int ret;
ath10k_pci_init_irq_tasklets(ar);
- if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO &&
- !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
- ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode);
+ if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO)
+ ath10k_info(ar, "limiting irq mode to: %d\n",
+ ath10k_pci_irq_mode);
/* Try MSI-X */
- if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
+ if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
ar_pci->num_msi_intrs);
@@ -2426,34 +2255,16 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
* synchronization checking. */
ar_pci->num_msi_intrs = 0;
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_warn("failed to wake target: %d\n", ret);
- return ret;
- }
-
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
- ath10k_pci_sleep(ar);
return 0;
}
-static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
+static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
{
- int ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_warn("failed to wake target: %d\n", ret);
- return ret;
- }
-
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
0);
- ath10k_pci_sleep(ar);
-
- return 0;
}
static int ath10k_pci_deinit_irq(struct ath10k *ar)
@@ -2462,7 +2273,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
switch (ar_pci->num_msi_intrs) {
case 0:
- return ath10k_pci_deinit_irq_legacy(ar);
+ ath10k_pci_deinit_irq_legacy(ar);
+ return 0;
case 1:
/* fall-through */
case MSI_NUM_REQUEST:
@@ -2472,7 +2284,7 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
pci_disable_msi(ar_pci->pdev);
}
- ath10k_warn("unknown irq configuration upon deinit\n");
+ ath10k_warn(ar, "unknown irq configuration upon deinit\n");
return -EINVAL;
}
@@ -2480,23 +2292,17 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
unsigned long timeout;
- int ret;
u32 val;
- ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
-
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_err("failed to wake up target for init: %d\n", ret);
- return ret;
- }
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT);
do {
val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target indicator %x\n",
+ val);
/* target should never return this */
if (val == 0xffffffff)
@@ -2511,55 +2317,42 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
if (ar_pci->num_msi_intrs == 0)
/* Fix potential race by repeating CORE_BASE writes */
- ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS,
- PCIE_INTR_FIRMWARE_MASK |
- PCIE_INTR_CE_MASK_ALL);
+ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+ PCIE_INTR_ENABLE_ADDRESS,
+ PCIE_INTR_FIRMWARE_MASK |
+ PCIE_INTR_CE_MASK_ALL);
mdelay(10);
} while (time_before(jiffies, timeout));
if (val == 0xffffffff) {
- ath10k_err("failed to read device register, device is gone\n");
- ret = -EIO;
- goto out;
+ ath10k_err(ar, "failed to read device register, device is gone\n");
+ return -EIO;
}
if (val & FW_IND_EVENT_PENDING) {
- ath10k_warn("device has crashed during init\n");
- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
- val & ~FW_IND_EVENT_PENDING);
- ath10k_pci_hif_dump_area(ar);
- ret = -ECOMM;
- goto out;
+ ath10k_warn(ar, "device has crashed during init\n");
+ ath10k_pci_fw_crashed_clear(ar);
+ ath10k_pci_fw_crashed_dump(ar);
+ return -ECOMM;
}
if (!(val & FW_IND_INITIALIZED)) {
- ath10k_err("failed to receive initialized event from target: %08x\n",
+ ath10k_err(ar, "failed to receive initialized event from target: %08x\n",
val);
- ret = -ETIMEDOUT;
- goto out;
+ return -ETIMEDOUT;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n");
-
-out:
- ath10k_pci_sleep(ar);
- return ret;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target initialised\n");
+ return 0;
}
static int ath10k_pci_cold_reset(struct ath10k *ar)
{
- int i, ret;
+ int i;
u32 val;
- ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n");
-
- ret = ath10k_do_pci_wake(ar);
- if (ret) {
- ath10k_err("failed to wake up target: %d\n",
- ret);
- return ret;
- }
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
/* Put Target, including PCIe, into RESET. */
val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
@@ -2584,169 +2377,198 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
msleep(1);
}
- ath10k_do_pci_sleep(ar);
-
- ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
return 0;
}
-static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
-{
- int i;
-
- for (i = 0; i < ATH10K_PCI_FEATURE_COUNT; i++) {
- if (!test_bit(i, ar_pci->features))
- continue;
-
- switch (i) {
- case ATH10K_PCI_FEATURE_MSI_X:
- ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n");
- break;
- case ATH10K_PCI_FEATURE_SOC_POWER_SAVE:
- ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n");
- break;
- }
- }
-}
-
-static int ath10k_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *pci_dev)
+static int ath10k_pci_claim(struct ath10k *ar)
{
- void __iomem *mem;
- int ret = 0;
- struct ath10k *ar;
- struct ath10k_pci *ar_pci;
- u32 lcr_val, chip_id;
-
- ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n");
-
- ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL);
- if (ar_pci == NULL)
- return -ENOMEM;
-
- ar_pci->pdev = pdev;
- ar_pci->dev = &pdev->dev;
-
- switch (pci_dev->device) {
- case QCA988X_2_0_DEVICE_ID:
- set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
- break;
- default:
- ret = -ENODEV;
- ath10k_err("Unknown device ID: %d\n", pci_dev->device);
- goto err_ar_pci;
- }
-
- if (ath10k_pci_target_ps)
- set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);
-
- ath10k_pci_dump_features(ar_pci);
-
- ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
- if (!ar) {
- ath10k_err("failed to create driver core\n");
- ret = -EINVAL;
- goto err_ar_pci;
- }
-
- ar_pci->ar = ar;
- atomic_set(&ar_pci->keep_awake_count, 0);
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct pci_dev *pdev = ar_pci->pdev;
+ u32 lcr_val;
+ int ret;
pci_set_drvdata(pdev, ar);
ret = pci_enable_device(pdev);
if (ret) {
- ath10k_err("failed to enable PCI device: %d\n", ret);
- goto err_ar;
+ ath10k_err(ar, "failed to enable pci device: %d\n", ret);
+ return ret;
}
- /* Request MMIO resources */
ret = pci_request_region(pdev, BAR_NUM, "ath");
if (ret) {
- ath10k_err("failed to request MMIO region: %d\n", ret);
+ ath10k_err(ar, "failed to request region BAR%d: %d\n", BAR_NUM,
+ ret);
goto err_device;
}
- /*
- * Target structures have a limit of 32 bit DMA pointers.
- * DMA pointers can be wider than 32 bits by default on some systems.
- */
+ /* Target expects 32 bit DMA. Enforce it. */
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret);
+ ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret);
goto err_region;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- ath10k_err("failed to set consistent DMA mask to 32-bit\n");
+ ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n",
+ ret);
goto err_region;
}
- /* Set bus master bit in PCI_COMMAND to enable DMA */
pci_set_master(pdev);
- /*
- * Temporary FIX: disable ASPM
- * Will be removed after the OTP is programmed
- */
+ /* Workaround: Disable ASPM */
pci_read_config_dword(pdev, 0x80, &lcr_val);
pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00));
/* Arrange for access to Target SoC registers. */
- mem = pci_iomap(pdev, BAR_NUM, 0);
- if (!mem) {
- ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM);
+ ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
+ if (!ar_pci->mem) {
+ ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM);
ret = -EIO;
goto err_master;
}
- ar_pci->mem = mem;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
+ return 0;
+
+err_master:
+ pci_clear_master(pdev);
+
+err_region:
+ pci_release_region(pdev, BAR_NUM);
+
+err_device:
+ pci_disable_device(pdev);
+
+ return ret;
+}
+
+static void ath10k_pci_release(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct pci_dev *pdev = ar_pci->pdev;
+
+ pci_iounmap(pdev, ar_pci->mem);
+ pci_release_region(pdev, BAR_NUM);
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+}
+
+static int ath10k_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_dev)
+{
+ int ret = 0;
+ struct ath10k *ar;
+ struct ath10k_pci *ar_pci;
+ u32 chip_id;
+
+ ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev,
+ &ath10k_pci_hif_ops);
+ if (!ar) {
+ dev_err(&pdev->dev, "failed to allocate core\n");
+ return -ENOMEM;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n");
+
+ ar_pci = ath10k_pci_priv(ar);
+ ar_pci->pdev = pdev;
+ ar_pci->dev = &pdev->dev;
+ ar_pci->ar = ar;
spin_lock_init(&ar_pci->ce_lock);
+ setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
+ (unsigned long)ar);
- ret = ath10k_do_pci_wake(ar);
+ ret = ath10k_pci_claim(ar);
if (ret) {
- ath10k_err("Failed to get chip id: %d\n", ret);
- goto err_iomap;
+ ath10k_err(ar, "failed to claim device: %d\n", ret);
+ goto err_core_destroy;
}
- chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ ret = ath10k_pci_wake(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to wake up: %d\n", ret);
+ goto err_release;
+ }
- ath10k_do_pci_sleep(ar);
+ chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ if (chip_id == 0xffffffff) {
+ ath10k_err(ar, "failed to get chip id\n");
+ goto err_sleep;
+ }
ret = ath10k_pci_alloc_ce(ar);
if (ret) {
- ath10k_err("failed to allocate copy engine pipes: %d\n", ret);
- goto err_iomap;
+ ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
+ ret);
+ goto err_sleep;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
+ ath10k_pci_ce_deinit(ar);
- ret = ath10k_core_register(ar, chip_id);
+ ret = ath10k_ce_disable_interrupts(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to disable copy engine interrupts: %d\n",
+ ret);
+ goto err_free_ce;
+ }
+
+ /* Workaround: There's no known way to mask all possible interrupts via
+ * device CSR. The only way to make sure device doesn't assert
+ * interrupts is to reset it. Interrupts are then disabled on host
+ * after handlers are registered.
+ */
+ ath10k_pci_warm_reset(ar);
+
+ ret = ath10k_pci_init_irq(ar);
if (ret) {
- ath10k_err("failed to register driver core: %d\n", ret);
+ ath10k_err(ar, "failed to init irqs: %d\n", ret);
goto err_free_ce;
}
+ ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
+ ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs,
+ ath10k_pci_irq_mode, ath10k_pci_reset_mode);
+
+ ret = ath10k_pci_request_irq(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to request irqs: %d\n", ret);
+ goto err_deinit_irq;
+ }
+
+ /* This shouldn't race as the device has been reset above. */
+ ath10k_pci_irq_disable(ar);
+
+ ret = ath10k_core_register(ar, chip_id);
+ if (ret) {
+ ath10k_err(ar, "failed to register driver core: %d\n", ret);
+ goto err_free_irq;
+ }
+
return 0;
+err_free_irq:
+ ath10k_pci_free_irq(ar);
+
+err_deinit_irq:
+ ath10k_pci_deinit_irq(ar);
+
err_free_ce:
ath10k_pci_free_ce(ar);
-err_iomap:
- pci_iounmap(pdev, mem);
-err_master:
- pci_clear_master(pdev);
-err_region:
- pci_release_region(pdev, BAR_NUM);
-err_device:
- pci_disable_device(pdev);
-err_ar:
+
+err_sleep:
+ ath10k_pci_sleep(ar);
+
+err_release:
+ ath10k_pci_release(ar);
+
+err_core_destroy:
ath10k_core_destroy(ar);
-err_ar_pci:
- /* call HIF PCI free here */
- kfree(ar_pci);
return ret;
}
@@ -2756,7 +2578,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
struct ath10k *ar = pci_get_drvdata(pdev);
struct ath10k_pci *ar_pci;
- ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n");
if (!ar)
return;
@@ -2767,15 +2589,13 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
return;
ath10k_core_unregister(ar);
+ ath10k_pci_free_irq(ar);
+ ath10k_pci_deinit_irq(ar);
+ ath10k_pci_ce_deinit(ar);
ath10k_pci_free_ce(ar);
-
- pci_iounmap(pdev, ar_pci->mem);
- pci_release_region(pdev, BAR_NUM);
- pci_clear_master(pdev);
- pci_disable_device(pdev);
-
+ ath10k_pci_sleep(ar);
+ ath10k_pci_release(ar);
ath10k_core_destroy(ar);
- kfree(ar_pci);
}
MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
@@ -2793,7 +2613,8 @@ static int __init ath10k_pci_init(void)
ret = pci_register_driver(&ath10k_pci_driver);
if (ret)
- ath10k_err("failed to register PCI driver: %d\n", ret);
+ printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
+ ret);
return ret;
}
@@ -2809,5 +2630,5 @@ module_exit(ath10k_pci_exit);
MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 9401292..cf36511 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -23,9 +23,6 @@
#include "hw.h"
#include "ce.h"
-/* FW dump area */
-#define REG_DUMP_COUNT_QCA988X 60
-
/*
* maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
*/
@@ -103,12 +100,12 @@ struct pcie_state {
* NOTE: Structure is shared between Host software and Target firmware!
*/
struct ce_pipe_config {
- u32 pipenum;
- u32 pipedir;
- u32 nentries;
- u32 nbytes_max;
- u32 flags;
- u32 reserved;
+ __le32 pipenum;
+ __le32 pipedir;
+ __le32 nentries;
+ __le32 nbytes_max;
+ __le32 flags;
+ __le32 reserved;
};
/*
@@ -130,17 +127,9 @@ struct ce_pipe_config {
/* Establish a mapping between a service/direction and a pipe. */
struct service_to_pipe {
- u32 service_id;
- u32 pipedir;
- u32 pipenum;
-};
-
-enum ath10k_pci_features {
- ATH10K_PCI_FEATURE_MSI_X = 0,
- ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 1,
-
- /* keep last */
- ATH10K_PCI_FEATURE_COUNT
+ __le32 service_id;
+ __le32 pipedir;
+ __le32 pipenum;
};
/* Per-pipe state. */
@@ -169,8 +158,6 @@ struct ath10k_pci {
struct ath10k *ar;
void __iomem *mem;
- DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
-
/*
* Number of MSI interrupts granted, 0 --> using legacy PCI line
* interrupts.
@@ -179,12 +166,6 @@ struct ath10k_pci {
struct tasklet_struct intr_tq;
struct tasklet_struct msi_fw_err;
- struct tasklet_struct early_irq_tasklet;
-
- int started;
-
- atomic_t keep_awake_count;
- bool verified_awake;
struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
@@ -198,27 +179,15 @@ struct ath10k_pci {
/* Map CE id to ce_state */
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
+ struct timer_list rx_post_retry;
};
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
{
- return ar->hif.priv;
-}
-
-static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
-}
-
-static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
+ return (struct ath10k_pci *)ar->drv_priv;
}
+#define ATH10K_PCI_RX_POST_RETRY_MS 50
#define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
#define PCIE_WAKE_TIMEOUT 5000 /* 5ms */
@@ -242,35 +211,17 @@ static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
#define DIAG_ACCESS_CE_TIMEOUT_MS 10
-/*
- * This API allows the Host to access Target registers directly
- * and relatively efficiently over PCIe.
- * This allows the Host to avoid extra overhead associated with
- * sending a message to firmware and waiting for a response message
- * from firmware, as is done on other interconnects.
- *
- * Yet there is some complexity with direct accesses because the
- * Target's power state is not known a priori. The Host must issue
- * special PCIe reads/writes in order to explicitly wake the Target
- * and to verify that it is awake and will remain awake.
- *
- * Usage:
+/* Target exposes its registers for direct access. However before host can
+ * access them it needs to make sure the target is awake (ath10k_pci_wake,
+ * ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go
+ * to sleep unless host tells it to (ath10k_pci_sleep).
*
- * Use ath10k_pci_read32 and ath10k_pci_write32 to access Target space.
- * These calls must be bracketed by ath10k_pci_wake and
- * ath10k_pci_sleep. A single BEGIN/END pair is adequate for
- * multiple READ/WRITE operations.
+ * If host tries to access target registers without waking it up it can
+ * scribble over host memory.
*
- * Use ath10k_pci_wake to put the Target in a state in
- * which it is legal for the Host to directly access it. This
- * may involve waking the Target from a low power state, which
- * may take up to 2Ms!
- *
- * Use ath10k_pci_sleep to tell the Target that as far as
- * this code path is concerned, it no longer needs to remain
- * directly accessible. BEGIN/END is under a reference counter;
- * multiple code paths may issue BEGIN/END on a single targid.
+ * If target is asleep waking it up may take up to even 2ms.
*/
+
static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
u32 value)
{
@@ -296,25 +247,18 @@ static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
}
-int ath10k_do_pci_wake(struct ath10k *ar);
-void ath10k_do_pci_sleep(struct ath10k *ar);
-
-static inline int ath10k_pci_wake(struct ath10k *ar)
+static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- return ath10k_do_pci_wake(ar);
-
- return 0;
+ return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
}
-static inline void ath10k_pci_sleep(struct ath10k *ar)
+static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- ath10k_do_pci_sleep(ar);
+ iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
}
#endif /* _PCI_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
new file mode 100644
index 0000000..3e1454b
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/spectral.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/relay.h>
+#include "core.h"
+#include "debug.h"
+
+static void send_fft_sample(struct ath10k *ar,
+ const struct fft_sample_tlv *fft_sample_tlv)
+{
+ int length;
+
+ if (!ar->spectral.rfs_chan_spec_scan)
+ return;
+
+ length = __be16_to_cpu(fft_sample_tlv->length) +
+ sizeof(*fft_sample_tlv);
+ relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length);
+}
+
+static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
+ u8 *data)
+{
+ int dc_pos;
+ u8 max_exp;
+
+ dc_pos = bin_len / 2;
+
+ /* peak index outside of bins */
+ if (dc_pos < max_index || -dc_pos >= max_index)
+ return 0;
+
+ for (max_exp = 0; max_exp < 8; max_exp++) {
+ if (data[dc_pos + max_index] == (max_magnitude >> max_exp))
+ break;
+ }
+
+ /* max_exp not found */
+ if (data[dc_pos + max_index] != (max_magnitude >> max_exp))
+ return 0;
+
+ return max_exp;
+}
+
+int ath10k_spectral_process_fft(struct ath10k *ar,
+ struct wmi_single_phyerr_rx_event *event,
+ struct phyerr_fft_report *fftr,
+ size_t bin_len, u64 tsf)
+{
+ struct fft_sample_ath10k *fft_sample;
+ u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
+ u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
+ u32 reg0, reg1, nf_list1, nf_list2;
+ u8 chain_idx, *bins;
+ int dc_pos;
+
+ fft_sample = (struct fft_sample_ath10k *)&buf;
+
+ if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)
+ return -EINVAL;
+
+ reg0 = __le32_to_cpu(fftr->reg0);
+ reg1 = __le32_to_cpu(fftr->reg1);
+
+ length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len;
+ fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K;
+ fft_sample->tlv.length = __cpu_to_be16(length);
+
+ /* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
+ * but the results/plots suggest that its actually 22/44/88 MHz.
+ */
+ switch (event->hdr.chan_width_mhz) {
+ case 20:
+ fft_sample->chan_width_mhz = 22;
+ break;
+ case 40:
+ fft_sample->chan_width_mhz = 44;
+ break;
+ case 80:
+ /* TODO: As experiments with an analogue sender and various
+ * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
+ * show, the particular configuration of 80 MHz/64 bins does
+ * not match with the other smaples at all. Until the reason
+ * for that is found, don't report these samples.
+ */
+ if (bin_len == 64)
+ return -EINVAL;
+ fft_sample->chan_width_mhz = 88;
+ break;
+ default:
+ fft_sample->chan_width_mhz = event->hdr.chan_width_mhz;
+ }
+
+ fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
+ fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB);
+
+ peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
+ fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
+ fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
+ fft_sample->rssi = event->hdr.rssi_combined;
+
+ total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
+ base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
+ fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
+ fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
+
+ freq1 = __le16_to_cpu(event->hdr.freq1);
+ freq2 = __le16_to_cpu(event->hdr.freq2);
+ fft_sample->freq1 = __cpu_to_be16(freq1);
+ fft_sample->freq2 = __cpu_to_be16(freq2);
+
+ nf_list1 = __le32_to_cpu(event->hdr.nf_list_1);
+ nf_list2 = __le32_to_cpu(event->hdr.nf_list_2);
+ chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
+
+ switch (chain_idx) {
+ case 0:
+ fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu);
+ break;
+ case 1:
+ fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu);
+ break;
+ case 2:
+ fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu);
+ break;
+ case 3:
+ fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu);
+ break;
+ }
+
+ bins = (u8 *)fftr;
+ bins += sizeof(*fftr);
+
+ fft_sample->tsf = __cpu_to_be64(tsf);
+
+ /* max_exp has been directly reported by previous hardware (ath9k),
+ * maybe its possible to get it by other means?
+ */
+ fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
+ bin_len, bins);
+
+ memcpy(fft_sample->data, bins, bin_len);
+
+ /* DC value (value in the middle) is the blind spot of the spectral
+ * sample and invalid, interpolate it.
+ */
+ dc_pos = bin_len / 2;
+ fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
+ fft_sample->data[dc_pos - 1]) / 2;
+
+ send_fft_sample(ar, &fft_sample->tlv);
+
+ return 0;
+}
+
+static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ if (list_empty(&ar->arvifs))
+ return NULL;
+
+ /* if there already is a vif doing spectral, return that. */
+ list_for_each_entry(arvif, &ar->arvifs, list)
+ if (arvif->spectral_enabled)
+ return arvif;
+
+ /* otherwise, return the first vif. */
+ return list_first_entry(&ar->arvifs, typeof(*arvif), list);
+}
+
+static int ath10k_spectral_scan_trigger(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+ int res;
+ int vdev_id;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ arvif = ath10k_get_spectral_vdev(ar);
+ if (!arvif)
+ return -ENODEV;
+ vdev_id = arvif->vdev_id;
+
+ if (ar->spectral.mode == SPECTRAL_DISABLED)
+ return 0;
+
+ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+ WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
+ WMI_SPECTRAL_ENABLE_CMD_ENABLE);
+ if (res < 0)
+ return res;
+
+ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+ WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
+ WMI_SPECTRAL_ENABLE_CMD_ENABLE);
+ if (res < 0)
+ return res;
+
+ return 0;
+}
+
+static int ath10k_spectral_scan_config(struct ath10k *ar,
+ enum ath10k_spectral_mode mode)
+{
+ struct wmi_vdev_spectral_conf_arg arg;
+ struct ath10k_vif *arvif;
+ int vdev_id, count, res = 0;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ arvif = ath10k_get_spectral_vdev(ar);
+ if (!arvif)
+ return -ENODEV;
+
+ vdev_id = arvif->vdev_id;
+
+ arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
+ ar->spectral.mode = mode;
+
+ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+ WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
+ WMI_SPECTRAL_ENABLE_CMD_DISABLE);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
+ return res;
+ }
+
+ if (mode == SPECTRAL_DISABLED)
+ return 0;
+
+ if (mode == SPECTRAL_BACKGROUND)
+ count = WMI_SPECTRAL_COUNT_DEFAULT;
+ else
+ count = max_t(u8, 1, ar->spectral.config.count);
+
+ arg.vdev_id = vdev_id;
+ arg.scan_count = count;
+ arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
+ arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
+ arg.scan_fft_size = ar->spectral.config.fft_size;
+ arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
+ arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
+ arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
+ arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
+ arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
+ arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
+ arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
+ arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
+ arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
+ arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
+ arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
+ arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+ arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
+ arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
+
+ res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
+ return res;
+ }
+
+ return 0;
+}
+
+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char *mode = "";
+ unsigned int len;
+ enum ath10k_spectral_mode spectral_mode;
+
+ mutex_lock(&ar->conf_mutex);
+ spectral_mode = ar->spectral.mode;
+ mutex_unlock(&ar->conf_mutex);
+
+ switch (spectral_mode) {
+ case SPECTRAL_DISABLED:
+ mode = "disable";
+ break;
+ case SPECTRAL_BACKGROUND:
+ mode = "background";
+ break;
+ case SPECTRAL_MANUAL:
+ mode = "manual";
+ break;
+ }
+
+ len = strlen(mode);
+ return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ ssize_t len;
+ int res;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (strncmp("trigger", buf, 7) == 0) {
+ if (ar->spectral.mode == SPECTRAL_MANUAL ||
+ ar->spectral.mode == SPECTRAL_BACKGROUND) {
+ /* reset the configuration to adopt possibly changed
+ * debugfs parameters
+ */
+ res = ath10k_spectral_scan_config(ar,
+ ar->spectral.mode);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
+ res);
+ }
+ res = ath10k_spectral_scan_trigger(ar);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
+ res);
+ }
+ } else {
+ res = -EINVAL;
+ }
+ } else if (strncmp("background", buf, 9) == 0) {
+ res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
+ } else if (strncmp("manual", buf, 6) == 0) {
+ res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
+ } else if (strncmp("disable", buf, 7) == 0) {
+ res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
+ } else {
+ res = -EINVAL;
+ }
+
+ mutex_unlock(&ar->conf_mutex);
+
+ if (res < 0)
+ return res;
+
+ return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+ .read = read_file_spec_scan_ctl,
+ .write = write_file_spec_scan_ctl,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_count(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ unsigned int len;
+ u8 spectral_count;
+
+ mutex_lock(&ar->conf_mutex);
+ spectral_count = ar->spectral.config.count;
+ mutex_unlock(&ar->conf_mutex);
+
+ len = sprintf(buf, "%d\n", spectral_count);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_count(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+ ar->spectral.config.count = val;
+ mutex_unlock(&ar->conf_mutex);
+
+ return count;
+}
+
+static const struct file_operations fops_spectral_count = {
+ .read = read_file_spectral_count,
+ .write = write_file_spectral_count,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_bins(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ unsigned int len, bins, fft_size, bin_scale;
+
+ mutex_lock(&ar->conf_mutex);
+
+ fft_size = ar->spectral.config.fft_size;
+ bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+ bins = 1 << (fft_size - bin_scale);
+
+ mutex_unlock(&ar->conf_mutex);
+
+ len = sprintf(buf, "%d\n", bins);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_bins(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
+ return -EINVAL;
+
+ if (!is_power_of_2(val))
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+ ar->spectral.config.fft_size = ilog2(val);
+ ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+ mutex_unlock(&ar->conf_mutex);
+
+ return count;
+}
+
+static const struct file_operations fops_spectral_bins = {
+ .read = read_file_spectral_bins,
+ .write = write_file_spectral_bins,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static struct dentry *create_buf_file_handler(const char *filename,
+ struct dentry *parent,
+ umode_t mode,
+ struct rchan_buf *buf,
+ int *is_global)
+{
+ struct dentry *buf_file;
+
+ buf_file = debugfs_create_file(filename, mode, parent, buf,
+ &relay_file_operations);
+ *is_global = 1;
+ return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+ debugfs_remove(dentry);
+
+ return 0;
+}
+
+static struct rchan_callbacks rfs_spec_scan_cb = {
+ .create_buf_file = create_buf_file_handler,
+ .remove_buf_file = remove_buf_file_handler,
+};
+
+int ath10k_spectral_start(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list)
+ arvif->spectral_enabled = 0;
+
+ ar->spectral.mode = SPECTRAL_DISABLED;
+ ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
+ ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
+
+ return 0;
+}
+
+int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
+{
+ if (!arvif->spectral_enabled)
+ return 0;
+
+ return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
+}
+
+int ath10k_spectral_create(struct ath10k *ar)
+{
+ ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
+ ar->debug.debugfs_phy,
+ 1024, 256,
+ &rfs_spec_scan_cb, NULL);
+ debugfs_create_file("spectral_scan_ctl",
+ S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar,
+ &fops_spec_scan_ctl);
+ debugfs_create_file("spectral_count",
+ S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar,
+ &fops_spectral_count);
+ debugfs_create_file("spectral_bins",
+ S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar,
+ &fops_spectral_bins);
+
+ return 0;
+}
+
+void ath10k_spectral_destroy(struct ath10k *ar)
+{
+ if (ar->spectral.rfs_chan_spec_scan) {
+ relay_close(ar->spectral.rfs_chan_spec_scan);
+ ar->spectral.rfs_chan_spec_scan = NULL;
+ }
+}
diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h
new file mode 100644
index 0000000..ddc57c5
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/spectral.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SPECTRAL_H
+#define SPECTRAL_H
+
+#include "../spectral_common.h"
+
+/**
+ * struct ath10k_spec_scan - parameters for Atheros spectral scan
+ *
+ * @count: number of scan results requested for manual mode
+ * @fft_size: number of bins to be requested = 2^(fft_size - bin_scale)
+ */
+struct ath10k_spec_scan {
+ u8 count;
+ u8 fft_size;
+};
+
+/* enum ath10k_spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ * something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ * is performed manually.
+ */
+enum ath10k_spectral_mode {
+ SPECTRAL_DISABLED = 0,
+ SPECTRAL_BACKGROUND,
+ SPECTRAL_MANUAL,
+};
+
+#ifdef CONFIG_ATH10K_DEBUGFS
+
+int ath10k_spectral_process_fft(struct ath10k *ar,
+ struct wmi_single_phyerr_rx_event *event,
+ struct phyerr_fft_report *fftr,
+ size_t bin_len, u64 tsf);
+int ath10k_spectral_start(struct ath10k *ar);
+int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
+int ath10k_spectral_create(struct ath10k *ar);
+void ath10k_spectral_destroy(struct ath10k *ar);
+
+#else
+
+static inline int
+ath10k_spectral_process_fft(struct ath10k *ar,
+ struct wmi_single_phyerr_rx_event *event,
+ struct phyerr_fft_report *fftr,
+ size_t bin_len, u64 tsf)
+{
+ return 0;
+}
+
+static inline int ath10k_spectral_start(struct ath10k *ar)
+{
+ return 0;
+}
+
+static inline int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
+{
+ return 0;
+}
+
+static inline int ath10k_spectral_create(struct ath10k *ar)
+{
+ return 0;
+}
+
+static inline void ath10k_spectral_destroy(struct ath10k *ar)
+{
+}
+
+#endif /* CONFIG_ATH10K_DEBUGFS */
+
+#endif /* SPECTRAL_H */
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index f4fa22d..2eeec8a 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -32,14 +32,14 @@ static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb)
* offchan_tx_skb. */
spin_lock_bh(&ar->data_lock);
if (ar->offchan_tx_skb != skb) {
- ath10k_warn("completed old offchannel frame\n");
+ ath10k_warn(ar, "completed old offchannel frame\n");
goto out;
}
complete(&ar->offchan_tx_completed);
ar->offchan_tx_skb = NULL; /* just for sanity */
- ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
out:
spin_unlock_bh(&ar->data_lock);
}
@@ -47,18 +47,19 @@ out:
void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
const struct htt_tx_done *tx_done)
{
- struct device *dev = htt->ar->dev;
+ struct ath10k *ar = htt->ar;
+ struct device *dev = ar->dev;
struct ieee80211_tx_info *info;
struct ath10k_skb_cb *skb_cb;
struct sk_buff *msdu;
lockdep_assert_held(&htt->tx_lock);
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
if (tx_done->msdu_id >= htt->max_num_pending_tx) {
- ath10k_warn("warning: msdu_id %d too big, ignoring\n",
+ ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
tx_done->msdu_id);
return;
}
@@ -182,7 +183,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
wake_up(&ar->peer_mapping_wq);
}
- ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
ev->vdev_id, ev->addr, ev->peer_id);
set_bit(ev->peer_id, peer->peer_ids);
@@ -199,12 +200,12 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, ev->peer_id);
if (!peer) {
- ath10k_warn("peer-unmap-event: unknown peer id %d\n",
+ ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n",
ev->peer_id);
goto exit;
}
- ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
peer->vdev_id, peer->addr, ev->peer_id);
clear_bit(ev->peer_id, peer->peer_ids);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c2c87c9..e500a3c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -487,6 +487,127 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
};
+/* firmware 10.2 specific mappings */
+static struct wmi_cmd_map wmi_10_2_cmd_map = {
+ .init_cmdid = WMI_10_2_INIT_CMDID,
+ .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID,
+ .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID,
+ .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID,
+ .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+ .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+ .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID,
+ .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+ .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+ .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+ .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+ .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+ .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+ .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+ .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+ .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+ .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID,
+ .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID,
+ .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID,
+ .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+ .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID,
+ .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID,
+ .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID,
+ .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID,
+ .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+ .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID,
+ .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID,
+ .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+ .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID,
+ .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID,
+ .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+ .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+ .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID,
+ .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID,
+ .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID,
+ .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+ .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID,
+ .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+ .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID,
+ .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+ .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+ .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID,
+ .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID,
+ .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID,
+ .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID,
+ .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+ .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+ .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+ .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+ .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+ .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+ .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE,
+ .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+ .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD,
+ .roam_scan_rssi_change_threshold =
+ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+ .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE,
+ .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+ .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+ .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD,
+ .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+ .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+ .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE,
+ .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+ .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
+ .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+ .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+ .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+ .wlan_profile_set_hist_intvl_cmdid =
+ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+ .wlan_profile_get_profile_data_cmdid =
+ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+ .wlan_profile_enable_profile_id_cmdid =
+ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+ .wlan_profile_list_profile_id_cmdid =
+ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+ .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID,
+ .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID,
+ .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID,
+ .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID,
+ .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+ .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+ .wow_enable_disable_wake_event_cmdid =
+ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+ .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID,
+ .wow_hostwakeup_from_sleep_cmdid =
+ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+ .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID,
+ .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID,
+ .vdev_spectral_scan_configure_cmdid =
+ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+ .vdev_spectral_scan_enable_cmdid =
+ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+ .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID,
+ .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
+ .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
+ .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
+ .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
+ .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
+ .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
+ .echo_cmdid = WMI_10_2_ECHO_CMDID,
+ .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID,
+ .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID,
+ .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID,
+ .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
+ .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+ .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+ .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
+ .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
+ .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
+};
+
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
{
int ret;
@@ -503,18 +624,18 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar)
return ret;
}
-static struct sk_buff *ath10k_wmi_alloc_skb(u32 len)
+static struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len)
{
struct sk_buff *skb;
u32 round_len = roundup(len, 4);
- skb = ath10k_htc_alloc_skb(WMI_SKB_HEADROOM + round_len);
+ skb = ath10k_htc_alloc_skb(ar, WMI_SKB_HEADROOM + round_len);
if (!skb)
return NULL;
skb_reserve(skb, WMI_SKB_HEADROOM);
if (!IS_ALIGNED((unsigned long)skb->data, 4))
- ath10k_warn("Unaligned WMI skb\n");
+ ath10k_warn(ar, "Unaligned WMI skb\n");
skb_put(skb, round_len);
memset(skb->data, 0, round_len);
@@ -612,7 +733,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
might_sleep();
if (cmd_id == WMI_CMD_UNSUPPORTED) {
- ath10k_warn("wmi command %d is not supported by firmware\n",
+ ath10k_warn(ar, "wmi command %d is not supported by firmware\n",
cmd_id);
return ret;
}
@@ -660,7 +781,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
len = round_up(len, 4);
- wmi_skb = ath10k_wmi_alloc_skb(len);
+ wmi_skb = ath10k_wmi_alloc_skb(ar, len);
if (!wmi_skb)
return -ENOMEM;
@@ -674,7 +795,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN);
memcpy(cmd->buf, skb->data, skb->len);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
fc & IEEE80211_FCTL_STYPE);
@@ -690,6 +811,130 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
return ret;
}
+static void ath10k_wmi_event_scan_started(struct ath10k *ar)
+{
+ lockdep_assert_held(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ ath10k_warn(ar, "received scan started event in an invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_STARTING:
+ ar->scan.state = ATH10K_SCAN_RUNNING;
+
+ if (ar->scan.is_roc)
+ ieee80211_ready_on_channel(ar->hw);
+
+ complete(&ar->scan.started);
+ break;
+ }
+}
+
+static void ath10k_wmi_event_scan_completed(struct ath10k *ar)
+{
+ lockdep_assert_held(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ /* One suspected reason scan can be completed while starting is
+ * if firmware fails to deliver all scan events to the host,
+ * e.g. when transport pipe is full. This has been observed
+ * with spectral scan phyerr events starving wmi transport
+ * pipe. In such case the "scan completed" event should be (and
+ * is) ignored by the host as it may be just firmware's scan
+ * state machine recovering.
+ */
+ ath10k_warn(ar, "received scan completed event in an invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ __ath10k_scan_finish(ar);
+ break;
+ }
+}
+
+static void ath10k_wmi_event_scan_bss_chan(struct ath10k *ar)
+{
+ lockdep_assert_held(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ ath10k_warn(ar, "received scan bss chan event in an invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ ar->scan_channel = NULL;
+ break;
+ }
+}
+
+static void ath10k_wmi_event_scan_foreign_chan(struct ath10k *ar, u32 freq)
+{
+ lockdep_assert_held(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ ath10k_warn(ar, "received scan foreign chan event in an invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
+
+ if (ar->scan.is_roc && ar->scan.roc_freq == freq)
+ complete(&ar->scan.on_channel);
+ break;
+ }
+}
+
+static const char *
+ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
+ enum wmi_scan_completion_reason reason)
+{
+ switch (type) {
+ case WMI_SCAN_EVENT_STARTED:
+ return "started";
+ case WMI_SCAN_EVENT_COMPLETED:
+ switch (reason) {
+ case WMI_SCAN_REASON_COMPLETED:
+ return "completed";
+ case WMI_SCAN_REASON_CANCELLED:
+ return "completed [cancelled]";
+ case WMI_SCAN_REASON_PREEMPTED:
+ return "completed [preempted]";
+ case WMI_SCAN_REASON_TIMEDOUT:
+ return "completed [timedout]";
+ case WMI_SCAN_REASON_MAX:
+ break;
+ }
+ return "completed [unknown]";
+ case WMI_SCAN_EVENT_BSS_CHANNEL:
+ return "bss channel";
+ case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
+ return "foreign channel";
+ case WMI_SCAN_EVENT_DEQUEUED:
+ return "dequeued";
+ case WMI_SCAN_EVENT_PREEMPTED:
+ return "preempted";
+ case WMI_SCAN_EVENT_START_FAILED:
+ return "start failed";
+ default:
+ return "unknown";
+ }
+}
+
static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data;
@@ -707,81 +952,32 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
scan_id = __le32_to_cpu(event->scan_id);
vdev_id = __le32_to_cpu(event->vdev_id);
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENTID\n");
- ath10k_dbg(ATH10K_DBG_WMI,
- "scan event type %d reason %d freq %d req_id %d "
- "scan_id %d vdev_id %d\n",
- event_type, reason, freq, req_id, scan_id, vdev_id);
-
spin_lock_bh(&ar->data_lock);
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n",
+ ath10k_wmi_event_scan_type_str(event_type, reason),
+ event_type, reason, freq, req_id, scan_id, vdev_id,
+ ath10k_scan_state_str(ar->scan.state), ar->scan.state);
+
switch (event_type) {
case WMI_SCAN_EVENT_STARTED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_STARTED\n");
- if (ar->scan.in_progress && ar->scan.is_roc)
- ieee80211_ready_on_channel(ar->hw);
-
- complete(&ar->scan.started);
+ ath10k_wmi_event_scan_started(ar);
break;
case WMI_SCAN_EVENT_COMPLETED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_COMPLETED\n");
- switch (reason) {
- case WMI_SCAN_REASON_COMPLETED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_COMPLETED\n");
- break;
- case WMI_SCAN_REASON_CANCELLED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_CANCELED\n");
- break;
- case WMI_SCAN_REASON_PREEMPTED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_PREEMPTED\n");
- break;
- case WMI_SCAN_REASON_TIMEDOUT:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_TIMEDOUT\n");
- break;
- default:
- break;
- }
-
- ar->scan_channel = NULL;
- if (!ar->scan.in_progress) {
- ath10k_warn("no scan requested, ignoring\n");
- break;
- }
-
- if (ar->scan.is_roc) {
- ath10k_offchan_tx_purge(ar);
-
- if (!ar->scan.aborting)
- ieee80211_remain_on_channel_expired(ar->hw);
- } else {
- ieee80211_scan_completed(ar->hw, ar->scan.aborting);
- }
-
- del_timer(&ar->scan.timeout);
- complete_all(&ar->scan.completed);
- ar->scan.in_progress = false;
+ ath10k_wmi_event_scan_completed(ar);
break;
case WMI_SCAN_EVENT_BSS_CHANNEL:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_BSS_CHANNEL\n");
- ar->scan_channel = NULL;
+ ath10k_wmi_event_scan_bss_chan(ar);
break;
case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_FOREIGN_CHANNEL\n");
- ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
- if (ar->scan.in_progress && ar->scan.is_roc &&
- ar->scan.roc_freq == freq) {
- complete(&ar->scan.on_channel);
- }
- break;
- case WMI_SCAN_EVENT_DEQUEUED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_DEQUEUED\n");
- break;
- case WMI_SCAN_EVENT_PREEMPTED:
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_PREEMPTED\n");
+ ath10k_wmi_event_scan_foreign_chan(ar, freq);
break;
case WMI_SCAN_EVENT_START_FAILED:
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_START_FAILED\n");
+ ath10k_warn(ar, "received scan start failure event\n");
break;
+ case WMI_SCAN_EVENT_DEQUEUED:
+ case WMI_SCAN_EVENT_PREEMPTED:
default:
break;
}
@@ -911,7 +1107,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
memset(status, 0, sizeof(*status));
- ath10k_dbg(ATH10K_DBG_MGMT,
+ ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx status %08x\n", rx_status);
if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
@@ -947,9 +1143,9 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
if (phy_mode == MODE_11B &&
status->band == IEEE80211_BAND_5GHZ)
- ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+ ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
} else {
- ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n");
+ ath10k_warn(ar, "using (unreliable) phy_mode to extract band for mgmt rx\n");
status->band = phy_mode_to_band(phy_mode);
}
@@ -979,12 +1175,12 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
}
}
- ath10k_dbg(ATH10K_DBG_MGMT,
+ ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx skb %p len %d ftype %02x stype %02x\n",
skb, skb->len,
fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);
- ath10k_dbg(ATH10K_DBG_MGMT,
+ ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx freq %d band %d snr %d, rate_idx %d\n",
status->freq, status->band, status->signal,
status->rate_idx);
@@ -1034,21 +1230,26 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
cycle_count = __le32_to_cpu(ev->cycle_count);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
err_code, freq, cmd_flags, noise_floor, rx_clear_count,
cycle_count);
spin_lock_bh(&ar->data_lock);
- if (!ar->scan.in_progress) {
- ath10k_warn("chan info event without a scan request?\n");
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ ath10k_warn(ar, "received chan info event without a scan request, ignoring\n");
goto exit;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ break;
}
idx = freq_to_idx(ar, freq);
if (idx >= ARRAY_SIZE(ar->survey)) {
- ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n",
+ ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
freq, idx);
goto exit;
}
@@ -1079,12 +1280,12 @@ exit:
static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
}
static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
skb->len);
trace_ath10k_wmi_dbglog(skb->data, skb->len);
@@ -1097,7 +1298,7 @@ static void ath10k_wmi_event_update_stats(struct ath10k *ar,
{
struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data;
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
ath10k_debug_read_target_stats(ar, ev);
}
@@ -1107,7 +1308,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
{
struct wmi_vdev_start_response_event *ev;
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
ev = (struct wmi_vdev_start_response_event *)skb->data;
@@ -1120,7 +1321,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
complete(&ar->vdev_setup_done);
}
@@ -1132,14 +1333,14 @@ static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
ev = (struct wmi_peer_sta_kickout_event *)skb->data;
- ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
ev->peer_macaddr.addr);
rcu_read_lock();
sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
if (!sta) {
- ath10k_warn("Spurious quick kickout for STA %pM\n",
+ ath10k_warn(ar, "Spurious quick kickout for STA %pM\n",
ev->peer_macaddr.addr);
goto exit;
}
@@ -1216,7 +1417,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
(u8 *)skb_tail_pointer(bcn) - ies);
if (!ie) {
if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
- ath10k_warn("no tim ie found;\n");
+ ath10k_warn(ar, "no tim ie found;\n");
return;
}
@@ -1236,12 +1437,12 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
ie_len += expand_size;
pvm_len += expand_size;
} else {
- ath10k_warn("tim expansion failed\n");
+ ath10k_warn(ar, "tim expansion failed\n");
}
}
if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) {
- ath10k_warn("tim pvm length is too great (%d)\n", pvm_len);
+ ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len);
return;
}
@@ -1255,7 +1456,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
}
- ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
tim->dtim_count, tim->dtim_period,
tim->bitmap_ctrl, pvm_len);
}
@@ -1333,7 +1534,7 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
return;
- ath10k_dbg(ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
+ ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) {
new_len = ath10k_p2p_calc_noa_ie_len(noa);
if (!new_len)
@@ -1381,7 +1582,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
ev = (struct wmi_host_swba_event *)skb->data;
map = __le32_to_cpu(ev->vdev_map);
- ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
ev->vdev_map);
for (; map; map >>= 1, vdev_id++) {
@@ -1391,13 +1592,13 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
i++;
if (i >= WMI_MAX_AP_VDEV) {
- ath10k_warn("swba has corrupted vdev map\n");
+ ath10k_warn(ar, "swba has corrupted vdev map\n");
break;
}
bcn_info = &ev->bcn_info[i];
- ath10k_dbg(ATH10K_DBG_MGMT,
+ ath10k_dbg(ar, ATH10K_DBG_MGMT,
"mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
i,
__le32_to_cpu(bcn_info->tim_info.tim_len),
@@ -1411,7 +1612,8 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
arvif = ath10k_get_arvif(ar, vdev_id);
if (arvif == NULL) {
- ath10k_warn("no vif for vdev_id %d found\n", vdev_id);
+ ath10k_warn(ar, "no vif for vdev_id %d found\n",
+ vdev_id);
continue;
}
@@ -1428,7 +1630,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
if (!bcn) {
- ath10k_warn("could not get mac80211 beacon\n");
+ ath10k_warn(ar, "could not get mac80211 beacon\n");
continue;
}
@@ -1440,7 +1642,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
if (arvif->beacon) {
if (!arvif->beacon_sent)
- ath10k_warn("SWBA overrun on vdev %d\n",
+ ath10k_warn(ar, "SWBA overrun on vdev %d\n",
arvif->vdev_id);
dma_unmap_single(arvif->ar->dev,
@@ -1456,7 +1658,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
ret = dma_mapping_error(arvif->ar->dev,
ATH10K_SKB_CB(bcn)->paddr);
if (ret) {
- ath10k_warn("failed to map beacon: %d\n", ret);
+ ath10k_warn(ar, "failed to map beacon: %d\n", ret);
dev_kfree_skb_any(bcn);
goto skip;
}
@@ -1473,7 +1675,7 @@ skip:
static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
}
static void ath10k_dfs_radar_report(struct ath10k *ar,
@@ -1489,20 +1691,20 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
reg0 = __le32_to_cpu(rr->reg0);
reg1 = __le32_to_cpu(rr->reg1);
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n",
MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP),
MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH),
MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN),
MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF));
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n",
MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK),
MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX),
MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID),
MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN),
MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK));
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n",
MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET),
MS(reg1, RADAR_REPORT_REG1_PULSE_DUR));
@@ -1529,25 +1731,25 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
pe.width = width;
pe.rssi = rssi;
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
pe.freq, pe.width, pe.rssi, pe.ts);
ATH10K_DFS_STAT_INC(ar, pulses_detected);
if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) {
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"dfs no pulse pattern detected, yet\n");
return;
}
- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
ATH10K_DFS_STAT_INC(ar, radar_detected);
/* Control radar events reporting in debugfs file
dfs_block_radar_events */
if (ar->dfs_block_radar_events) {
- ath10k_info("DFS Radar detected, but ignored as requested\n");
+ ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
return;
}
@@ -1566,13 +1768,13 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
reg1 = __le32_to_cpu(fftr->reg1);
rssi = event->hdr.rssi_combined;
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB),
MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB),
MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX),
MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX));
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n",
MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB),
MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB),
@@ -1584,7 +1786,7 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
/* false event detection */
if (rssi == DFS_RSSI_POSSIBLY_FALSE &&
peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) {
- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
ATH10K_DFS_STAT_INC(ar, pulses_discarded);
return -EINVAL;
}
@@ -1603,7 +1805,7 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
u8 *tlv_buf;
buf_len = __le32_to_cpu(event->hdr.buf_len);
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",
event->hdr.phy_err_code, event->hdr.rssi_combined,
__le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len);
@@ -1616,21 +1818,22 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
while (i < buf_len) {
if (i + sizeof(*tlv) > buf_len) {
- ath10k_warn("too short buf for tlv header (%d)\n", i);
+ ath10k_warn(ar, "too short buf for tlv header (%d)\n",
+ i);
return;
}
tlv = (struct phyerr_tlv *)&event->bufp[i];
tlv_len = __le16_to_cpu(tlv->len);
tlv_buf = &event->bufp[i + sizeof(*tlv)];
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n",
tlv_len, tlv->tag, tlv->sig);
switch (tlv->tag) {
case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY:
if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) {
- ath10k_warn("too short radar pulse summary (%d)\n",
+ ath10k_warn(ar, "too short radar pulse summary (%d)\n",
i);
return;
}
@@ -1640,7 +1843,8 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
break;
case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) {
- ath10k_warn("too short fft report (%d)\n", i);
+ ath10k_warn(ar, "too short fft report (%d)\n",
+ i);
return;
}
@@ -1659,7 +1863,54 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
struct wmi_single_phyerr_rx_event *event,
u64 tsf)
{
- ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n");
+ int buf_len, tlv_len, res, i = 0;
+ struct phyerr_tlv *tlv;
+ u8 *tlv_buf;
+ struct phyerr_fft_report *fftr;
+ size_t fftr_len;
+
+ buf_len = __le32_to_cpu(event->hdr.buf_len);
+
+ while (i < buf_len) {
+ if (i + sizeof(*tlv) > buf_len) {
+ ath10k_warn(ar, "failed to parse phyerr tlv header at byte %d\n",
+ i);
+ return;
+ }
+
+ tlv = (struct phyerr_tlv *)&event->bufp[i];
+ tlv_len = __le16_to_cpu(tlv->len);
+ tlv_buf = &event->bufp[i + sizeof(*tlv)];
+
+ if (i + sizeof(*tlv) + tlv_len > buf_len) {
+ ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n",
+ i);
+ return;
+ }
+
+ switch (tlv->tag) {
+ case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
+ if (sizeof(*fftr) > tlv_len) {
+ ath10k_warn(ar, "failed to parse fft report at byte %d\n",
+ i);
+ return;
+ }
+
+ fftr_len = tlv_len - sizeof(*fftr);
+ fftr = (struct phyerr_fft_report *)tlv_buf;
+ res = ath10k_spectral_process_fft(ar, event,
+ fftr, fftr_len,
+ tsf);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to process fft report: %d\n",
+ res);
+ return;
+ }
+ break;
+ }
+
+ i += sizeof(*tlv) + tlv_len;
+ }
}
static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
@@ -1674,7 +1925,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
/* Check if combined event available */
if (left_len < sizeof(*comb_event)) {
- ath10k_warn("wmi phyerr combined event wrong len\n");
+ ath10k_warn(ar, "wmi phyerr combined event wrong len\n");
return;
}
@@ -1688,7 +1939,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
tsf <<= 32;
tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event phyerr count %d tsf64 0x%llX\n",
count, tsf);
@@ -1696,7 +1947,8 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
for (i = 0; i < count; i++) {
/* Check if we can read event header */
if (left_len < sizeof(*event)) {
- ath10k_warn("single event (%d) wrong head len\n", i);
+ ath10k_warn(ar, "single event (%d) wrong head len\n",
+ i);
return;
}
@@ -1706,7 +1958,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
phy_err_code = event->hdr.phy_err_code;
if (left_len < buf_len) {
- ath10k_warn("single event (%d) wrong buf len\n", i);
+ ath10k_warn(ar, "single event (%d) wrong buf len\n", i);
return;
}
@@ -1733,13 +1985,13 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
}
static void ath10k_wmi_event_profile_match(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
}
static void ath10k_wmi_event_debug_print(struct ath10k *ar,
@@ -1764,7 +2016,7 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
}
if (i == sizeof(buf) - 1)
- ath10k_warn("wmi debug print truncated: %d\n", skb->len);
+ ath10k_warn(ar, "wmi debug print truncated: %d\n", skb->len);
/* for some reason the debug prints end with \n, remove that */
if (skb->data[i - 1] == '\n')
@@ -1773,108 +2025,108 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
/* the last byte is always reserved for the null character */
buf[i] = '\0';
- ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
}
static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
}
static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
}
static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
}
static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
}
static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
}
static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
}
static void ath10k_wmi_event_dcs_interference(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
}
static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
}
static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
}
static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
}
static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
}
static void ath10k_wmi_event_delba_complete(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
}
static void ath10k_wmi_event_addba_complete(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
}
static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
}
static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
}
static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
}
static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
}
static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
@@ -1894,7 +2146,7 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
&paddr,
GFP_ATOMIC);
if (!ar->wmi.mem_chunks[idx].vaddr) {
- ath10k_warn("failed to allocate memory chunk\n");
+ ath10k_warn(ar, "failed to allocate memory chunk\n");
return -ENOMEM;
}
@@ -1912,9 +2164,10 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
struct sk_buff *skb)
{
struct wmi_service_ready_event *ev = (void *)skb->data;
+ DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {};
if (skb->len < sizeof(*ev)) {
- ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
+ ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
skb->len, sizeof(*ev));
return;
}
@@ -1937,7 +2190,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
- ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
+ ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
}
@@ -1945,8 +2198,10 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
ar->ath_common.regulatory.current_rd =
__le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
- ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
- sizeof(ev->wmi_service_bitmap));
+ wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap);
+ ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+ ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+ ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
if (strlen(ar->hw->wiphy->fw_version) == 0) {
snprintf(ar->hw->wiphy->fw_version,
@@ -1960,11 +2215,11 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
/* FIXME: it probably should be better to support this */
if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
- ath10k_warn("target requested %d memory chunks; ignoring\n",
+ ath10k_warn(ar, "target requested %d memory chunks; ignoring\n",
__le32_to_cpu(ev->num_mem_reqs));
}
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
__le32_to_cpu(ev->sw_version),
__le32_to_cpu(ev->sw_version_1),
@@ -1986,9 +2241,10 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
int ret;
struct wmi_service_ready_event_10x *ev = (void *)skb->data;
+ DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {};
if (skb->len < sizeof(*ev)) {
- ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
+ ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
skb->len, sizeof(*ev));
return;
}
@@ -2004,7 +2260,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
- ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
+ ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
}
@@ -2012,8 +2268,10 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
ar->ath_common.regulatory.current_rd =
__le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
- ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
- sizeof(ev->wmi_service_bitmap));
+ wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap);
+ ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+ ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+ ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
if (strlen(ar->hw->wiphy->fw_version) == 0) {
snprintf(ar->hw->wiphy->fw_version,
@@ -2026,7 +2284,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
- ath10k_warn("requested memory chunks number (%d) exceeds the limit\n",
+ ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
num_mem_reqs);
return;
}
@@ -2034,7 +2292,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
if (!num_mem_reqs)
goto exit;
- ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
num_mem_reqs);
for (i = 0; i < num_mem_reqs; ++i) {
@@ -2052,7 +2310,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS)
num_units = TARGET_10X_NUM_VDEVS + 1;
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
req_id,
__le32_to_cpu(ev->mem_reqs[i].num_units),
@@ -2067,7 +2325,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
}
exit:
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
__le32_to_cpu(ev->sw_version),
__le32_to_cpu(ev->abi_version),
@@ -2091,7 +2349,7 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
__le32_to_cpu(ev->sw_version),
__le32_to_cpu(ev->abi_version),
@@ -2211,7 +2469,7 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_wmi_ready_event_rx(ar, skb);
break;
default:
- ath10k_warn("Unknown eventid: %d\n", id);
+ ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
}
@@ -2318,27 +2576,151 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_wmi_ready_event_rx(ar, skb);
break;
default:
- ath10k_warn("Unknown eventid: %d\n", id);
+ ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
}
dev_kfree_skb(skb);
}
+static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_cmd_hdr *cmd_hdr;
+ enum wmi_10_2_event_id id;
+
+ cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
+ id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
+
+ if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+ return;
+
+ trace_ath10k_wmi_event(id, skb->data, skb->len);
+
+ switch (id) {
+ case WMI_10_2_MGMT_RX_EVENTID:
+ ath10k_wmi_event_mgmt_rx(ar, skb);
+ /* mgmt_rx() owns the skb now! */
+ return;
+ case WMI_10_2_SCAN_EVENTID:
+ ath10k_wmi_event_scan(ar, skb);
+ break;
+ case WMI_10_2_CHAN_INFO_EVENTID:
+ ath10k_wmi_event_chan_info(ar, skb);
+ break;
+ case WMI_10_2_ECHO_EVENTID:
+ ath10k_wmi_event_echo(ar, skb);
+ break;
+ case WMI_10_2_DEBUG_MESG_EVENTID:
+ ath10k_wmi_event_debug_mesg(ar, skb);
+ break;
+ case WMI_10_2_UPDATE_STATS_EVENTID:
+ ath10k_wmi_event_update_stats(ar, skb);
+ break;
+ case WMI_10_2_VDEV_START_RESP_EVENTID:
+ ath10k_wmi_event_vdev_start_resp(ar, skb);
+ break;
+ case WMI_10_2_VDEV_STOPPED_EVENTID:
+ ath10k_wmi_event_vdev_stopped(ar, skb);
+ break;
+ case WMI_10_2_PEER_STA_KICKOUT_EVENTID:
+ ath10k_wmi_event_peer_sta_kickout(ar, skb);
+ break;
+ case WMI_10_2_HOST_SWBA_EVENTID:
+ ath10k_wmi_event_host_swba(ar, skb);
+ break;
+ case WMI_10_2_TBTTOFFSET_UPDATE_EVENTID:
+ ath10k_wmi_event_tbttoffset_update(ar, skb);
+ break;
+ case WMI_10_2_PHYERR_EVENTID:
+ ath10k_wmi_event_phyerr(ar, skb);
+ break;
+ case WMI_10_2_ROAM_EVENTID:
+ ath10k_wmi_event_roam(ar, skb);
+ break;
+ case WMI_10_2_PROFILE_MATCH:
+ ath10k_wmi_event_profile_match(ar, skb);
+ break;
+ case WMI_10_2_DEBUG_PRINT_EVENTID:
+ ath10k_wmi_event_debug_print(ar, skb);
+ break;
+ case WMI_10_2_PDEV_QVIT_EVENTID:
+ ath10k_wmi_event_pdev_qvit(ar, skb);
+ break;
+ case WMI_10_2_WLAN_PROFILE_DATA_EVENTID:
+ ath10k_wmi_event_wlan_profile_data(ar, skb);
+ break;
+ case WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID:
+ ath10k_wmi_event_rtt_measurement_report(ar, skb);
+ break;
+ case WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID:
+ ath10k_wmi_event_tsf_measurement_report(ar, skb);
+ break;
+ case WMI_10_2_RTT_ERROR_REPORT_EVENTID:
+ ath10k_wmi_event_rtt_error_report(ar, skb);
+ break;
+ case WMI_10_2_WOW_WAKEUP_HOST_EVENTID:
+ ath10k_wmi_event_wow_wakeup_host(ar, skb);
+ break;
+ case WMI_10_2_DCS_INTERFERENCE_EVENTID:
+ ath10k_wmi_event_dcs_interference(ar, skb);
+ break;
+ case WMI_10_2_PDEV_TPC_CONFIG_EVENTID:
+ ath10k_wmi_event_pdev_tpc_config(ar, skb);
+ break;
+ case WMI_10_2_INST_RSSI_STATS_EVENTID:
+ ath10k_wmi_event_inst_rssi_stats(ar, skb);
+ break;
+ case WMI_10_2_VDEV_STANDBY_REQ_EVENTID:
+ ath10k_wmi_event_vdev_standby_req(ar, skb);
+ break;
+ case WMI_10_2_VDEV_RESUME_REQ_EVENTID:
+ ath10k_wmi_event_vdev_resume_req(ar, skb);
+ break;
+ case WMI_10_2_SERVICE_READY_EVENTID:
+ ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+ break;
+ case WMI_10_2_READY_EVENTID:
+ ath10k_wmi_ready_event_rx(ar, skb);
+ break;
+ case WMI_10_2_RTT_KEEPALIVE_EVENTID:
+ case WMI_10_2_GPIO_INPUT_EVENTID:
+ case WMI_10_2_PEER_RATECODE_LIST_EVENTID:
+ case WMI_10_2_GENERIC_BUFFER_EVENTID:
+ case WMI_10_2_MCAST_BUF_RELEASE_EVENTID:
+ case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID:
+ case WMI_10_2_WDS_PEER_EVENTID:
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "received event id %d not implemented\n", id);
+ break;
+ default:
+ ath10k_warn(ar, "Unknown eventid: %d\n", id);
+ break;
+ }
+
+ dev_kfree_skb(skb);
+}
static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
{
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- ath10k_wmi_10x_process_rx(ar, skb);
- else
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ath10k_wmi_10_2_process_rx(ar, skb);
+ else
+ ath10k_wmi_10x_process_rx(ar, skb);
+ } else {
ath10k_wmi_main_process_rx(ar, skb);
+ }
}
/* WMI Initialization functions */
int ath10k_wmi_attach(struct ath10k *ar)
{
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- ar->wmi.cmd = &wmi_10x_cmd_map;
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ar->wmi.cmd = &wmi_10_2_cmd_map;
+ else
+ ar->wmi.cmd = &wmi_10x_cmd_map;
+
ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
} else {
@@ -2388,7 +2770,7 @@ int ath10k_wmi_connect(struct ath10k *ar)
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",
+ ath10k_warn(ar, "failed to connect to WMI CONTROL service status: %d\n",
status);
return status;
}
@@ -2404,7 +2786,7 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
struct wmi_pdev_set_regdomain_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2415,7 +2797,7 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g);
cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n",
rd, rd2g, rd5g, ctl2g, ctl5g);
@@ -2431,7 +2813,7 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
struct wmi_pdev_set_regdomain_cmd_10x *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2443,7 +2825,7 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
cmd->dfs_domain = __cpu_to_le32(dfs_reg);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
@@ -2473,7 +2855,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
if (arg->passive)
return -EINVAL;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2491,7 +2873,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
cmd->chan.reg_classid = arg->reg_class_id;
cmd->chan.antenna_max = arg->max_antenna_gain;
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi set channel mode %d freq %d\n",
arg->mode, arg->freq);
@@ -2504,7 +2886,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
struct wmi_pdev_suspend_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2518,7 +2900,7 @@ int ath10k_wmi_pdev_resume_target(struct ath10k *ar)
{
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(0);
+ skb = ath10k_wmi_alloc_skb(ar, 0);
if (skb == NULL)
return -ENOMEM;
@@ -2531,11 +2913,12 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
struct sk_buff *skb;
if (id == WMI_PDEV_PARAM_UNSUPPORTED) {
- ath10k_warn("pdev param %d not supported by firmware\n", id);
+ ath10k_warn(ar, "pdev param %d not supported by firmware\n",
+ id);
return -EOPNOTSUPP;
}
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2543,7 +2926,7 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
cmd->param_id = __cpu_to_le32(id);
cmd->param_value = __cpu_to_le32(value);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
id, value);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
}
@@ -2610,7 +2993,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
len = sizeof(*cmd) +
(sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
- buf = ath10k_wmi_alloc_skb(len);
+ buf = ath10k_wmi_alloc_skb(ar, len);
if (!buf)
return -ENOMEM;
@@ -2621,7 +3004,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
goto out;
}
- ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
ar->wmi.num_mem_chunks);
cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
@@ -2634,7 +3017,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
cmd->host_mem_chunks[i].req_id =
__cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi chunk %d len %d requested, addr 0x%llx\n",
i,
ar->wmi.mem_chunks[i].len,
@@ -2643,7 +3026,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
out:
memcpy(&cmd->resource_config, &config, sizeof(config));
- ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
}
@@ -2701,7 +3084,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
len = sizeof(*cmd) +
(sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
- buf = ath10k_wmi_alloc_skb(len);
+ buf = ath10k_wmi_alloc_skb(ar, len);
if (!buf)
return -ENOMEM;
@@ -2712,7 +3095,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
goto out;
}
- ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
ar->wmi.num_mem_chunks);
cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
@@ -2725,7 +3108,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
cmd->host_mem_chunks[i].req_id =
__cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi chunk %d len %d requested, addr 0x%llx\n",
i,
ar->wmi.mem_chunks[i].len,
@@ -2734,7 +3117,98 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
out:
memcpy(&cmd->resource_config, &config, sizeof(config));
- ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10x\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
+ return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+}
+
+static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
+{
+ struct wmi_init_cmd_10_2 *cmd;
+ struct sk_buff *buf;
+ struct wmi_resource_config_10x config = {};
+ u32 len, val;
+ int i;
+
+ config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+ config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+ config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
+ config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+ config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
+ config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
+ config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
+ config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+ config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+ config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+ config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI);
+ config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
+
+ config.scan_max_pending_reqs =
+ __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS);
+
+ config.bmiss_offload_max_vdev =
+ __cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
+
+ config.roam_offload_max_vdev =
+ __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
+
+ config.roam_offload_max_ap_profiles =
+ __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+
+ config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS);
+ config.num_mcast_table_elems =
+ __cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS);
+
+ config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE);
+ config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE);
+ config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES);
+ config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE);
+ config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM);
+
+ val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
+ config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val);
+
+ config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG);
+
+ config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
+ config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
+
+ len = sizeof(*cmd) +
+ (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
+
+ buf = ath10k_wmi_alloc_skb(ar, len);
+ if (!buf)
+ return -ENOMEM;
+
+ cmd = (struct wmi_init_cmd_10_2 *)buf->data;
+
+ if (ar->wmi.num_mem_chunks == 0) {
+ cmd->num_host_mem_chunks = 0;
+ goto out;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+ ar->wmi.num_mem_chunks);
+
+ cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+ for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+ cmd->host_mem_chunks[i].ptr =
+ __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
+ cmd->host_mem_chunks[i].size =
+ __cpu_to_le32(ar->wmi.mem_chunks[i].len);
+ cmd->host_mem_chunks[i].req_id =
+ __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi chunk %d len %d requested, addr 0x%llx\n",
+ i,
+ ar->wmi.mem_chunks[i].len,
+ (unsigned long long)ar->wmi.mem_chunks[i].paddr);
+ }
+out:
+ memcpy(&cmd->resource_config.common, &config, sizeof(config));
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
}
@@ -2742,10 +3216,14 @@ int ath10k_wmi_cmd_init(struct ath10k *ar)
{
int ret;
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- ret = ath10k_wmi_10x_cmd_init(ar);
- else
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ret = ath10k_wmi_10_2_cmd_init(ar);
+ else
+ ret = ath10k_wmi_10x_cmd_init(ar);
+ } else {
ret = ath10k_wmi_main_cmd_init(ar);
+ }
return ret;
}
@@ -2822,7 +3300,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
if (len < 0)
return len; /* len contains error code here */
- skb = ath10k_wmi_alloc_skb(len);
+ skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -2865,8 +3343,8 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
channels->num_chan = __cpu_to_le32(arg->n_channels);
for (i = 0; i < arg->n_channels; i++)
- channels->channel_list[i] =
- __cpu_to_le32(arg->channels[i]);
+ channels->channel_list[i].freq =
+ __cpu_to_le16(arg->channels[i]);
off += sizeof(*channels);
off += sizeof(__le32) * arg->n_channels;
@@ -2918,7 +3396,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
return -EINVAL;
}
- ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
}
@@ -2960,7 +3438,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
return -EINVAL;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2976,7 +3454,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
cmd->scan_id = __cpu_to_le32(scan_id);
cmd->scan_req_id = __cpu_to_le32(req_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi stop scan reqid %d req_type %d vdev/scan_id %d\n",
arg->req_id, arg->req_type, arg->u.scan_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
@@ -2990,7 +3468,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
struct wmi_vdev_create_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3000,7 +3478,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
cmd->vdev_subtype = __cpu_to_le32(subtype);
memcpy(cmd->vdev_macaddr.addr, macaddr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"WMI vdev create: id %d type %d subtype %d macaddr %pM\n",
vdev_id, type, subtype, macaddr);
@@ -3012,14 +3490,14 @@ int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
struct wmi_vdev_delete_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_vdev_delete_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"WMI vdev delete id %d\n", vdev_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
@@ -3052,7 +3530,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
else
return -EINVAL; /* should not happen, we already check cmd_id */
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3090,7 +3568,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
cmd->chan.reg_classid = arg->channel.reg_class_id;
cmd->chan.antenna_max = arg->channel.max_antenna_gain;
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, "
"ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id,
flags, arg->channel.freq, arg->channel.mode,
@@ -3120,14 +3598,14 @@ int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
struct wmi_vdev_stop_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_vdev_stop_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
}
@@ -3137,7 +3615,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
struct wmi_vdev_up_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3146,7 +3624,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
cmd->vdev_assoc_id = __cpu_to_le32(aid);
memcpy(&cmd->vdev_bssid.addr, bssid, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n",
vdev_id, aid, bssid);
@@ -3158,14 +3636,14 @@ int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
struct wmi_vdev_down_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_vdev_down_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mgmt vdev down id 0x%x\n", vdev_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
@@ -3178,13 +3656,13 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
struct sk_buff *skb;
if (param_id == WMI_VDEV_PARAM_UNSUPPORTED) {
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"vdev param %d not supported by firmware\n",
param_id);
return -EOPNOTSUPP;
}
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3193,7 +3671,7 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
cmd->param_id = __cpu_to_le32(param_id);
cmd->param_value = __cpu_to_le32(param_value);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev id 0x%x set param %d value %d\n",
vdev_id, param_id, param_value);
@@ -3211,7 +3689,7 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
return -EINVAL;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->key_len);
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len);
if (!skb)
return -ENOMEM;
@@ -3229,20 +3707,76 @@ 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,
+ ath10k_dbg(ar, 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,
ar->wmi.cmd->vdev_install_key_cmdid);
}
+int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+ const struct wmi_vdev_spectral_conf_arg *arg)
+{
+ struct wmi_vdev_spectral_conf_cmd *cmd;
+ struct sk_buff *skb;
+ u32 cmdid;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+ cmd->scan_count = __cpu_to_le32(arg->scan_count);
+ cmd->scan_period = __cpu_to_le32(arg->scan_period);
+ cmd->scan_priority = __cpu_to_le32(arg->scan_priority);
+ cmd->scan_fft_size = __cpu_to_le32(arg->scan_fft_size);
+ cmd->scan_gc_ena = __cpu_to_le32(arg->scan_gc_ena);
+ cmd->scan_restart_ena = __cpu_to_le32(arg->scan_restart_ena);
+ cmd->scan_noise_floor_ref = __cpu_to_le32(arg->scan_noise_floor_ref);
+ cmd->scan_init_delay = __cpu_to_le32(arg->scan_init_delay);
+ cmd->scan_nb_tone_thr = __cpu_to_le32(arg->scan_nb_tone_thr);
+ cmd->scan_str_bin_thr = __cpu_to_le32(arg->scan_str_bin_thr);
+ cmd->scan_wb_rpt_mode = __cpu_to_le32(arg->scan_wb_rpt_mode);
+ cmd->scan_rssi_rpt_mode = __cpu_to_le32(arg->scan_rssi_rpt_mode);
+ cmd->scan_rssi_thr = __cpu_to_le32(arg->scan_rssi_thr);
+ cmd->scan_pwr_format = __cpu_to_le32(arg->scan_pwr_format);
+ cmd->scan_rpt_mode = __cpu_to_le32(arg->scan_rpt_mode);
+ cmd->scan_bin_scale = __cpu_to_le32(arg->scan_bin_scale);
+ cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj);
+ cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask);
+
+ cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
+
+int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+ u32 enable)
+{
+ struct wmi_vdev_spectral_enable_cmd *cmd;
+ struct sk_buff *skb;
+ u32 cmdid;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->trigger_cmd = __cpu_to_le32(trigger);
+ cmd->enable_cmd = __cpu_to_le32(enable);
+
+ cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
+
int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
const u8 peer_addr[ETH_ALEN])
{
struct wmi_peer_create_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3250,7 +3784,7 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
cmd->vdev_id = __cpu_to_le32(vdev_id);
memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer create vdev_id %d peer_addr %pM\n",
vdev_id, peer_addr);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
@@ -3262,7 +3796,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
struct wmi_peer_delete_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3270,7 +3804,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
cmd->vdev_id = __cpu_to_le32(vdev_id);
memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer delete vdev_id %d peer_addr %pM\n",
vdev_id, peer_addr);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
@@ -3282,7 +3816,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
struct wmi_peer_flush_tids_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3291,7 +3825,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap);
memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer flush vdev_id %d peer_addr %pM tids %08x\n",
vdev_id, peer_addr, tid_bitmap);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
@@ -3304,7 +3838,7 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
struct wmi_peer_set_param_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3314,7 +3848,7 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
cmd->param_value = __cpu_to_le32(param_value);
memcpy(&cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev %d peer 0x%pM set param %d value %d\n",
vdev_id, peer_addr, param_id, param_value);
@@ -3327,7 +3861,7 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
struct wmi_sta_powersave_mode_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3335,7 +3869,7 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
cmd->vdev_id = __cpu_to_le32(vdev_id);
cmd->sta_ps_mode = __cpu_to_le32(psmode);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi set powersave id 0x%x mode %d\n",
vdev_id, psmode);
@@ -3350,7 +3884,7 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
struct wmi_sta_powersave_param_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3359,7 +3893,7 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
cmd->param_id = __cpu_to_le32(param_id);
cmd->param_value = __cpu_to_le32(value);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi sta ps param vdev_id 0x%x param %d value %d\n",
vdev_id, param_id, value);
return ath10k_wmi_cmd_send(ar, skb,
@@ -3375,7 +3909,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
if (!mac)
return -EINVAL;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3385,7 +3919,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
cmd->param_value = __cpu_to_le32(value);
memcpy(&cmd->peer_macaddr, mac, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n",
vdev_id, param_id, value, mac);
@@ -3405,7 +3939,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel);
- skb = ath10k_wmi_alloc_skb(len);
+ skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb)
return -EINVAL;
@@ -3447,24 +3981,12 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
}
-int ath10k_wmi_peer_assoc(struct ath10k *ar,
- const struct wmi_peer_assoc_complete_arg *arg)
+static void
+ath10k_wmi_peer_assoc_fill(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
{
- struct wmi_peer_assoc_complete_cmd *cmd;
- struct sk_buff *skb;
+ struct wmi_common_peer_assoc_complete_cmd *cmd = buf;
- if (arg->peer_mpdu_density > 16)
- return -EINVAL;
- if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
- return -EINVAL;
- if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
- return -EINVAL;
-
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- if (!skb)
- return -ENOMEM;
-
- cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
cmd->peer_new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
cmd->peer_associd = __cpu_to_le32(arg->peer_aid);
@@ -3499,8 +4021,80 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
__cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
cmd->peer_vht_rates.tx_mcs_set =
__cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_main(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct wmi_main_peer_assoc_complete_cmd *cmd = buf;
+
+ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+ memset(cmd->peer_ht_info, 0, sizeof(cmd->peer_ht_info));
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_10_1(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct wmi_10_2_peer_assoc_complete_cmd *cmd = buf;
+ int max_mcs, max_nss;
+ u32 info0;
+
+ /* TODO: Is using max values okay with firmware? */
+ max_mcs = 0xf;
+ max_nss = 0xf;
+
+ info0 = SM(max_mcs, WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX) |
+ SM(max_nss, WMI_PEER_ASSOC_INFO0_MAX_NSS);
+
+ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+ cmd->info0 = __cpu_to_le32(info0);
+}
+
+int ath10k_wmi_peer_assoc(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct sk_buff *skb;
+ int len;
+
+ if (arg->peer_mpdu_density > 16)
+ return -EINVAL;
+ if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
+ return -EINVAL;
+ if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
+ return -EINVAL;
+
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
+ else
+ len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
+ } else {
+ len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
+ }
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return -ENOMEM;
+
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
+ else
+ ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
+ } else {
+ ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
+ }
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer assoc vdev %d addr %pM (%s)\n",
arg->vdev_id, arg->addr,
arg->peer_reassoc ? "reassociate" : "new");
@@ -3518,7 +4112,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
int ret;
u16 fc;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3532,6 +4126,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
cmd->msdu_id = 0;
cmd->frame_control = __cpu_to_le32(fc);
cmd->flags = 0;
+ cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA);
if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
@@ -3565,7 +4160,7 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
struct wmi_pdev_set_wmm_params *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3575,7 +4170,7 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi);
ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
return ath10k_wmi_cmd_send(ar, skb,
ar->wmi.cmd->pdev_set_wmm_params_cmdid);
}
@@ -3585,14 +4180,14 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
struct wmi_request_stats_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_request_stats_cmd *)skb->data;
cmd->stats_id = __cpu_to_le32(stats_id);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
}
@@ -3602,7 +4197,7 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
struct wmi_force_fw_hang_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3610,7 +4205,7 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
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",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
type, delay_ms);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
}
@@ -3621,7 +4216,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
struct sk_buff *skb;
u32 cfg;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3642,7 +4237,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
cmd->config_enable = __cpu_to_le32(cfg);
cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi dbglog cfg modules %08x %08x config %08x %08x\n",
__le32_to_cpu(cmd->module_enable),
__le32_to_cpu(cmd->module_valid),
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index e93df2c..e708365 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -73,116 +73,279 @@ struct wmi_cmd_hdr {
#define HTC_PROTOCOL_VERSION 0x0002
#define WMI_PROTOCOL_VERSION 0x0002
-enum wmi_service_id {
- WMI_SERVICE_BEACON_OFFLOAD = 0, /* beacon offload */
- WMI_SERVICE_SCAN_OFFLOAD, /* scan offload */
- WMI_SERVICE_ROAM_OFFLOAD, /* roam offload */
- WMI_SERVICE_BCN_MISS_OFFLOAD, /* beacon miss offload */
- WMI_SERVICE_STA_PWRSAVE, /* fake sleep + basic power save */
- WMI_SERVICE_STA_ADVANCED_PWRSAVE, /* uapsd, pspoll, force sleep */
- WMI_SERVICE_AP_UAPSD, /* uapsd on AP */
- WMI_SERVICE_AP_DFS, /* DFS on AP */
- WMI_SERVICE_11AC, /* supports 11ac */
- WMI_SERVICE_BLOCKACK, /* Supports triggering ADDBA/DELBA from host*/
- WMI_SERVICE_PHYERR, /* PHY error */
- WMI_SERVICE_BCN_FILTER, /* Beacon filter support */
- WMI_SERVICE_RTT, /* RTT (round trip time) support */
- WMI_SERVICE_RATECTRL, /* Rate-control */
- WMI_SERVICE_WOW, /* WOW Support */
- WMI_SERVICE_RATECTRL_CACHE, /* Rate-control caching */
- WMI_SERVICE_IRAM_TIDS, /* TIDs in IRAM */
- WMI_SERVICE_ARPNS_OFFLOAD, /* ARP NS Offload support */
- WMI_SERVICE_NLO, /* Network list offload service */
- WMI_SERVICE_GTK_OFFLOAD, /* GTK offload */
- WMI_SERVICE_SCAN_SCH, /* Scan Scheduler Service */
- WMI_SERVICE_CSA_OFFLOAD, /* CSA offload service */
- WMI_SERVICE_CHATTER, /* Chatter service */
- WMI_SERVICE_COEX_FREQAVOID, /* FW report freq range to avoid */
- WMI_SERVICE_PACKET_POWER_SAVE, /* packet power save service */
- WMI_SERVICE_FORCE_FW_HANG, /* To test fw recovery mechanism */
- WMI_SERVICE_GPIO, /* GPIO service */
- WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, /* Modulated DTIM support */
- WMI_STA_UAPSD_BASIC_AUTO_TRIG, /* UAPSD AC Trigger Generation */
- WMI_STA_UAPSD_VAR_AUTO_TRIG, /* -do- */
- WMI_SERVICE_STA_KEEP_ALIVE, /* STA keep alive mechanism support */
- WMI_SERVICE_TX_ENCAP, /* Packet type for TX encapsulation */
-
- WMI_SERVICE_LAST,
- WMI_MAX_SERVICE = 64 /* max service */
+enum wmi_service {
+ WMI_SERVICE_BEACON_OFFLOAD = 0,
+ WMI_SERVICE_SCAN_OFFLOAD,
+ WMI_SERVICE_ROAM_OFFLOAD,
+ WMI_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_SERVICE_STA_PWRSAVE,
+ WMI_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_SERVICE_AP_UAPSD,
+ WMI_SERVICE_AP_DFS,
+ WMI_SERVICE_11AC,
+ WMI_SERVICE_BLOCKACK,
+ WMI_SERVICE_PHYERR,
+ WMI_SERVICE_BCN_FILTER,
+ WMI_SERVICE_RTT,
+ WMI_SERVICE_RATECTRL,
+ WMI_SERVICE_WOW,
+ WMI_SERVICE_RATECTRL_CACHE,
+ WMI_SERVICE_IRAM_TIDS,
+ WMI_SERVICE_ARPNS_OFFLOAD,
+ WMI_SERVICE_NLO,
+ WMI_SERVICE_GTK_OFFLOAD,
+ WMI_SERVICE_SCAN_SCH,
+ WMI_SERVICE_CSA_OFFLOAD,
+ WMI_SERVICE_CHATTER,
+ WMI_SERVICE_COEX_FREQAVOID,
+ WMI_SERVICE_PACKET_POWER_SAVE,
+ WMI_SERVICE_FORCE_FW_HANG,
+ WMI_SERVICE_GPIO,
+ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+ WMI_SERVICE_STA_KEEP_ALIVE,
+ WMI_SERVICE_TX_ENCAP,
+ WMI_SERVICE_BURST,
+ WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+ WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+};
+
+enum wmi_10x_service {
+ WMI_10X_SERVICE_BEACON_OFFLOAD = 0,
+ WMI_10X_SERVICE_SCAN_OFFLOAD,
+ WMI_10X_SERVICE_ROAM_OFFLOAD,
+ WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_10X_SERVICE_STA_PWRSAVE,
+ WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_10X_SERVICE_AP_UAPSD,
+ WMI_10X_SERVICE_AP_DFS,
+ WMI_10X_SERVICE_11AC,
+ WMI_10X_SERVICE_BLOCKACK,
+ WMI_10X_SERVICE_PHYERR,
+ WMI_10X_SERVICE_BCN_FILTER,
+ WMI_10X_SERVICE_RTT,
+ WMI_10X_SERVICE_RATECTRL,
+ WMI_10X_SERVICE_WOW,
+ WMI_10X_SERVICE_RATECTRL_CACHE,
+ WMI_10X_SERVICE_IRAM_TIDS,
+ WMI_10X_SERVICE_BURST,
+
+ /* introduced in 10.2 */
+ WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+ WMI_10X_SERVICE_FORCE_FW_HANG,
+ WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+};
+
+enum wmi_main_service {
+ WMI_MAIN_SERVICE_BEACON_OFFLOAD = 0,
+ WMI_MAIN_SERVICE_SCAN_OFFLOAD,
+ WMI_MAIN_SERVICE_ROAM_OFFLOAD,
+ WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_MAIN_SERVICE_STA_PWRSAVE,
+ WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_MAIN_SERVICE_AP_UAPSD,
+ WMI_MAIN_SERVICE_AP_DFS,
+ WMI_MAIN_SERVICE_11AC,
+ WMI_MAIN_SERVICE_BLOCKACK,
+ WMI_MAIN_SERVICE_PHYERR,
+ WMI_MAIN_SERVICE_BCN_FILTER,
+ WMI_MAIN_SERVICE_RTT,
+ WMI_MAIN_SERVICE_RATECTRL,
+ WMI_MAIN_SERVICE_WOW,
+ WMI_MAIN_SERVICE_RATECTRL_CACHE,
+ WMI_MAIN_SERVICE_IRAM_TIDS,
+ WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
+ WMI_MAIN_SERVICE_NLO,
+ WMI_MAIN_SERVICE_GTK_OFFLOAD,
+ WMI_MAIN_SERVICE_SCAN_SCH,
+ WMI_MAIN_SERVICE_CSA_OFFLOAD,
+ WMI_MAIN_SERVICE_CHATTER,
+ WMI_MAIN_SERVICE_COEX_FREQAVOID,
+ WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
+ WMI_MAIN_SERVICE_FORCE_FW_HANG,
+ WMI_MAIN_SERVICE_GPIO,
+ WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+ WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+ WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+ WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
+ WMI_MAIN_SERVICE_TX_ENCAP,
};
static inline char *wmi_service_name(int service_id)
{
+#define SVCSTR(x) case x: return #x
+
switch (service_id) {
- case WMI_SERVICE_BEACON_OFFLOAD:
- return "BEACON_OFFLOAD";
- case WMI_SERVICE_SCAN_OFFLOAD:
- return "SCAN_OFFLOAD";
- case WMI_SERVICE_ROAM_OFFLOAD:
- return "ROAM_OFFLOAD";
- case WMI_SERVICE_BCN_MISS_OFFLOAD:
- return "BCN_MISS_OFFLOAD";
- case WMI_SERVICE_STA_PWRSAVE:
- return "STA_PWRSAVE";
- case WMI_SERVICE_STA_ADVANCED_PWRSAVE:
- return "STA_ADVANCED_PWRSAVE";
- case WMI_SERVICE_AP_UAPSD:
- return "AP_UAPSD";
- case WMI_SERVICE_AP_DFS:
- return "AP_DFS";
- case WMI_SERVICE_11AC:
- return "11AC";
- case WMI_SERVICE_BLOCKACK:
- return "BLOCKACK";
- case WMI_SERVICE_PHYERR:
- return "PHYERR";
- case WMI_SERVICE_BCN_FILTER:
- return "BCN_FILTER";
- case WMI_SERVICE_RTT:
- return "RTT";
- case WMI_SERVICE_RATECTRL:
- return "RATECTRL";
- case WMI_SERVICE_WOW:
- return "WOW";
- case WMI_SERVICE_RATECTRL_CACHE:
- return "RATECTRL CACHE";
- case WMI_SERVICE_IRAM_TIDS:
- return "IRAM TIDS";
- case WMI_SERVICE_ARPNS_OFFLOAD:
- return "ARPNS_OFFLOAD";
- case WMI_SERVICE_NLO:
- return "NLO";
- case WMI_SERVICE_GTK_OFFLOAD:
- return "GTK_OFFLOAD";
- case WMI_SERVICE_SCAN_SCH:
- return "SCAN_SCH";
- case WMI_SERVICE_CSA_OFFLOAD:
- return "CSA_OFFLOAD";
- case WMI_SERVICE_CHATTER:
- return "CHATTER";
- case WMI_SERVICE_COEX_FREQAVOID:
- return "COEX_FREQAVOID";
- case WMI_SERVICE_PACKET_POWER_SAVE:
- return "PACKET_POWER_SAVE";
- case WMI_SERVICE_FORCE_FW_HANG:
- return "FORCE FW HANG";
- case WMI_SERVICE_GPIO:
- return "GPIO";
- case WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM:
- return "MODULATED DTIM";
- case WMI_STA_UAPSD_BASIC_AUTO_TRIG:
- return "BASIC UAPSD";
- case WMI_STA_UAPSD_VAR_AUTO_TRIG:
- return "VAR UAPSD";
- case WMI_SERVICE_STA_KEEP_ALIVE:
- return "STA KEEP ALIVE";
- case WMI_SERVICE_TX_ENCAP:
- return "TX ENCAP";
+ SVCSTR(WMI_SERVICE_BEACON_OFFLOAD);
+ SVCSTR(WMI_SERVICE_SCAN_OFFLOAD);
+ SVCSTR(WMI_SERVICE_ROAM_OFFLOAD);
+ SVCSTR(WMI_SERVICE_BCN_MISS_OFFLOAD);
+ SVCSTR(WMI_SERVICE_STA_PWRSAVE);
+ SVCSTR(WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+ SVCSTR(WMI_SERVICE_AP_UAPSD);
+ SVCSTR(WMI_SERVICE_AP_DFS);
+ SVCSTR(WMI_SERVICE_11AC);
+ SVCSTR(WMI_SERVICE_BLOCKACK);
+ SVCSTR(WMI_SERVICE_PHYERR);
+ SVCSTR(WMI_SERVICE_BCN_FILTER);
+ SVCSTR(WMI_SERVICE_RTT);
+ SVCSTR(WMI_SERVICE_RATECTRL);
+ SVCSTR(WMI_SERVICE_WOW);
+ SVCSTR(WMI_SERVICE_RATECTRL_CACHE);
+ SVCSTR(WMI_SERVICE_IRAM_TIDS);
+ SVCSTR(WMI_SERVICE_ARPNS_OFFLOAD);
+ SVCSTR(WMI_SERVICE_NLO);
+ SVCSTR(WMI_SERVICE_GTK_OFFLOAD);
+ SVCSTR(WMI_SERVICE_SCAN_SCH);
+ SVCSTR(WMI_SERVICE_CSA_OFFLOAD);
+ SVCSTR(WMI_SERVICE_CHATTER);
+ SVCSTR(WMI_SERVICE_COEX_FREQAVOID);
+ SVCSTR(WMI_SERVICE_PACKET_POWER_SAVE);
+ SVCSTR(WMI_SERVICE_FORCE_FW_HANG);
+ SVCSTR(WMI_SERVICE_GPIO);
+ SVCSTR(WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+ SVCSTR(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+ SVCSTR(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+ SVCSTR(WMI_SERVICE_STA_KEEP_ALIVE);
+ SVCSTR(WMI_SERVICE_TX_ENCAP);
+ SVCSTR(WMI_SERVICE_BURST);
+ SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+ SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
default:
- return "UNKNOWN SERVICE\n";
+ return NULL;
}
+
+#undef SVCSTR
+}
+
+#define WMI_MAX_SERVICE 64
+
+#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
+ (__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
+ BIT((svc_id)%(sizeof(u32))))
+
+#define SVCMAP(x, y) \
+ do { \
+ if (WMI_SERVICE_IS_ENABLED((in), (x))) \
+ __set_bit(y, out); \
+ } while (0)
+
+static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out)
+{
+ SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD,
+ WMI_SERVICE_BEACON_OFFLOAD);
+ SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD,
+ WMI_SERVICE_SCAN_OFFLOAD);
+ SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD,
+ WMI_SERVICE_ROAM_OFFLOAD);
+ SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_SERVICE_BCN_MISS_OFFLOAD);
+ SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE,
+ WMI_SERVICE_STA_PWRSAVE);
+ SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+ SVCMAP(WMI_10X_SERVICE_AP_UAPSD,
+ WMI_SERVICE_AP_UAPSD);
+ SVCMAP(WMI_10X_SERVICE_AP_DFS,
+ WMI_SERVICE_AP_DFS);
+ SVCMAP(WMI_10X_SERVICE_11AC,
+ WMI_SERVICE_11AC);
+ SVCMAP(WMI_10X_SERVICE_BLOCKACK,
+ WMI_SERVICE_BLOCKACK);
+ SVCMAP(WMI_10X_SERVICE_PHYERR,
+ WMI_SERVICE_PHYERR);
+ SVCMAP(WMI_10X_SERVICE_BCN_FILTER,
+ WMI_SERVICE_BCN_FILTER);
+ SVCMAP(WMI_10X_SERVICE_RTT,
+ WMI_SERVICE_RTT);
+ SVCMAP(WMI_10X_SERVICE_RATECTRL,
+ WMI_SERVICE_RATECTRL);
+ SVCMAP(WMI_10X_SERVICE_WOW,
+ WMI_SERVICE_WOW);
+ SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE,
+ WMI_SERVICE_RATECTRL_CACHE);
+ SVCMAP(WMI_10X_SERVICE_IRAM_TIDS,
+ WMI_SERVICE_IRAM_TIDS);
+ SVCMAP(WMI_10X_SERVICE_BURST,
+ WMI_SERVICE_BURST);
+ SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+ WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+ SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG,
+ WMI_SERVICE_FORCE_FW_HANG);
+ SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+ WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
+}
+
+static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out)
+{
+ SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD,
+ WMI_SERVICE_BEACON_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD,
+ WMI_SERVICE_SCAN_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD,
+ WMI_SERVICE_ROAM_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_SERVICE_BCN_MISS_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE,
+ WMI_SERVICE_STA_PWRSAVE);
+ SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+ SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD,
+ WMI_SERVICE_AP_UAPSD);
+ SVCMAP(WMI_MAIN_SERVICE_AP_DFS,
+ WMI_SERVICE_AP_DFS);
+ SVCMAP(WMI_MAIN_SERVICE_11AC,
+ WMI_SERVICE_11AC);
+ SVCMAP(WMI_MAIN_SERVICE_BLOCKACK,
+ WMI_SERVICE_BLOCKACK);
+ SVCMAP(WMI_MAIN_SERVICE_PHYERR,
+ WMI_SERVICE_PHYERR);
+ SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER,
+ WMI_SERVICE_BCN_FILTER);
+ SVCMAP(WMI_MAIN_SERVICE_RTT,
+ WMI_SERVICE_RTT);
+ SVCMAP(WMI_MAIN_SERVICE_RATECTRL,
+ WMI_SERVICE_RATECTRL);
+ SVCMAP(WMI_MAIN_SERVICE_WOW,
+ WMI_SERVICE_WOW);
+ SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE,
+ WMI_SERVICE_RATECTRL_CACHE);
+ SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS,
+ WMI_SERVICE_IRAM_TIDS);
+ SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
+ WMI_SERVICE_ARPNS_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_NLO,
+ WMI_SERVICE_NLO);
+ SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD,
+ WMI_SERVICE_GTK_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH,
+ WMI_SERVICE_SCAN_SCH);
+ SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD,
+ WMI_SERVICE_CSA_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_CHATTER,
+ WMI_SERVICE_CHATTER);
+ SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID,
+ WMI_SERVICE_COEX_FREQAVOID);
+ SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
+ WMI_SERVICE_PACKET_POWER_SAVE);
+ SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG,
+ WMI_SERVICE_FORCE_FW_HANG);
+ SVCMAP(WMI_MAIN_SERVICE_GPIO,
+ WMI_SERVICE_GPIO);
+ SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+ SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+ SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+ SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
+ WMI_SERVICE_STA_KEEP_ALIVE);
+ SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP,
+ WMI_SERVICE_TX_ENCAP);
}
+#undef SVCMAP
#define WMI_SERVICE_BM_SIZE \
((WMI_MAX_SERVICE + sizeof(u32) - 1)/sizeof(u32))
@@ -803,6 +966,159 @@ enum wmi_10x_event_id {
WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1,
};
+enum wmi_10_2_cmd_id {
+ WMI_10_2_START_CMDID = 0x9000,
+ WMI_10_2_END_CMDID = 0x9FFF,
+ WMI_10_2_INIT_CMDID,
+ WMI_10_2_START_SCAN_CMDID = WMI_10_2_START_CMDID,
+ WMI_10_2_STOP_SCAN_CMDID,
+ WMI_10_2_SCAN_CHAN_LIST_CMDID,
+ WMI_10_2_ECHO_CMDID,
+ WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+ WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+ WMI_10_2_PDEV_SET_PARAM_CMDID,
+ WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+ WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+ WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+ WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+ WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+ WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+ WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+ WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+ WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+ WMI_10_2_VDEV_CREATE_CMDID,
+ WMI_10_2_VDEV_DELETE_CMDID,
+ WMI_10_2_VDEV_START_REQUEST_CMDID,
+ WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+ WMI_10_2_VDEV_UP_CMDID,
+ WMI_10_2_VDEV_STOP_CMDID,
+ WMI_10_2_VDEV_DOWN_CMDID,
+ WMI_10_2_VDEV_STANDBY_RESPONSE_CMDID,
+ WMI_10_2_VDEV_RESUME_RESPONSE_CMDID,
+ WMI_10_2_VDEV_SET_PARAM_CMDID,
+ WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+ WMI_10_2_VDEV_SET_DSCP_TID_MAP_CMDID,
+ WMI_10_2_PEER_CREATE_CMDID,
+ WMI_10_2_PEER_DELETE_CMDID,
+ WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+ WMI_10_2_PEER_SET_PARAM_CMDID,
+ WMI_10_2_PEER_ASSOC_CMDID,
+ WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+ WMI_10_2_PEER_UPDATE_WDS_ENTRY_CMDID,
+ WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+ WMI_10_2_PEER_MCAST_GROUP_CMDID,
+ WMI_10_2_BCN_TX_CMDID,
+ WMI_10_2_BCN_PRB_TMPL_CMDID,
+ WMI_10_2_BCN_FILTER_RX_CMDID,
+ WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+ WMI_10_2_MGMT_TX_CMDID,
+ WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+ WMI_10_2_ADDBA_SEND_CMDID,
+ WMI_10_2_ADDBA_STATUS_CMDID,
+ WMI_10_2_DELBA_SEND_CMDID,
+ WMI_10_2_ADDBA_SET_RESP_CMDID,
+ WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+ WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+ WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+ WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+ WMI_10_2_DBGLOG_CFG_CMDID,
+ WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+ WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+ WMI_10_2_PDEV_QVIT_CMDID,
+ WMI_10_2_ROAM_SCAN_MODE,
+ WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+ WMI_10_2_ROAM_SCAN_PERIOD,
+ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+ WMI_10_2_ROAM_AP_PROFILE,
+ WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+ WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+ WMI_10_2_OFL_SCAN_PERIOD,
+ WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+ WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+ WMI_10_2_P2P_GO_SET_BEACON_IE,
+ WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+ WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+ WMI_10_2_AP_PS_PEER_UAPSD_COEX_CMDID,
+ WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+ WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+ WMI_10_2_PDEV_SUSPEND_CMDID,
+ WMI_10_2_PDEV_RESUME_CMDID,
+ WMI_10_2_ADD_BCN_FILTER_CMDID,
+ WMI_10_2_RMV_BCN_FILTER_CMDID,
+ WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+ WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+ WMI_10_2_WOW_ENABLE_CMDID,
+ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+ WMI_10_2_RTT_MEASREQ_CMDID,
+ WMI_10_2_RTT_TSF_CMDID,
+ WMI_10_2_RTT_KEEPALIVE_CMDID,
+ WMI_10_2_PDEV_SEND_BCN_CMDID,
+ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+ WMI_10_2_REQUEST_STATS_CMDID,
+ WMI_10_2_GPIO_CONFIG_CMDID,
+ WMI_10_2_GPIO_OUTPUT_CMDID,
+ WMI_10_2_VDEV_RATEMASK_CMDID,
+ WMI_10_2_PDEV_SMART_ANT_ENABLE_CMDID,
+ WMI_10_2_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID,
+ WMI_10_2_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID,
+ WMI_10_2_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID,
+ WMI_10_2_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID,
+ WMI_10_2_FORCE_FW_HANG_CMDID,
+ WMI_10_2_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID,
+ WMI_10_2_PDEV_SET_CTL_TABLE_CMDID,
+ WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID,
+ WMI_10_2_PDEV_RATEPWR_TABLE_CMDID,
+ WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID,
+ WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
+};
+
+enum wmi_10_2_event_id {
+ WMI_10_2_SERVICE_READY_EVENTID = 0x8000,
+ WMI_10_2_READY_EVENTID,
+ WMI_10_2_DEBUG_MESG_EVENTID,
+ WMI_10_2_START_EVENTID = 0x9000,
+ WMI_10_2_END_EVENTID = 0x9FFF,
+ WMI_10_2_SCAN_EVENTID = WMI_10_2_START_EVENTID,
+ WMI_10_2_ECHO_EVENTID,
+ WMI_10_2_UPDATE_STATS_EVENTID,
+ WMI_10_2_INST_RSSI_STATS_EVENTID,
+ WMI_10_2_VDEV_START_RESP_EVENTID,
+ WMI_10_2_VDEV_STANDBY_REQ_EVENTID,
+ WMI_10_2_VDEV_RESUME_REQ_EVENTID,
+ WMI_10_2_VDEV_STOPPED_EVENTID,
+ WMI_10_2_PEER_STA_KICKOUT_EVENTID,
+ WMI_10_2_HOST_SWBA_EVENTID,
+ WMI_10_2_TBTTOFFSET_UPDATE_EVENTID,
+ WMI_10_2_MGMT_RX_EVENTID,
+ WMI_10_2_CHAN_INFO_EVENTID,
+ WMI_10_2_PHYERR_EVENTID,
+ WMI_10_2_ROAM_EVENTID,
+ WMI_10_2_PROFILE_MATCH,
+ WMI_10_2_DEBUG_PRINT_EVENTID,
+ WMI_10_2_PDEV_QVIT_EVENTID,
+ WMI_10_2_WLAN_PROFILE_DATA_EVENTID,
+ WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID,
+ WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID,
+ WMI_10_2_RTT_ERROR_REPORT_EVENTID,
+ WMI_10_2_RTT_KEEPALIVE_EVENTID,
+ WMI_10_2_WOW_WAKEUP_HOST_EVENTID,
+ WMI_10_2_DCS_INTERFERENCE_EVENTID,
+ WMI_10_2_PDEV_TPC_CONFIG_EVENTID,
+ WMI_10_2_GPIO_INPUT_EVENTID,
+ WMI_10_2_PEER_RATECODE_LIST_EVENTID,
+ WMI_10_2_GENERIC_BUFFER_EVENTID,
+ WMI_10_2_MCAST_BUF_RELEASE_EVENTID,
+ WMI_10_2_MCAST_LIST_AGEOUT_EVENTID,
+ WMI_10_2_WDS_PEER_EVENTID,
+ WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,
+};
+
enum wmi_phy_mode {
MODE_11A = 0, /* 11a Mode */
MODE_11G = 1, /* 11b/g Mode */
@@ -1076,10 +1392,6 @@ struct wlan_host_mem_req {
__le32 num_units;
} __packed;
-#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
- ((((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
- (1 << ((svc_id)%(sizeof(u32))))) != 0)
-
/*
* The following struct holds optional payload for
* wmi_service_ready_event,e.g., 11ac pass some of the
@@ -1551,6 +1863,16 @@ struct wmi_resource_config_10x {
__le32 max_frag_entries;
} __packed;
+struct wmi_resource_config_10_2 {
+ struct wmi_resource_config_10x common;
+ __le32 max_peer_ext_stats;
+ __le32 smart_ant_cap; /* 0-disable, 1-enable */
+ __le32 bk_min_free;
+ __le32 be_min_free;
+ __le32 vi_min_free;
+ __le32 vo_min_free;
+ __le32 rx_batchmode; /* 0-disable, 1-enable */
+} __packed;
#define NUM_UNITS_IS_NUM_VDEVS 0x1
#define NUM_UNITS_IS_NUM_PEERS 0x2
@@ -1588,11 +1910,28 @@ struct wmi_init_cmd_10x {
struct host_memory_chunk host_mem_chunks[1];
} __packed;
+struct wmi_init_cmd_10_2 {
+ struct wmi_resource_config_10_2 resource_config;
+ __le32 num_host_mem_chunks;
+
+ /*
+ * variable number of host memory chunks.
+ * This should be the last element in the structure
+ */
+ struct host_memory_chunk host_mem_chunks[1];
+} __packed;
+
+struct wmi_chan_list_entry {
+ __le16 freq;
+ u8 phy_mode; /* valid for 10.2 only */
+ u8 reserved;
+} __packed;
+
/* TLV for channel list */
struct wmi_chan_list {
__le32 tag; /* WMI_CHAN_LIST_TAG */
__le32 num_chan;
- __le32 channel_list[0];
+ struct wmi_chan_list_entry channel_list[0];
} __packed;
struct wmi_bssid_list {
@@ -1821,7 +2160,7 @@ struct wmi_start_scan_arg {
u32 n_bssids;
u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN];
- u32 channels[64];
+ u16 channels[64];
struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID];
struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID];
};
@@ -2067,6 +2406,7 @@ struct wmi_comb_phyerr_rx_event {
#define PHYERR_TLV_SIG 0xBB
#define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB
#define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8
+#define PHYERR_TLV_TAG_SPECTRAL_SUMMARY_REPORT 0xF9
struct phyerr_radar_report {
__le32 reg0; /* RADAR_REPORT_REG0_* */
@@ -2515,6 +2855,19 @@ enum wmi_10x_pdev_param {
WMI_10X_PDEV_PARAM_BURST_DUR,
/* Set Bursting Enable*/
WMI_10X_PDEV_PARAM_BURST_ENABLE,
+
+ /* following are available as of firmware 10.2 */
+ WMI_10X_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA,
+ WMI_10X_PDEV_PARAM_IGMPMLD_OVERRIDE,
+ WMI_10X_PDEV_PARAM_IGMPMLD_TID,
+ WMI_10X_PDEV_PARAM_ANTENNA_GAIN,
+ WMI_10X_PDEV_PARAM_RX_DECAP_MODE,
+ WMI_10X_PDEV_PARAM_RX_FILTER,
+ WMI_10X_PDEV_PARAM_SET_MCAST_TO_UCAST_TID,
+ WMI_10X_PDEV_PARAM_PROXY_STA_MODE,
+ WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE,
+ WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
+ WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
};
struct wmi_pdev_set_param_cmd {
@@ -3387,6 +3740,14 @@ enum wmi_10x_vdev_param {
WMI_10X_VDEV_PARAM_ENABLE_RTSCTS,
WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
+
+ /* following are available as of firmware 10.2 */
+ WMI_10X_VDEV_PARAM_TX_ENCAP_TYPE,
+ WMI_10X_VDEV_PARAM_CABQ_MAXDUR,
+ WMI_10X_VDEV_PARAM_MFPTEST_SET,
+ WMI_10X_VDEV_PARAM_RTS_FIXED_RATE,
+ WMI_10X_VDEV_PARAM_VHT_SGIMASK,
+ WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
};
/* slot time long */
@@ -3444,6 +3805,98 @@ struct wmi_vdev_simple_event {
/* unsupported VDEV combination */
#define WMI_INIFIED_VDEV_START_RESPONSE_NOT_SUPPORTED 0x2
+/* TODO: please add more comments if you have in-depth information */
+struct wmi_vdev_spectral_conf_cmd {
+ __le32 vdev_id;
+
+ /* number of fft samples to send (0 for infinite) */
+ __le32 scan_count;
+ __le32 scan_period;
+ __le32 scan_priority;
+
+ /* number of bins in the FFT: 2^(fft_size - bin_scale) */
+ __le32 scan_fft_size;
+ __le32 scan_gc_ena;
+ __le32 scan_restart_ena;
+ __le32 scan_noise_floor_ref;
+ __le32 scan_init_delay;
+ __le32 scan_nb_tone_thr;
+ __le32 scan_str_bin_thr;
+ __le32 scan_wb_rpt_mode;
+ __le32 scan_rssi_rpt_mode;
+ __le32 scan_rssi_thr;
+ __le32 scan_pwr_format;
+
+ /* rpt_mode: Format of FFT report to software for spectral scan
+ * triggered FFTs:
+ * 0: No FFT report (only spectral scan summary report)
+ * 1: 2-dword summary of metrics for each completed FFT + spectral
+ * scan summary report
+ * 2: 2-dword summary of metrics for each completed FFT +
+ * 1x- oversampled bins(in-band) per FFT + spectral scan summary
+ * report
+ * 3: 2-dword summary of metrics for each completed FFT +
+ * 2x- oversampled bins (all) per FFT + spectral scan summary
+ */
+ __le32 scan_rpt_mode;
+ __le32 scan_bin_scale;
+ __le32 scan_dbm_adj;
+ __le32 scan_chn_mask;
+} __packed;
+
+struct wmi_vdev_spectral_conf_arg {
+ u32 vdev_id;
+ u32 scan_count;
+ u32 scan_period;
+ u32 scan_priority;
+ u32 scan_fft_size;
+ u32 scan_gc_ena;
+ u32 scan_restart_ena;
+ u32 scan_noise_floor_ref;
+ u32 scan_init_delay;
+ u32 scan_nb_tone_thr;
+ u32 scan_str_bin_thr;
+ u32 scan_wb_rpt_mode;
+ u32 scan_rssi_rpt_mode;
+ u32 scan_rssi_thr;
+ u32 scan_pwr_format;
+ u32 scan_rpt_mode;
+ u32 scan_bin_scale;
+ u32 scan_dbm_adj;
+ u32 scan_chn_mask;
+};
+
+#define WMI_SPECTRAL_ENABLE_DEFAULT 0
+#define WMI_SPECTRAL_COUNT_DEFAULT 0
+#define WMI_SPECTRAL_PERIOD_DEFAULT 35
+#define WMI_SPECTRAL_PRIORITY_DEFAULT 1
+#define WMI_SPECTRAL_FFT_SIZE_DEFAULT 7
+#define WMI_SPECTRAL_GC_ENA_DEFAULT 1
+#define WMI_SPECTRAL_RESTART_ENA_DEFAULT 0
+#define WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT -96
+#define WMI_SPECTRAL_INIT_DELAY_DEFAULT 80
+#define WMI_SPECTRAL_NB_TONE_THR_DEFAULT 12
+#define WMI_SPECTRAL_STR_BIN_THR_DEFAULT 8
+#define WMI_SPECTRAL_WB_RPT_MODE_DEFAULT 0
+#define WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT 0
+#define WMI_SPECTRAL_RSSI_THR_DEFAULT 0xf0
+#define WMI_SPECTRAL_PWR_FORMAT_DEFAULT 0
+#define WMI_SPECTRAL_RPT_MODE_DEFAULT 2
+#define WMI_SPECTRAL_BIN_SCALE_DEFAULT 1
+#define WMI_SPECTRAL_DBM_ADJ_DEFAULT 1
+#define WMI_SPECTRAL_CHN_MASK_DEFAULT 1
+
+struct wmi_vdev_spectral_enable_cmd {
+ __le32 vdev_id;
+ __le32 trigger_cmd;
+ __le32 enable_cmd;
+} __packed;
+
+#define WMI_SPECTRAL_TRIGGER_CMD_TRIGGER 1
+#define WMI_SPECTRAL_TRIGGER_CMD_CLEAR 2
+#define WMI_SPECTRAL_ENABLE_CMD_ENABLE 1
+#define WMI_SPECTRAL_ENABLE_CMD_DISABLE 2
+
/* Beacon processing related command and event structures */
struct wmi_bcn_tx_hdr {
__le32 vdev_id;
@@ -3470,6 +3923,11 @@ enum wmi_bcn_tx_ref_flags {
WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
};
+/* TODO: It is unclear why "no antenna" works while any other seemingly valid
+ * chainmask yields no beacons on the air at all.
+ */
+#define WMI_BCN_TX_REF_DEF_ANTENNA 0
+
struct wmi_bcn_tx_ref_cmd {
__le32 vdev_id;
__le32 data_len;
@@ -3481,6 +3939,8 @@ struct wmi_bcn_tx_ref_cmd {
__le32 frame_control;
/* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
__le32 flags;
+ /* introduced in 10.2 */
+ __le32 antenna_mask;
} __packed;
/* Beacon filter */
@@ -4053,7 +4513,7 @@ struct wmi_peer_set_q_empty_callback_cmd {
/* Maximum listen interval supported by hw in units of beacon interval */
#define ATH10K_MAX_HW_LISTEN_INTERVAL 5
-struct wmi_peer_assoc_complete_cmd {
+struct wmi_common_peer_assoc_complete_cmd {
struct wmi_mac_addr peer_macaddr;
__le32 vdev_id;
__le32 peer_new_assoc; /* 1=assoc, 0=reassoc */
@@ -4071,11 +4531,30 @@ struct wmi_peer_assoc_complete_cmd {
__le32 peer_vht_caps;
__le32 peer_phymode;
struct wmi_vht_rate_set peer_vht_rates;
+};
+
+struct wmi_main_peer_assoc_complete_cmd {
+ struct wmi_common_peer_assoc_complete_cmd cmd;
+
/* HT Operation Element of the peer. Five bytes packed in 2
* INT32 array and filled from lsb to msb. */
__le32 peer_ht_info[2];
} __packed;
+struct wmi_10_1_peer_assoc_complete_cmd {
+ struct wmi_common_peer_assoc_complete_cmd cmd;
+} __packed;
+
+#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_LSB 0
+#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_MASK 0x0f
+#define WMI_PEER_ASSOC_INFO0_MAX_NSS_LSB 4
+#define WMI_PEER_ASSOC_INFO0_MAX_NSS_MASK 0xf0
+
+struct wmi_10_2_peer_assoc_complete_cmd {
+ struct wmi_common_peer_assoc_complete_cmd cmd;
+ __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
+} __packed;
+
struct wmi_peer_assoc_complete_arg {
u8 addr[ETH_ALEN];
u32 vdev_id;
@@ -4290,6 +4769,10 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
u32 param_id, u32 param_value);
int ath10k_wmi_vdev_install_key(struct ath10k *ar,
const struct wmi_vdev_install_key_arg *arg);
+int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+ const struct wmi_vdev_spectral_conf_arg *arg);
+int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+ u32 enable);
int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
const u8 peer_addr[ETH_ALEN]);
int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 7106547..66b6366 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -351,8 +351,7 @@ void ath5k_hw_deinit(struct ath5k_hw *ah)
{
__set_bit(ATH_STAT_INVALID, ah->status);
- if (ah->ah_rf_banks != NULL)
- kfree(ah->ah_rf_banks);
+ kfree(ah->ah_rf_banks);
ath5k_eeprom_detach(ah);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 8ad2550..59a8724 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1423,7 +1423,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
break;
}
- if (rxs->rate_idx >= 0 && rs->rs_rate ==
+ if (rs->rs_rate ==
ah->sbands[ah->curchan->band].bitrates[rxs->rate_idx].hw_value_short)
rxs->flag |= RX_FLAG_SHORTPRE;
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index b8d031a..30e4e1f 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -894,6 +894,100 @@ static const struct file_operations fops_queue = {
.llseek = default_llseek,
};
+/* debugfs: eeprom */
+
+struct eeprom_private {
+ u16 *buf;
+ int len;
+};
+
+static int open_file_eeprom(struct inode *inode, struct file *file)
+{
+ struct eeprom_private *ep;
+ struct ath5k_hw *ah = inode->i_private;
+ bool res;
+ int i, ret;
+ u32 eesize;
+ u16 val, *buf;
+
+ /* Get eeprom size */
+
+ res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val);
+ if (!res)
+ return -EACCES;
+
+ if (val == 0) {
+ eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE;
+ } else {
+ eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
+ AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
+ ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val);
+ eesize = eesize | val;
+ }
+
+ if (eesize > 4096)
+ return -EINVAL;
+
+ /* Create buffer and read in eeprom */
+
+ buf = vmalloc(eesize);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < eesize; ++i) {
+ AR5K_EEPROM_READ(i, val);
+ buf[i] = val;
+ }
+
+ /* Create private struct and assign to file */
+
+ ep = kmalloc(sizeof(*ep), GFP_KERNEL);
+ if (!ep) {
+ ret = -ENOMEM;
+ goto freebuf;
+ }
+
+ ep->buf = buf;
+ ep->len = i;
+
+ file->private_data = (void *)ep;
+
+ return 0;
+
+freebuf:
+ vfree(buf);
+err:
+ return ret;
+
+}
+
+static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct eeprom_private *ep = file->private_data;
+
+ return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len);
+}
+
+static int release_file_eeprom(struct inode *inode, struct file *file)
+{
+ struct eeprom_private *ep = file->private_data;
+
+ vfree(ep->buf);
+ kfree(ep);
+
+ return 0;
+}
+
+static const struct file_operations fops_eeprom = {
+ .open = open_file_eeprom,
+ .read = read_file_eeprom,
+ .release = release_file_eeprom,
+ .owner = THIS_MODULE,
+};
+
void
ath5k_debug_init_device(struct ath5k_hw *ah)
@@ -921,6 +1015,8 @@ ath5k_debug_init_device(struct ath5k_hw *ah)
debugfs_create_file("misc", S_IRUSR, phydir, ah, &fops_misc);
+ debugfs_create_file("eeprom", S_IRUSR, phydir, ah, &fops_eeprom);
+
debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, ah,
&fops_frameerrors);
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 48a6a69b..2062d11 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -130,6 +130,7 @@ ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
led->ah = ah;
strncpy(led->name, name, sizeof(led->name));
+ led->name[sizeof(led->name)-1] = 0;
led->led_dev.name = led->name;
led->led_dev.default_trigger = trigger;
led->led_dev.brightness_set = ath5k_led_brightness_set;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index e535807..ba60e37 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -717,6 +717,7 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
memcpy(ie + 2, vif->ssid, vif->ssid_len);
memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
bss = cfg80211_inform_bss(ar->wiphy, chan,
+ CFG80211_BSS_FTYPE_UNKNOWN,
bssid, 0, cap_val, 100,
ie, 2 + vif->ssid_len + beacon_ie_len,
0, GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index fffd523..6e473fa 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1049,7 +1049,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
ar->hw.reserved_ram_size = le32_to_cpup(val);
ath6kl_dbg(ATH6KL_DBG_BOOT,
- "found reserved ram size ie 0x%d\n",
+ "found reserved ram size ie %d\n",
ar->hw.reserved_ram_size);
break;
case ATH6KL_FW_IE_CAPABILITIES:
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 21516bc..933aef0 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -225,7 +225,7 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
ret = ath6kl_hif_diag_write32(ar, address, value);
if (ret) {
- ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
+ ath6kl_err("failed to write 0x%x during diagnose window to 0x%x\n",
address, value);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 339d89f..eab0ab9 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -1400,6 +1400,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))},
{},
};
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index c443258..a6a5e40 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -1229,26 +1229,7 @@ static struct usb_driver ath6kl_usb_driver = {
.disable_hub_initiated_lpm = 1,
};
-static int ath6kl_usb_init(void)
-{
- int ret;
-
- ret = usb_register(&ath6kl_usb_driver);
- if (ret) {
- ath6kl_err("usb registration failed: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static void ath6kl_usb_exit(void)
-{
- usb_deregister(&ath6kl_usb_driver);
-}
-
-module_init(ath6kl_usb_init);
-module_exit(ath6kl_usb_exit);
+module_usb_driver(ath6kl_usb_driver);
MODULE_AUTHOR("Atheros Communications, Inc.");
MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices");
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 94df345..b921005 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -619,8 +619,7 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
dlen, freq, vif->probe_req_report);
if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0,
- GFP_ATOMIC);
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
return 0;
}
@@ -659,7 +658,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, GFP_ATOMIC);
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
return 0;
}
@@ -1093,7 +1092,6 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
u8 *buf;
struct ieee80211_channel *channel;
struct ath6kl *ar = wmi->parent_dev;
- struct ieee80211_mgmt *mgmt;
struct cfg80211_bss *bss;
if (len <= sizeof(struct wmi_bss_info_hdr2))
@@ -1139,39 +1137,15 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
}
}
- /*
- * In theory, use of cfg80211_inform_bss() would be more natural here
- * since we do not have the full frame. However, at least for now,
- * cfg80211 can only distinguish Beacon and Probe Response frames from
- * each other when using cfg80211_inform_bss_frame(), so let's build a
- * fake IEEE 802.11 header to be able to take benefit of this.
- */
- mgmt = kmalloc(24 + len, GFP_ATOMIC);
- if (mgmt == NULL)
- return -EINVAL;
-
- if (bih->frame_type == BEACON_FTYPE) {
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_BEACON);
- memset(mgmt->da, 0xff, ETH_ALEN);
- } else {
- struct net_device *dev = vif->ndev;
-
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_PROBE_RESP);
- memcpy(mgmt->da, dev->dev_addr, ETH_ALEN);
- }
- mgmt->duration = cpu_to_le16(0);
- memcpy(mgmt->sa, bih->bssid, ETH_ALEN);
- memcpy(mgmt->bssid, bih->bssid, ETH_ALEN);
- mgmt->seq_ctrl = cpu_to_le16(0);
-
- memcpy(&mgmt->u.beacon, buf, len);
-
- bss = cfg80211_inform_bss_frame(ar->wiphy, channel, mgmt,
- 24 + len, (bih->snr - 95) * 100,
- GFP_ATOMIC);
- kfree(mgmt);
+ bss = cfg80211_inform_bss(ar->wiphy, channel,
+ bih->frame_type == BEACON_FTYPE ?
+ CFG80211_BSS_FTYPE_BEACON :
+ CFG80211_BSS_FTYPE_PRESP,
+ bih->bssid, get_unaligned_le64((__le64 *)buf),
+ get_unaligned_le16(((__le16 *)buf) + 5),
+ get_unaligned_le16(((__le16 *)buf) + 4),
+ buf + 8 + 2 + 2, len - 8 - 2 - 2,
+ (bih->snr - 95) * 100, GFP_ATOMIC);
if (bss == NULL)
return -ENOMEM;
cfg80211_put_bss(ar->wiphy, bss);
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 8fcc029..b8f570e 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -130,6 +130,15 @@ config ATH9K_RFKILL
seconds. Turn off to save power, but enable it if you have
a platform that can toggle the RF-Kill GPIO.
+config ATH9K_CHANNEL_CONTEXT
+ bool "Channel Context support"
+ depends on ATH9K
+ default n
+ ---help---
+ This option enables channel context support in ath9k, which is needed
+ for multi-channel concurrency. Enable this if P2P PowerSave support
+ is required.
+
config ATH9K_HTC
tristate "Atheros HTC based wireless cards support"
depends on USB && MAC80211
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 7fc13a8..660c151 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -31,6 +31,7 @@
#include "spectral.h"
struct ath_node;
+struct ath_vif;
extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt;
@@ -313,7 +314,6 @@ struct ath_rx {
bool discard_next;
u32 *rxlink;
u32 num_pkts;
- unsigned int rxfilter;
struct list_head rxbuf;
struct ath_descdma rxdma;
struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
@@ -324,6 +324,10 @@ struct ath_rx {
u32 ampdu_ref;
};
+/*******************/
+/* Channel Context */
+/*******************/
+
struct ath_chanctx {
struct cfg80211_chan_def chandef;
struct list_head vifs;
@@ -345,6 +349,9 @@ struct ath_chanctx {
bool active;
bool assigned;
bool switch_after_beacon;
+
+ short nvifs;
+ unsigned int rxfilter;
};
enum ath_chanctx_event {
@@ -354,7 +361,9 @@ enum ath_chanctx_event {
ATH_CHANCTX_EVENT_BEACON_RECEIVED,
ATH_CHANCTX_EVENT_ASSOC,
ATH_CHANCTX_EVENT_SWITCH,
+ ATH_CHANCTX_EVENT_ASSIGN,
ATH_CHANCTX_EVENT_UNASSIGN,
+ ATH_CHANCTX_EVENT_CHANGE,
ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL,
};
@@ -369,6 +378,9 @@ enum ath_chanctx_state {
struct ath_chanctx_sched {
bool beacon_pending;
bool offchannel_pending;
+ bool wait_switch;
+ bool force_noa_update;
+ bool extend_absence;
enum ath_chanctx_state state;
u8 beacon_miss;
@@ -403,38 +415,124 @@ struct ath_offchannel {
int roc_duration;
int duration;
};
+
+#define case_rtn_string(val) case val: return #val
+
#define ath_for_each_chanctx(_sc, _ctx) \
for (ctx = &sc->chanctx[0]; \
ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \
ctx++)
-void ath9k_fill_chanctx_ops(void);
-void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
+void ath_chanctx_init(struct ath_softc *sc);
+void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+ struct cfg80211_chan_def *chandef);
+
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
static inline struct ath_chanctx *
ath_chanctx_get(struct ieee80211_chanctx_conf *ctx)
{
struct ath_chanctx **ptr = (void *) ctx->drv_priv;
return *ptr;
}
-void ath_chanctx_init(struct ath_softc *sc);
-void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
- struct cfg80211_chan_def *chandef);
-void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
- struct cfg80211_chan_def *chandef);
+
+bool ath9k_is_chanctx_enabled(void);
+void ath9k_fill_chanctx_ops(void);
+void ath9k_init_channel_context(struct ath_softc *sc);
+void ath9k_offchannel_init(struct ath_softc *sc);
+void ath9k_deinit_channel_context(struct ath_softc *sc);
+int ath9k_init_p2p(struct ath_softc *sc);
+void ath9k_deinit_p2p(struct ath_softc *sc);
+void ath9k_p2p_remove_vif(struct ath_softc *sc,
+ struct ieee80211_vif *vif);
+void ath9k_p2p_beacon_sync(struct ath_softc *sc);
+void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+ struct ieee80211_vif *vif);
+void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+ struct sk_buff *skb);
+void ath9k_p2p_ps_timer(void *priv);
+void ath9k_chanctx_wake_queues(struct ath_softc *sc);
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx);
-void ath_offchannel_timer(unsigned long data);
-void ath_offchannel_channel_change(struct ath_softc *sc);
-void ath_chanctx_offchan_switch(struct ath_softc *sc,
- struct ieee80211_channel *chan);
-struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
- bool active);
+
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
+ enum ath_chanctx_event ev);
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev);
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
enum ath_chanctx_event ev);
-void ath_chanctx_timer(unsigned long data);
+void ath_chanctx_set_next(struct ath_softc *sc, bool force);
+void ath_offchannel_next(struct ath_softc *sc);
+void ath_scan_complete(struct ath_softc *sc, bool abort);
+void ath_roc_complete(struct ath_softc *sc, bool abort);
+
+#else
+
+static inline bool ath9k_is_chanctx_enabled(void)
+{
+ return false;
+}
+static inline void ath9k_fill_chanctx_ops(void)
+{
+}
+static inline void ath9k_init_channel_context(struct ath_softc *sc)
+{
+}
+static inline void ath9k_offchannel_init(struct ath_softc *sc)
+{
+}
+static inline void ath9k_deinit_channel_context(struct ath_softc *sc)
+{
+}
+static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
+ enum ath_chanctx_event ev)
+{
+}
+static inline void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev)
+{
+}
+static inline void ath_chanctx_event(struct ath_softc *sc,
+ struct ieee80211_vif *vif,
+ enum ath_chanctx_event ev)
+{
+}
+static inline int ath9k_init_p2p(struct ath_softc *sc)
+{
+ return 0;
+}
+static inline void ath9k_deinit_p2p(struct ath_softc *sc)
+{
+}
+static inline void ath9k_p2p_remove_vif(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+}
+static inline void ath9k_p2p_beacon_sync(struct ath_softc *sc)
+{
+}
+static inline void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+}
+static inline void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+ struct sk_buff *skb)
+{
+}
+static inline void ath9k_p2p_ps_timer(struct ath_softc *sc)
+{
+}
+static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc)
+{
+}
+static inline void ath_chanctx_check_active(struct ath_softc *sc,
+ struct ath_chanctx *ctx)
+{
+}
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
-int ath_startrecv(struct ath_softc *sc);
+void ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
int ath_rx_init(struct ath_softc *sc, int nbufs);
@@ -479,6 +577,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
/* VIFs */
/********/
+#define P2P_DEFAULT_CTWIN 10
+
struct ath_vif {
struct list_head list;
@@ -497,8 +597,10 @@ struct ath_vif {
u32 offchannel_start;
u32 offchannel_duration;
- u32 periodic_noa_start;
- u32 periodic_noa_duration;
+ /* These are used for both periodic and one-shot */
+ u32 noa_start;
+ u32 noa_duration;
+ bool periodic_noa;
};
struct ath9k_vif_iter_data {
@@ -583,7 +685,6 @@ void ath9k_csa_update(struct ath_softc *sc);
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
#define ATH_PLL_WORK_INTERVAL 100
-void ath_chanctx_work(struct work_struct *work);
void ath_tx_complete_poll_work(struct work_struct *work);
void ath_reset_work(struct work_struct *work);
bool ath_hw_check(struct ath_softc *sc);
@@ -597,8 +698,6 @@ int ath_update_survey_stats(struct ath_softc *sc);
void ath_update_survey_nf(struct ath_softc *sc, int channel);
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
void ath_ps_full_sleep(unsigned long data);
-void ath9k_p2p_ps_timer(void *priv);
-void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);
void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
/**********/
@@ -849,12 +948,17 @@ struct ath_softc {
struct mutex mutex;
struct work_struct paprd_work;
struct work_struct hw_reset_work;
- struct work_struct chanctx_work;
struct completion paprd_complete;
wait_queue_head_t tx_wait;
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+ struct work_struct chanctx_work;
struct ath_gen_timer *p2p_ps_timer;
struct ath_vif *p2p_ps_vif;
+ struct ath_chanctx_sched sched;
+ struct ath_offchannel offchannel;
+ struct ath_chanctx *next_chan;
+#endif
unsigned long driver_data;
@@ -865,7 +969,6 @@ struct ath_softc {
bool ps_enabled;
bool ps_idle;
short nbcnvifs;
- short nvifs;
unsigned long ps_usecount;
struct ath_rx rx;
@@ -875,10 +978,7 @@ struct ath_softc {
struct cfg80211_chan_def cur_chandef;
struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX];
struct ath_chanctx *cur_chan;
- struct ath_chanctx *next_chan;
spinlock_t chan_lock;
- struct ath_offchannel offchannel;
- struct ath_chanctx_sched sched;
#ifdef CONFIG_MAC80211_LEDS
bool led_registered;
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index eaf8f05..a6af855 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -108,55 +108,6 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
}
-static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
- struct sk_buff *skb)
-{
- static const u8 noa_ie_hdr[] = {
- WLAN_EID_VENDOR_SPECIFIC, /* type */
- 0, /* length */
- 0x50, 0x6f, 0x9a, /* WFA OUI */
- 0x09, /* P2P subtype */
- 0x0c, /* Notice of Absence */
- 0x00, /* LSB of little-endian len */
- 0x00, /* MSB of little-endian len */
- };
-
- struct ieee80211_p2p_noa_attr *noa;
- int noa_len, noa_desc, i = 0;
- u8 *hdr;
-
- if (!avp->offchannel_duration && !avp->periodic_noa_duration)
- return;
-
- noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration;
- noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
-
- hdr = skb_put(skb, sizeof(noa_ie_hdr));
- memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
- hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
- hdr[7] = noa_len;
-
- noa = (void *) skb_put(skb, noa_len);
- memset(noa, 0, noa_len);
-
- noa->index = avp->noa_index;
- if (avp->periodic_noa_duration) {
- u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
-
- noa->desc[i].count = 255;
- noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start);
- noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
- noa->desc[i].interval = cpu_to_le32(interval);
- i++;
- }
-
- if (avp->offchannel_duration) {
- noa->desc[i].count = 1;
- noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
- noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
- }
-}
-
static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -232,7 +183,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
spin_unlock_bh(&cabq->axq_lock);
if (skb && cabq_depth) {
- if (sc->nvifs > 1) {
+ if (sc->cur_chan->nvifs > 1) {
ath_dbg(common, BEACON,
"Flushing previous cabq traffic\n");
ath_draintxq(sc, cabq);
@@ -427,9 +378,10 @@ void ath9k_beacon_tasklet(unsigned long data)
/* EDMA devices check that in the tx completion function. */
if (!edma) {
- if (sc->sched.beacon_pending)
- ath_chanctx_event(sc, NULL,
+ if (ath9k_is_chanctx_enabled()) {
+ ath_chanctx_beacon_sent_ev(sc,
ATH_CHANCTX_EVENT_BEACON_SENT);
+ }
if (ath9k_csa_is_finished(sc, vif))
return;
@@ -438,7 +390,10 @@ void ath9k_beacon_tasklet(unsigned long data)
if (!vif || !vif->bss_conf.enable_beacon)
return;
- ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
+ if (ath9k_is_chanctx_enabled()) {
+ ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
+ }
+
bf = ath9k_beacon_generate(sc->hw, vif);
if (sc->beacon.bmisscnt != 0) {
@@ -559,6 +514,18 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ if (ath9k_is_chanctx_enabled()) {
+ /*
+ * If the VIF is not present in the current channel context,
+ * then we can't do the usual opmode checks. Allow the
+ * beacon config for the VIF to be updated in this case and
+ * return immediately.
+ */
+ if (sc->cur_chan != avp->chanctx)
+ return true;
+ }
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
if ((vif->type != NL80211_IFTYPE_AP) ||
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index ba214eb..a1b3282 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -101,202 +101,6 @@ static int ath_set_channel(struct ath_softc *sc)
return 0;
}
-static bool
-ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
- bool powersave)
-{
- struct ieee80211_vif *vif = avp->vif;
- struct ieee80211_sta *sta = NULL;
- struct ieee80211_hdr_3addr *nullfunc;
- struct ath_tx_control txctl;
- struct sk_buff *skb;
- int band = sc->cur_chan->chandef.chan->band;
-
- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
- if (!vif->bss_conf.assoc)
- return false;
-
- skb = ieee80211_nullfunc_get(sc->hw, vif);
- if (!skb)
- return false;
-
- nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
- if (powersave)
- nullfunc->frame_control |=
- cpu_to_le16(IEEE80211_FCTL_PM);
-
- skb_set_queue_mapping(skb, IEEE80211_AC_VO);
- if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
- dev_kfree_skb_any(skb);
- return false;
- }
- break;
- default:
- return false;
- }
-
- memset(&txctl, 0, sizeof(txctl));
- txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.sta = sta;
- txctl.force_channel = true;
- if (ath_tx_start(sc->hw, skb, &txctl)) {
- ieee80211_free_txskb(sc->hw, skb);
- return false;
- }
-
- return true;
-}
-
-void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_vif *avp;
- bool active = false;
- u8 n_active = 0;
-
- if (!ctx)
- return;
-
- list_for_each_entry(avp, &ctx->vifs, list) {
- struct ieee80211_vif *vif = avp->vif;
-
- switch (vif->type) {
- case NL80211_IFTYPE_P2P_CLIENT:
- case NL80211_IFTYPE_STATION:
- if (vif->bss_conf.assoc)
- active = true;
- break;
- default:
- active = true;
- break;
- }
- }
- ctx->active = active;
-
- ath_for_each_chanctx(sc, ctx) {
- if (!ctx->assigned || list_empty(&ctx->vifs))
- continue;
- n_active++;
- }
-
- if (n_active <= 1) {
- clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
- return;
- }
- if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
- return;
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
-}
-
-static bool
-ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
-{
- struct ath_vif *avp;
- bool sent = false;
-
- rcu_read_lock();
- list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
- if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
- sent = true;
- }
- rcu_read_unlock();
-
- return sent;
-}
-
-static bool ath_chanctx_defer_switch(struct ath_softc *sc)
-{
- if (sc->cur_chan == &sc->offchannel.chan)
- return false;
-
- switch (sc->sched.state) {
- case ATH_CHANCTX_STATE_SWITCH:
- return false;
- case ATH_CHANCTX_STATE_IDLE:
- if (!sc->cur_chan->switch_after_beacon)
- return false;
-
- sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
- break;
- default:
- break;
- }
-
- return true;
-}
-
-static void ath_chanctx_set_next(struct ath_softc *sc, bool force)
-{
- struct timespec ts;
- bool measure_time = false;
- bool send_ps = false;
-
- spin_lock_bh(&sc->chan_lock);
- if (!sc->next_chan) {
- spin_unlock_bh(&sc->chan_lock);
- return;
- }
-
- if (!force && ath_chanctx_defer_switch(sc)) {
- spin_unlock_bh(&sc->chan_lock);
- return;
- }
-
- if (sc->cur_chan != sc->next_chan) {
- sc->cur_chan->stopped = true;
- spin_unlock_bh(&sc->chan_lock);
-
- if (sc->next_chan == &sc->offchannel.chan) {
- getrawmonotonic(&ts);
- measure_time = true;
- }
- __ath9k_flush(sc->hw, ~0, true);
-
- if (ath_chanctx_send_ps_frame(sc, true))
- __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
-
- send_ps = true;
- spin_lock_bh(&sc->chan_lock);
-
- if (sc->cur_chan != &sc->offchannel.chan) {
- getrawmonotonic(&sc->cur_chan->tsf_ts);
- sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
- }
- }
- sc->cur_chan = sc->next_chan;
- sc->cur_chan->stopped = false;
- sc->next_chan = NULL;
- sc->sched.offchannel_duration = 0;
- if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
- sc->sched.state = ATH_CHANCTX_STATE_IDLE;
-
- spin_unlock_bh(&sc->chan_lock);
-
- if (sc->sc_ah->chip_fullsleep ||
- memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
- sizeof(sc->cur_chandef))) {
- ath_set_channel(sc);
- if (measure_time)
- sc->sched.channel_switch_time =
- ath9k_hw_get_tsf_offset(&ts, NULL);
- }
- if (send_ps)
- ath_chanctx_send_ps_frame(sc, false);
-
- ath_offchannel_channel_change(sc);
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
-}
-
-void ath_chanctx_work(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc,
- chanctx_work);
- mutex_lock(&sc->mutex);
- ath_chanctx_set_next(sc, false);
- mutex_unlock(&sc->mutex);
-}
-
void ath_chanctx_init(struct ath_softc *sc)
{
struct ath_chanctx *ctx;
@@ -318,115 +122,124 @@ void ath_chanctx_init(struct ath_softc *sc)
for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
INIT_LIST_HEAD(&ctx->acq[j]);
}
- ctx = &sc->offchannel.chan;
- cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
- INIT_LIST_HEAD(&ctx->vifs);
- ctx->txpower = ATH_TXPOWER_MAX;
- for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
- INIT_LIST_HEAD(&ctx->acq[j]);
- sc->offchannel.chan.offchannel = true;
-
}
-void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+ struct cfg80211_chan_def *chandef)
{
- struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
- bool changed = false;
-
- if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
- return;
-
- if (!avp->chanctx)
- return;
-
- mutex_lock(&sc->mutex);
+ bool cur_chan;
spin_lock_bh(&sc->chan_lock);
- if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
- sc->next_chan = avp->chanctx;
- changed = true;
- }
- sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
+ if (chandef)
+ memcpy(&ctx->chandef, chandef, sizeof(*chandef));
+ cur_chan = sc->cur_chan == ctx;
spin_unlock_bh(&sc->chan_lock);
- if (changed)
- ath_chanctx_set_next(sc, true);
+ if (!cur_chan) {
+ ath_dbg(common, CHAN_CTX,
+ "Current context differs from the new context\n");
+ return;
+ }
- mutex_unlock(&sc->mutex);
+ ath_set_channel(sc);
}
-void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
- struct cfg80211_chan_def *chandef)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
- spin_lock_bh(&sc->chan_lock);
+/**********************************************************/
+/* Functions to handle the channel context state machine. */
+/**********************************************************/
- if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
- (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
- sc->sched.offchannel_pending = true;
- spin_unlock_bh(&sc->chan_lock);
- return;
+static const char *offchannel_state_string(enum ath_offchannel_state state)
+{
+ switch (state) {
+ case_rtn_string(ATH_OFFCHANNEL_IDLE);
+ case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND);
+ case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT);
+ case_rtn_string(ATH_OFFCHANNEL_SUSPEND);
+ case_rtn_string(ATH_OFFCHANNEL_ROC_START);
+ case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT);
+ case_rtn_string(ATH_OFFCHANNEL_ROC_DONE);
+ default:
+ return "unknown";
}
+}
- sc->next_chan = ctx;
- if (chandef)
- ctx->chandef = *chandef;
-
- if (sc->next_chan == &sc->offchannel.chan) {
- sc->sched.offchannel_duration =
- TU_TO_USEC(sc->offchannel.duration) +
- sc->sched.channel_switch_time;
+static const char *chanctx_event_string(enum ath_chanctx_event ev)
+{
+ switch (ev) {
+ case_rtn_string(ATH_CHANCTX_EVENT_BEACON_PREPARE);
+ case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT);
+ case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER);
+ case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED);
+ case_rtn_string(ATH_CHANCTX_EVENT_ASSOC);
+ case_rtn_string(ATH_CHANCTX_EVENT_SWITCH);
+ case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN);
+ case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN);
+ case_rtn_string(ATH_CHANCTX_EVENT_CHANGE);
+ case_rtn_string(ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
+ default:
+ return "unknown";
}
- spin_unlock_bh(&sc->chan_lock);
- ieee80211_queue_work(sc->hw, &sc->chanctx_work);
}
-void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
- struct cfg80211_chan_def *chandef)
+static const char *chanctx_state_string(enum ath_chanctx_state state)
{
- bool cur_chan;
+ switch (state) {
+ case_rtn_string(ATH_CHANCTX_STATE_IDLE);
+ case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_BEACON);
+ case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_TIMER);
+ case_rtn_string(ATH_CHANCTX_STATE_SWITCH);
+ case_rtn_string(ATH_CHANCTX_STATE_FORCE_ACTIVE);
+ default:
+ return "unknown";
+ }
+}
- spin_lock_bh(&sc->chan_lock);
- if (chandef)
- memcpy(&ctx->chandef, chandef, sizeof(*chandef));
- cur_chan = sc->cur_chan == ctx;
- spin_unlock_bh(&sc->chan_lock);
+void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_vif *avp;
+ bool active = false;
+ u8 n_active = 0;
- if (!cur_chan)
+ if (!ctx)
return;
- ath_set_channel(sc);
-}
+ list_for_each_entry(avp, &ctx->vifs, list) {
+ struct ieee80211_vif *vif = avp->vif;
-struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active)
-{
- struct ath_chanctx *ctx;
+ switch (vif->type) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_STATION:
+ if (vif->bss_conf.assoc)
+ active = true;
+ break;
+ default:
+ active = true;
+ break;
+ }
+ }
+ ctx->active = active;
ath_for_each_chanctx(sc, ctx) {
if (!ctx->assigned || list_empty(&ctx->vifs))
continue;
- if (active && !ctx->active)
- continue;
-
- if (ctx->switch_after_beacon)
- return ctx;
+ n_active++;
}
- return &sc->chanctx[0];
-}
-
-void ath_chanctx_offchan_switch(struct ath_softc *sc,
- struct ieee80211_channel *chan)
-{
- struct cfg80211_chan_def chandef;
-
- cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+ if (n_active <= 1) {
+ clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
+ return;
+ }
+ if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+ return;
- ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
+ if (ath9k_is_chanctx_enabled()) {
+ ath_chanctx_event(sc, NULL,
+ ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
+ }
}
static struct ath_chanctx *
@@ -469,25 +282,22 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
prev->tsf_val += offset;
}
-void ath_chanctx_timer(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *) data;
-
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
-}
-
/* Configure the TSF based hardware timer for a channel switch.
* Also set up backup software timer, in case the gen timer fails.
* This could be caused by a hardware reset.
*/
static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_hw *ah = sc->sc_ah;
ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
tsf_time -= ath9k_hw_gettsf32(ah);
tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
- mod_timer(&sc->sched.timer, tsf_time);
+ mod_timer(&sc->sched.timer, jiffies + tsf_time);
+
+ ath_dbg(common, CHAN_CTX,
+ "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
}
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
@@ -500,40 +310,56 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
struct ath_chanctx *ctx;
u32 tsf_time;
u32 beacon_int;
- bool noa_changed = false;
if (vif)
avp = (struct ath_vif *) vif->drv_priv;
spin_lock_bh(&sc->chan_lock);
+ ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n",
+ sc->cur_chan->chandef.center_freq1,
+ chanctx_event_string(ev),
+ chanctx_state_string(sc->sched.state));
+
switch (ev) {
case ATH_CHANCTX_EVENT_BEACON_PREPARE:
if (avp->offchannel_duration)
avp->offchannel_duration = 0;
- if (avp->chanctx != sc->cur_chan)
+ if (avp->chanctx != sc->cur_chan) {
+ ath_dbg(common, CHAN_CTX,
+ "Contexts differ, not preparing beacon\n");
break;
+ }
- if (sc->sched.offchannel_pending) {
+ if (sc->sched.offchannel_pending && !sc->sched.wait_switch) {
sc->sched.offchannel_pending = false;
sc->next_chan = &sc->offchannel.chan;
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+ ath_dbg(common, CHAN_CTX,
+ "Setting offchannel_pending to false\n");
}
ctx = ath_chanctx_get_next(sc, sc->cur_chan);
if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) {
sc->next_chan = ctx;
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+ ath_dbg(common, CHAN_CTX,
+ "Set next context, move chanctx state to WAIT_FOR_BEACON\n");
}
/* if the timer missed its window, use the next interval */
- if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
+ if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) {
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
+ }
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break;
+ ath_dbg(common, CHAN_CTX, "Preparing beacon for vif: %pM\n", vif->addr);
+
sc->sched.beacon_pending = true;
sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER);
@@ -545,47 +371,107 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->sched.switch_start_time = tsf_time;
sc->cur_chan->last_beacon = sc->sched.next_tbtt;
- /* Prevent wrap-around issues */
- if (avp->periodic_noa_duration &&
- tsf_time - avp->periodic_noa_start > BIT(30))
- avp->periodic_noa_duration = 0;
-
- if (ctx->active && !avp->periodic_noa_duration) {
- avp->periodic_noa_start = tsf_time;
- avp->periodic_noa_duration =
- TU_TO_USEC(cur_conf->beacon_interval) / 2 -
- sc->sched.channel_switch_time;
- noa_changed = true;
- } else if (!ctx->active && avp->periodic_noa_duration) {
- avp->periodic_noa_duration = 0;
- noa_changed = true;
+ /*
+ * If an offchannel switch is scheduled to happen after
+ * a beacon transmission, update the NoA with one-shot
+ * values and increment the index.
+ */
+ if (sc->next_chan == &sc->offchannel.chan) {
+ avp->noa_index++;
+ avp->offchannel_start = tsf_time;
+ avp->offchannel_duration = sc->sched.offchannel_duration;
+
+ ath_dbg(common, CHAN_CTX,
+ "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
+ avp->offchannel_duration,
+ avp->offchannel_start,
+ avp->noa_index);
+
+ /*
+ * When multiple contexts are active, the NoA
+ * has to be recalculated and advertised after
+ * an offchannel operation.
+ */
+ if (ctx->active && avp->noa_duration)
+ avp->noa_duration = 0;
+
+ break;
+ }
+
+
+ /*
+ * Clear the extend_absence flag if it had been
+ * set during the previous beacon transmission,
+ * since we need to revert to the normal NoA
+ * schedule.
+ */
+ if (ctx->active && sc->sched.extend_absence) {
+ avp->noa_duration = 0;
+ sc->sched.extend_absence = false;
}
/* If at least two consecutive beacons were missed on the STA
* chanctx, stay on the STA channel for one extra beacon period,
* to resync the timer properly.
*/
- if (ctx->active && sc->sched.beacon_miss >= 2)
- sc->sched.offchannel_duration = 3 * beacon_int / 2;
-
- if (sc->sched.offchannel_duration) {
- noa_changed = true;
- avp->offchannel_start = tsf_time;
- avp->offchannel_duration =
- sc->sched.offchannel_duration;
+ if (ctx->active && sc->sched.beacon_miss >= 2) {
+ avp->noa_duration = 0;
+ sc->sched.extend_absence = true;
}
+ /* Prevent wrap-around issues */
+ if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30))
+ avp->noa_duration = 0;
- if (noa_changed)
+ /*
+ * If multiple contexts are active, start periodic
+ * NoA and increment the index for the first
+ * announcement.
+ */
+ if (ctx->active &&
+ (!avp->noa_duration || sc->sched.force_noa_update)) {
avp->noa_index++;
+ avp->noa_start = tsf_time;
+
+ if (sc->sched.extend_absence)
+ avp->noa_duration = (3 * beacon_int / 2) +
+ sc->sched.channel_switch_time;
+ else
+ avp->noa_duration =
+ TU_TO_USEC(cur_conf->beacon_interval) / 2 +
+ sc->sched.channel_switch_time;
+
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
+ sc->sched.extend_absence)
+ avp->periodic_noa = false;
+ else
+ avp->periodic_noa = true;
+
+ ath_dbg(common, CHAN_CTX,
+ "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+ avp->noa_duration,
+ avp->noa_start,
+ avp->noa_index,
+ avp->periodic_noa);
+ }
+
+ if (ctx->active && sc->sched.force_noa_update)
+ sc->sched.force_noa_update = false;
+
break;
case ATH_CHANCTX_EVENT_BEACON_SENT:
- if (!sc->sched.beacon_pending)
+ if (!sc->sched.beacon_pending) {
+ ath_dbg(common, CHAN_CTX,
+ "No pending beacon\n");
break;
+ }
sc->sched.beacon_pending = false;
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state to WAIT_FOR_TIMER\n");
+
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
ath_chanctx_setup_timer(sc, sc->sched.switch_start_time);
break;
@@ -597,6 +483,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->sched.beacon_pending)
sc->sched.beacon_miss++;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state to SWITCH\n");
+
sc->sched.state = ATH_CHANCTX_STATE_SWITCH;
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
break;
@@ -625,6 +514,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
avp->chanctx != sc->cur_chan)
break;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state from FORCE_ACTIVE to IDLE\n");
+
sc->sched.state = ATH_CHANCTX_STATE_IDLE;
/* fall through */
case ATH_CHANCTX_EVENT_SWITCH:
@@ -640,10 +532,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
cur_conf = &sc->cur_chan->beacon;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n");
+
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
+ sc->sched.wait_switch = false;
tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2;
- if (sc->sched.beacon_miss >= 2) {
+
+ if (sc->sched.extend_absence) {
sc->sched.beacon_miss = 0;
tsf_time *= 3;
}
@@ -679,7 +576,833 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->next_chan = ctx;
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
break;
+ case ATH_CHANCTX_EVENT_ASSIGN:
+ /*
+ * When adding a new channel context, check if a scan
+ * is in progress and abort it since the addition of
+ * a new channel context is usually followed by VIF
+ * assignment, in which case we have to start multi-channel
+ * operation.
+ */
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
+ ath_dbg(common, CHAN_CTX,
+ "Aborting HW scan to add new context\n");
+
+ spin_unlock_bh(&sc->chan_lock);
+ del_timer_sync(&sc->offchannel.timer);
+ ath_scan_complete(sc, true);
+ spin_lock_bh(&sc->chan_lock);
+ }
+ break;
+ case ATH_CHANCTX_EVENT_CHANGE:
+ break;
}
spin_unlock_bh(&sc->chan_lock);
}
+
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev)
+{
+ if (sc->sched.beacon_pending)
+ ath_chanctx_event(sc, NULL, ev);
+}
+
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
+ enum ath_chanctx_event ev)
+{
+ sc->sched.next_tbtt = ts;
+ ath_chanctx_event(sc, NULL, ev);
+}
+
+static int ath_scan_channel_duration(struct ath_softc *sc,
+ struct ieee80211_channel *chan)
+{
+ struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+
+ if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
+ return (HZ / 9); /* ~110 ms */
+
+ return (HZ / 16); /* ~60 ms */
+}
+
+static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
+ struct cfg80211_chan_def *chandef)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ spin_lock_bh(&sc->chan_lock);
+
+ if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
+ (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
+ if (chandef)
+ ctx->chandef = *chandef;
+
+ sc->sched.offchannel_pending = true;
+ sc->sched.wait_switch = true;
+ sc->sched.offchannel_duration =
+ jiffies_to_usecs(sc->offchannel.duration) +
+ sc->sched.channel_switch_time;
+
+ spin_unlock_bh(&sc->chan_lock);
+ ath_dbg(common, CHAN_CTX,
+ "Set offchannel_pending to true\n");
+ return;
+ }
+
+ sc->next_chan = ctx;
+ if (chandef) {
+ ctx->chandef = *chandef;
+ ath_dbg(common, CHAN_CTX,
+ "Assigned next_chan to %d MHz\n", chandef->center_freq1);
+ }
+
+ if (sc->next_chan == &sc->offchannel.chan) {
+ sc->sched.offchannel_duration =
+ jiffies_to_usecs(sc->offchannel.duration) +
+ sc->sched.channel_switch_time;
+
+ if (chandef) {
+ ath_dbg(common, CHAN_CTX,
+ "Offchannel duration for chan %d MHz : %u\n",
+ chandef->center_freq1,
+ sc->sched.offchannel_duration);
+ }
+ }
+ spin_unlock_bh(&sc->chan_lock);
+ ieee80211_queue_work(sc->hw, &sc->chanctx_work);
+}
+
+static void ath_chanctx_offchan_switch(struct ath_softc *sc,
+ struct ieee80211_channel *chan)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct cfg80211_chan_def chandef;
+
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+ ath_dbg(common, CHAN_CTX,
+ "Channel definition created: %d MHz\n", chandef.center_freq1);
+
+ ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
+}
+
+static struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
+ bool active)
+{
+ struct ath_chanctx *ctx;
+
+ ath_for_each_chanctx(sc, ctx) {
+ if (!ctx->assigned || list_empty(&ctx->vifs))
+ continue;
+ if (active && !ctx->active)
+ continue;
+
+ if (ctx->switch_after_beacon)
+ return ctx;
+ }
+
+ return &sc->chanctx[0];
+}
+
+static void
+ath_scan_next_channel(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+ struct ieee80211_channel *chan;
+
+ if (sc->offchannel.scan_idx >= req->n_channels) {
+ ath_dbg(common, CHAN_CTX,
+ "Moving offchannel state to ATH_OFFCHANNEL_IDLE, "
+ "scan_idx: %d, n_channels: %d\n",
+ sc->offchannel.scan_idx,
+ req->n_channels);
+
+ sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+ ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
+ NULL);
+ return;
+ }
+
+ ath_dbg(common, CHAN_CTX,
+ "Moving offchannel state to ATH_OFFCHANNEL_PROBE_SEND, scan_idx: %d\n",
+ sc->offchannel.scan_idx);
+
+ chan = req->channels[sc->offchannel.scan_idx++];
+ sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
+ sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
+
+ ath_chanctx_offchan_switch(sc, chan);
+}
+
+void ath_offchannel_next(struct ath_softc *sc)
+{
+ struct ieee80211_vif *vif;
+
+ if (sc->offchannel.scan_req) {
+ vif = sc->offchannel.scan_vif;
+ sc->offchannel.chan.txpower = vif->bss_conf.txpower;
+ ath_scan_next_channel(sc);
+ } else if (sc->offchannel.roc_vif) {
+ vif = sc->offchannel.roc_vif;
+ sc->offchannel.chan.txpower = vif->bss_conf.txpower;
+ sc->offchannel.duration =
+ msecs_to_jiffies(sc->offchannel.roc_duration);
+ sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
+ ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
+ } else {
+ ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
+ NULL);
+ sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+ if (sc->ps_idle)
+ ath_cancel_work(sc);
+ }
+}
+
+void ath_roc_complete(struct ath_softc *sc, bool abort)
+{
+ sc->offchannel.roc_vif = NULL;
+ sc->offchannel.roc_chan = NULL;
+ if (!abort)
+ ieee80211_remain_on_channel_expired(sc->hw);
+ ath_offchannel_next(sc);
+ ath9k_ps_restore(sc);
+}
+
+void ath_scan_complete(struct ath_softc *sc, bool abort)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ if (abort)
+ ath_dbg(common, CHAN_CTX, "HW scan aborted\n");
+ else
+ ath_dbg(common, CHAN_CTX, "HW scan complete\n");
+
+ sc->offchannel.scan_req = NULL;
+ sc->offchannel.scan_vif = NULL;
+ sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+ ieee80211_scan_completed(sc->hw, abort);
+ clear_bit(ATH_OP_SCANNING, &common->op_flags);
+ spin_lock_bh(&sc->chan_lock);
+ if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+ sc->sched.force_noa_update = true;
+ spin_unlock_bh(&sc->chan_lock);
+ ath_offchannel_next(sc);
+ ath9k_ps_restore(sc);
+}
+
+static void ath_scan_send_probe(struct ath_softc *sc,
+ struct cfg80211_ssid *ssid)
+{
+ struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+ struct ieee80211_vif *vif = sc->offchannel.scan_vif;
+ struct ath_tx_control txctl = {};
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
+ int band = sc->offchannel.chan.chandef.chan->band;
+
+ skb = ieee80211_probereq_get(sc->hw, vif,
+ ssid->ssid, ssid->ssid_len, req->ie_len);
+ if (!skb)
+ return;
+
+ info = IEEE80211_SKB_CB(skb);
+ if (req->no_cck)
+ info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
+
+ if (req->ie_len)
+ memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
+
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+
+ if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
+ goto error;
+
+ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+ txctl.force_channel = true;
+ if (ath_tx_start(sc->hw, skb, &txctl))
+ goto error;
+
+ return;
+
+error:
+ ieee80211_free_txskb(sc->hw, skb);
+}
+
+static void ath_scan_channel_start(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+ int i;
+
+ if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
+ req->n_ssids) {
+ for (i = 0; i < req->n_ssids; i++)
+ ath_scan_send_probe(sc, &req->ssids[i]);
+
+ }
+
+ ath_dbg(common, CHAN_CTX,
+ "Moving offchannel state to ATH_OFFCHANNEL_PROBE_WAIT\n");
+
+ sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
+ mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
+}
+
+static void ath_chanctx_timer(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *) data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_dbg(common, CHAN_CTX,
+ "Channel context timer invoked\n");
+
+ ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
+}
+
+static void ath_offchannel_timer(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *)data;
+ struct ath_chanctx *ctx;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
+ __func__, offchannel_state_string(sc->offchannel.state));
+
+ switch (sc->offchannel.state) {
+ case ATH_OFFCHANNEL_PROBE_WAIT:
+ if (!sc->offchannel.scan_req)
+ return;
+
+ /* get first active channel context */
+ ctx = ath_chanctx_get_oper_chan(sc, true);
+ if (ctx->active) {
+ ath_dbg(common, CHAN_CTX,
+ "Switch to oper/active context, "
+ "move offchannel state to ATH_OFFCHANNEL_SUSPEND\n");
+
+ sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
+ ath_chanctx_switch(sc, ctx, NULL);
+ mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
+ break;
+ }
+ /* fall through */
+ case ATH_OFFCHANNEL_SUSPEND:
+ if (!sc->offchannel.scan_req)
+ return;
+
+ ath_scan_next_channel(sc);
+ break;
+ case ATH_OFFCHANNEL_ROC_START:
+ case ATH_OFFCHANNEL_ROC_WAIT:
+ ctx = ath_chanctx_get_oper_chan(sc, false);
+ sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
+ ath_chanctx_switch(sc, ctx, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool
+ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
+ bool powersave)
+{
+ struct ieee80211_vif *vif = avp->vif;
+ struct ieee80211_sta *sta = NULL;
+ struct ieee80211_hdr_3addr *nullfunc;
+ struct ath_tx_control txctl;
+ struct sk_buff *skb;
+ int band = sc->cur_chan->chandef.chan->band;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (!vif->bss_conf.assoc)
+ return false;
+
+ skb = ieee80211_nullfunc_get(sc->hw, vif);
+ if (!skb)
+ return false;
+
+ nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
+ if (powersave)
+ nullfunc->frame_control |=
+ cpu_to_le16(IEEE80211_FCTL_PM);
+
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+ if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
+ dev_kfree_skb_any(skb);
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ memset(&txctl, 0, sizeof(txctl));
+ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+ txctl.sta = sta;
+ txctl.force_channel = true;
+ if (ath_tx_start(sc->hw, skb, &txctl)) {
+ ieee80211_free_txskb(sc->hw, skb);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
+{
+ struct ath_vif *avp;
+ bool sent = false;
+
+ rcu_read_lock();
+ list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
+ if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
+ sent = true;
+ }
+ rcu_read_unlock();
+
+ return sent;
+}
+
+static bool ath_chanctx_defer_switch(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ if (sc->cur_chan == &sc->offchannel.chan)
+ return false;
+
+ switch (sc->sched.state) {
+ case ATH_CHANCTX_STATE_SWITCH:
+ return false;
+ case ATH_CHANCTX_STATE_IDLE:
+ if (!sc->cur_chan->switch_after_beacon)
+ return false;
+
+ ath_dbg(common, CHAN_CTX,
+ "Defer switch, set chanctx state to WAIT_FOR_BEACON\n");
+
+ sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static void ath_offchannel_channel_change(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
+ __func__, offchannel_state_string(sc->offchannel.state));
+
+ switch (sc->offchannel.state) {
+ case ATH_OFFCHANNEL_PROBE_SEND:
+ if (!sc->offchannel.scan_req)
+ return;
+
+ if (sc->cur_chan->chandef.chan !=
+ sc->offchannel.chan.chandef.chan)
+ return;
+
+ ath_scan_channel_start(sc);
+ break;
+ case ATH_OFFCHANNEL_IDLE:
+ if (!sc->offchannel.scan_req)
+ return;
+
+ ath_scan_complete(sc, false);
+ break;
+ case ATH_OFFCHANNEL_ROC_START:
+ if (sc->cur_chan != &sc->offchannel.chan)
+ break;
+
+ sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
+ mod_timer(&sc->offchannel.timer,
+ jiffies + sc->offchannel.duration);
+ ieee80211_ready_on_channel(sc->hw);
+ break;
+ case ATH_OFFCHANNEL_ROC_DONE:
+ ath_roc_complete(sc, false);
+ break;
+ default:
+ break;
+ }
+}
+
+void ath_chanctx_set_next(struct ath_softc *sc, bool force)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct timespec ts;
+ bool measure_time = false;
+ bool send_ps = false;
+
+ spin_lock_bh(&sc->chan_lock);
+ if (!sc->next_chan) {
+ spin_unlock_bh(&sc->chan_lock);
+ return;
+ }
+
+ if (!force && ath_chanctx_defer_switch(sc)) {
+ spin_unlock_bh(&sc->chan_lock);
+ return;
+ }
+
+ ath_dbg(common, CHAN_CTX,
+ "%s: current: %d MHz, next: %d MHz\n",
+ __func__,
+ sc->cur_chan->chandef.center_freq1,
+ sc->next_chan->chandef.center_freq1);
+
+ if (sc->cur_chan != sc->next_chan) {
+ ath_dbg(common, CHAN_CTX,
+ "Stopping current chanctx: %d\n",
+ sc->cur_chan->chandef.center_freq1);
+ sc->cur_chan->stopped = true;
+ spin_unlock_bh(&sc->chan_lock);
+
+ if (sc->next_chan == &sc->offchannel.chan) {
+ getrawmonotonic(&ts);
+ measure_time = true;
+ }
+ __ath9k_flush(sc->hw, ~0, true);
+
+ if (ath_chanctx_send_ps_frame(sc, true))
+ __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
+
+ send_ps = true;
+ spin_lock_bh(&sc->chan_lock);
+
+ if (sc->cur_chan != &sc->offchannel.chan) {
+ getrawmonotonic(&sc->cur_chan->tsf_ts);
+ sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
+ }
+ }
+ sc->cur_chan = sc->next_chan;
+ sc->cur_chan->stopped = false;
+ sc->next_chan = NULL;
+
+ if (!sc->sched.offchannel_pending)
+ sc->sched.offchannel_duration = 0;
+
+ if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
+ sc->sched.state = ATH_CHANCTX_STATE_IDLE;
+
+ spin_unlock_bh(&sc->chan_lock);
+
+ if (sc->sc_ah->chip_fullsleep ||
+ memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
+ sizeof(sc->cur_chandef))) {
+ ath_dbg(common, CHAN_CTX,
+ "%s: Set channel %d MHz\n",
+ __func__, sc->cur_chan->chandef.center_freq1);
+ ath_set_channel(sc);
+ if (measure_time)
+ sc->sched.channel_switch_time =
+ ath9k_hw_get_tsf_offset(&ts, NULL);
+ }
+ if (send_ps)
+ ath_chanctx_send_ps_frame(sc, false);
+
+ ath_offchannel_channel_change(sc);
+ ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
+}
+
+static void ath_chanctx_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ chanctx_work);
+ mutex_lock(&sc->mutex);
+ ath_chanctx_set_next(sc, false);
+ mutex_unlock(&sc->mutex);
+}
+
+void ath9k_offchannel_init(struct ath_softc *sc)
+{
+ struct ath_chanctx *ctx;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+ int i;
+
+ sband = &common->sbands[IEEE80211_BAND_2GHZ];
+ if (!sband->n_channels)
+ sband = &common->sbands[IEEE80211_BAND_5GHZ];
+
+ chan = &sband->channels[0];
+
+ ctx = &sc->offchannel.chan;
+ INIT_LIST_HEAD(&ctx->vifs);
+ ctx->txpower = ATH_TXPOWER_MAX;
+ cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
+
+ for (i = 0; i < ARRAY_SIZE(ctx->acq); i++)
+ INIT_LIST_HEAD(&ctx->acq[i]);
+
+ sc->offchannel.chan.offchannel = true;
+}
+
+void ath9k_init_channel_context(struct ath_softc *sc)
+{
+ INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
+
+ setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
+ (unsigned long)sc);
+ setup_timer(&sc->sched.timer, ath_chanctx_timer,
+ (unsigned long)sc);
+}
+
+void ath9k_deinit_channel_context(struct ath_softc *sc)
+{
+ cancel_work_sync(&sc->chanctx_work);
+}
+
+bool ath9k_is_chanctx_enabled(void)
+{
+ return (ath9k_use_chanctx == 1);
+}
+
+/********************/
+/* Queue management */
+/********************/
+
+void ath9k_chanctx_wake_queues(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ int i;
+
+ if (sc->cur_chan == &sc->offchannel.chan) {
+ ieee80211_wake_queue(sc->hw,
+ sc->hw->offchannel_tx_hw_queue);
+ } else {
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ ieee80211_wake_queue(sc->hw,
+ sc->cur_chan->hw_queue_base + i);
+ }
+
+ if (ah->opmode == NL80211_IFTYPE_AP)
+ ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
+}
+
+/*****************/
+/* P2P Powersave */
+/*****************/
+
+static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ s32 tsf, target_tsf;
+
+ if (!avp || !avp->noa.has_next_tsf)
+ return;
+
+ ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
+
+ tsf = ath9k_hw_gettsf32(sc->sc_ah);
+
+ target_tsf = avp->noa.next_tsf;
+ if (!avp->noa.absent)
+ target_tsf -= ATH_P2P_PS_STOP_TIME;
+
+ if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
+ target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
+
+ ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
+}
+
+static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+ struct ath_vif *avp = (void *)vif->drv_priv;
+ u32 tsf;
+
+ if (!sc->p2p_ps_timer)
+ return;
+
+ if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
+ return;
+
+ sc->p2p_ps_vif = avp;
+ tsf = ath9k_hw_gettsf32(sc->sc_ah);
+ ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
+ ath9k_update_p2p_ps_timer(sc, avp);
+}
+
+static u8 ath9k_get_ctwin(struct ath_softc *sc, struct ath_vif *avp)
+{
+ struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
+ u8 switch_time, ctwin;
+
+ /*
+ * Channel switch in multi-channel mode is deferred
+ * by a quarter beacon interval when handling
+ * ATH_CHANCTX_EVENT_BEACON_PREPARE, so the P2P-GO
+ * interface is guaranteed to be discoverable
+ * for that duration after a TBTT.
+ */
+ switch_time = cur_conf->beacon_interval / 4;
+
+ ctwin = avp->vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
+ if (ctwin && (ctwin < switch_time))
+ return ctwin;
+
+ if (switch_time < P2P_DEFAULT_CTWIN)
+ return 0;
+
+ return P2P_DEFAULT_CTWIN;
+}
+
+void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+ struct sk_buff *skb)
+{
+ static const u8 noa_ie_hdr[] = {
+ WLAN_EID_VENDOR_SPECIFIC, /* type */
+ 0, /* length */
+ 0x50, 0x6f, 0x9a, /* WFA OUI */
+ 0x09, /* P2P subtype */
+ 0x0c, /* Notice of Absence */
+ 0x00, /* LSB of little-endian len */
+ 0x00, /* MSB of little-endian len */
+ };
+
+ struct ieee80211_p2p_noa_attr *noa;
+ int noa_len, noa_desc, i = 0;
+ u8 *hdr;
+
+ if (!avp->offchannel_duration && !avp->noa_duration)
+ return;
+
+ noa_desc = !!avp->offchannel_duration + !!avp->noa_duration;
+ noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
+
+ hdr = skb_put(skb, sizeof(noa_ie_hdr));
+ memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
+ hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
+ hdr[7] = noa_len;
+
+ noa = (void *) skb_put(skb, noa_len);
+ memset(noa, 0, noa_len);
+
+ noa->index = avp->noa_index;
+ noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
+
+ if (avp->noa_duration) {
+ if (avp->periodic_noa) {
+ u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
+ noa->desc[i].count = 255;
+ noa->desc[i].interval = cpu_to_le32(interval);
+ } else {
+ noa->desc[i].count = 1;
+ }
+
+ noa->desc[i].start_time = cpu_to_le32(avp->noa_start);
+ noa->desc[i].duration = cpu_to_le32(avp->noa_duration);
+ i++;
+ }
+
+ if (avp->offchannel_duration) {
+ noa->desc[i].count = 1;
+ noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
+ noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
+ }
+}
+
+void ath9k_p2p_ps_timer(void *priv)
+{
+ struct ath_softc *sc = priv;
+ struct ath_vif *avp = sc->p2p_ps_vif;
+ struct ieee80211_vif *vif;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ u32 tsf;
+
+ del_timer_sync(&sc->sched.timer);
+ ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
+ ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
+
+ if (!avp || avp->chanctx != sc->cur_chan)
+ return;
+
+ tsf = ath9k_hw_gettsf32(sc->sc_ah);
+ if (!avp->noa.absent)
+ tsf += ATH_P2P_PS_STOP_TIME;
+
+ if (!avp->noa.has_next_tsf ||
+ avp->noa.next_tsf - tsf > BIT(31))
+ ieee80211_update_p2p_noa(&avp->noa, tsf);
+
+ ath9k_update_p2p_ps_timer(sc, avp);
+
+ rcu_read_lock();
+
+ vif = avp->vif;
+ sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+ if (!sta)
+ goto out;
+
+ an = (void *) sta->drv_priv;
+ if (an->sleeping == !!avp->noa.absent)
+ goto out;
+
+ an->sleeping = avp->noa.absent;
+ if (an->sleeping)
+ ath_tx_aggr_sleep(sta, sc, an);
+ else
+ ath_tx_aggr_wakeup(sc, an);
+
+out:
+ rcu_read_unlock();
+}
+
+void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+ unsigned long flags;
+
+ spin_lock_bh(&sc->sc_pcu_lock);
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (!(sc->ps_flags & PS_BEACON_SYNC))
+ ath9k_update_p2p_ps(sc, vif);
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+ spin_unlock_bh(&sc->sc_pcu_lock);
+}
+
+void ath9k_p2p_beacon_sync(struct ath_softc *sc)
+{
+ if (sc->p2p_ps_vif)
+ ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+}
+
+void ath9k_p2p_remove_vif(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ spin_lock_bh(&sc->sc_pcu_lock);
+ if (avp == sc->p2p_ps_vif) {
+ sc->p2p_ps_vif = NULL;
+ ath9k_update_p2p_ps_timer(sc, NULL);
+ }
+ spin_unlock_bh(&sc->sc_pcu_lock);
+}
+
+int ath9k_init_p2p(struct ath_softc *sc)
+{
+ sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
+ NULL, sc, AR_FIRST_NDP_TIMER);
+ if (!sc->p2p_ps_timer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void ath9k_deinit_p2p(struct ath_softc *sc)
+{
+ if (sc->p2p_ps_timer)
+ ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
+}
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index d227936..5d8b5ea 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -838,7 +838,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
iter_data.nmeshes, iter_data.nwds);
len += scnprintf(buf + len, sizeof(buf) - len,
" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
- iter_data.nadhocs, sc->nvifs, sc->nbcnvifs);
+ iter_data.nadhocs, sc->cur_chan->nvifs, sc->nbcnvifs);
}
if (len > sizeof(buf))
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 8a3bd5f..d779f4f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -592,6 +592,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
hw->queues = 4;
hw->max_listen_interval = 1;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 39419ea..156a944 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -61,10 +61,14 @@ static int ath9k_ps_enable;
module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
int ath9k_use_chanctx;
module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444);
MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency");
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
bool is_ath9k_unloaded;
#ifdef CONFIG_MAC80211_LEDS
@@ -511,7 +515,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
sc->tx99_power = MAX_RATE_POWER + 1;
init_waitqueue_head(&sc->tx_wait);
sc->cur_chan = &sc->chanctx[0];
- if (!ath9k_use_chanctx)
+ if (!ath9k_is_chanctx_enabled())
sc->cur_chan->hw_queue_base = 0;
if (!pdata || pdata->use_eeprom) {
@@ -567,11 +571,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);
INIT_WORK(&sc->hw_reset_work, ath_reset_work);
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
- INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
- setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
- (unsigned long)sc);
- setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc);
+
+ ath9k_init_channel_context(sc);
/*
* Cache line size is used to size and align various
@@ -600,13 +602,15 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (ret)
goto err_btcoex;
- sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
- NULL, sc, AR_FIRST_NDP_TIMER);
+ ret = ath9k_init_p2p(sc);
+ if (ret)
+ goto err_btcoex;
ath9k_cmn_init_crypto(sc->sc_ah);
ath9k_init_misc(sc);
ath_fill_led_pin(sc);
ath_chanctx_init(sc);
+ ath9k_offchannel_init(sc);
if (common->bus_ops->aspm_init)
common->bus_ops->aspm_init(common);
@@ -672,18 +676,14 @@ static const struct ieee80211_iface_limit wds_limits[] = {
{ .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) },
};
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
static const struct ieee80211_iface_limit if_limits_multi[] = {
- { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) },
- { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) },
-};
-
-static const struct ieee80211_iface_limit if_dfs_limits[] = {
- { .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
-#ifdef CONFIG_MAC80211_MESH
- BIT(NL80211_IFTYPE_MESH_POINT) |
-#endif
- BIT(NL80211_IFTYPE_ADHOC) },
+ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
};
static const struct ieee80211_iface_combination if_comb_multi[] = {
@@ -696,6 +696,16 @@ static const struct ieee80211_iface_combination if_comb_multi[] = {
},
};
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
+static const struct ieee80211_iface_limit if_dfs_limits[] = {
+ { .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_ADHOC) },
+};
+
static const struct ieee80211_iface_combination if_comb[] = {
{
.limits = if_limits,
@@ -753,8 +763,9 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
- hw->wiphy->features |= (NL80211_FEATURE_ACTIVE_MONITOR |
- NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE);
+ hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
+ NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
+ NL80211_FEATURE_P2P_GO_CTWIN;
if (!config_enabled(CONFIG_ATH9K_TX99)) {
hw->wiphy->interface_modes =
@@ -763,24 +774,31 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_MESH_POINT);
- if (!ath9k_use_chanctx) {
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_WDS);
+
hw->wiphy->iface_combinations = if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
- hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS);
- } else {
- hw->wiphy->iface_combinations = if_comb_multi;
- hw->wiphy->n_iface_combinations =
- ARRAY_SIZE(if_comb_multi);
- hw->wiphy->max_scan_ssids = 255;
- hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
- hw->wiphy->max_remain_on_channel_duration = 10000;
- hw->chanctx_data_size = sizeof(void *);
- hw->extra_beacon_tailroom =
- sizeof(struct ieee80211_p2p_noa_attr) + 9;
- }
}
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
+ if (ath9k_is_chanctx_enabled()) {
+ hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
+ hw->wiphy->iface_combinations = if_comb_multi;
+ hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi);
+ hw->wiphy->max_scan_ssids = 255;
+ hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ hw->wiphy->max_remain_on_channel_duration = 10000;
+ hw->chanctx_data_size = sizeof(void *);
+ hw->extra_beacon_tailroom =
+ sizeof(struct ieee80211_p2p_noa_attr) + 9;
+
+ ath_dbg(common, CHAN_CTX, "Use channel contexts\n");
+ }
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -793,7 +811,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
/* allow 4 queues per channel context +
* 1 cab queue + 1 offchannel tx queue
*/
- hw->queues = 10;
+ hw->queues = ATH9K_NUM_TX_QUEUES;
/* last queue for offchannel */
hw->offchannel_tx_hw_queue = hw->queues - 1;
hw->max_rates = 4;
@@ -915,9 +933,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
{
int i = 0;
- if (sc->p2p_ps_timer)
- ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
-
+ ath9k_deinit_p2p(sc);
ath9k_deinit_btcoex(sc);
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index e6ac8d2..1bc2369 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -223,18 +223,12 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
unsigned long flags;
- int i;
-
- if (ath_startrecv(sc) != 0) {
- ath_err(common, "Unable to restart recv logic\n");
- return false;
- }
+ ath9k_calculate_summary_state(sc, sc->cur_chan);
+ ath_startrecv(sc);
ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->cur_chan->txpower, &sc->curtxpow);
-
clear_bit(ATH_OP_HW_RESET, &common->op_flags);
- ath9k_calculate_summary_state(sc, sc->cur_chan);
if (!sc->cur_chan->offchannel && start) {
/* restore per chanctx TSF timer */
@@ -268,20 +262,10 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
- if (!ath9k_use_chanctx)
+ if (!ath9k_is_chanctx_enabled())
ieee80211_wake_queues(sc->hw);
- else {
- if (sc->cur_chan == &sc->offchannel.chan)
- ieee80211_wake_queue(sc->hw,
- sc->hw->offchannel_tx_hw_queue);
- else {
- for (i = 0; i < IEEE80211_NUM_ACS; i++)
- ieee80211_wake_queue(sc->hw,
- sc->cur_chan->hw_queue_base + i);
- }
- if (ah->opmode == NL80211_IFTYPE_AP)
- ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
- }
+ else
+ ath9k_chanctx_wake_queues(sc);
ath9k_p2p_ps_timer(sc);
@@ -314,6 +298,9 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
if (!ath_prepare_reset(sc))
fastcc = false;
+ if (ath9k_is_chanctx_enabled())
+ fastcc = false;
+
spin_lock_bh(&sc->chan_lock);
sc->cur_chandef = sc->cur_chan->chandef;
spin_unlock_bh(&sc->chan_lock);
@@ -822,7 +809,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
struct ath_common *common = ath9k_hw_common(ah);
bool prev_idle;
- cancel_work_sync(&sc->chanctx_work);
+ ath9k_deinit_channel_context(sc);
+
mutex_lock(&sc->mutex);
ath_cancel_work(sc);
@@ -903,9 +891,9 @@ static bool ath9k_uses_beacons(int type)
}
}
-static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
+ u8 *mac, struct ieee80211_vif *vif)
{
- struct ath9k_vif_iter_data *iter_data = data;
int i;
if (iter_data->has_hw_macaddr) {
@@ -923,8 +911,6 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
switch (vif->type) {
case NL80211_IFTYPE_AP:
iter_data->naps++;
- if (vif->bss_conf.enable_beacon)
- iter_data->beacons = true;
break;
case NL80211_IFTYPE_STATION:
iter_data->nstations++;
@@ -968,6 +954,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
list_for_each_entry(avp, &ctx->vifs, list)
ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
if (ctx == &sc->offchannel.chan) {
struct ieee80211_vif *vif;
@@ -980,6 +967,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
ath9k_vif_iter(iter_data, vif->addr, vif);
iter_data->beacons = false;
}
+#endif
}
static void ath9k_set_assoc_state(struct ath_softc *sc,
@@ -1026,6 +1014,7 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_vif_iter_data iter_data;
+ struct ath_beacon_config *cur_conf;
ath_chanctx_check_active(sc, ctx);
@@ -1042,8 +1031,11 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ath_hw_setbssidmask(common);
if (iter_data.naps > 0) {
+ cur_conf = &ctx->beacon;
ath9k_hw_set_tsfadjust(ah, true);
ah->opmode = NL80211_IFTYPE_AP;
+ if (cur_conf->enable_beacon)
+ iter_data.beacons = true;
} else {
ath9k_hw_set_tsfadjust(ah, false);
@@ -1072,8 +1064,8 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
if (ah->opmode == NL80211_IFTYPE_STATION) {
bool changed = (iter_data.primary_sta != ctx->primary_sta);
- iter_data.beacons = true;
if (iter_data.primary_sta) {
+ iter_data.beacons = true;
ath9k_set_assoc_state(sc, iter_data.primary_sta,
changed);
if (!ctx->primary_sta ||
@@ -1112,6 +1104,20 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ath9k_ps_restore(sc);
}
+static void ath9k_assign_hw_queues(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ vif->hw_queue[i] = i;
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ vif->cab_queue = hw->queues - 2;
+ else
+ vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+}
+
static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1120,12 +1126,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_node *an = &avp->mcast_node;
- int i;
mutex_lock(&sc->mutex);
if (config_enabled(CONFIG_ATH9K_TX99)) {
- if (sc->nvifs >= 1) {
+ if (sc->cur_chan->nvifs >= 1) {
mutex_unlock(&sc->mutex);
return -EOPNOTSUPP;
}
@@ -1133,22 +1138,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
}
ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
- sc->nvifs++;
+ sc->cur_chan->nvifs++;
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);
avp->vif = vif;
- if (!ath9k_use_chanctx) {
+ if (!ath9k_is_chanctx_enabled()) {
avp->chanctx = sc->cur_chan;
list_add_tail(&avp->list, &avp->chanctx->vifs);
}
- for (i = 0; i < IEEE80211_NUM_ACS; i++)
- vif->hw_queue[i] = i;
- if (vif->type == NL80211_IFTYPE_AP)
- vif->cab_queue = hw->queues - 2;
- else
- vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
+ ath9k_assign_hw_queues(hw, vif);
an->sc = sc;
an->sta = NULL;
@@ -1168,7 +1169,6 @@ static int ath9k_change_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;
- int i;
mutex_lock(&sc->mutex);
@@ -1188,43 +1188,13 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);
- for (i = 0; i < IEEE80211_NUM_ACS; i++)
- vif->hw_queue[i] = i;
-
- if (vif->type == NL80211_IFTYPE_AP)
- vif->cab_queue = hw->queues - 2;
- else
- vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
-
+ ath9k_assign_hw_queues(hw, vif);
ath9k_calculate_summary_state(sc, avp->chanctx);
mutex_unlock(&sc->mutex);
return 0;
}
-static void
-ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
-{
- struct ath_hw *ah = sc->sc_ah;
- s32 tsf, target_tsf;
-
- if (!avp || !avp->noa.has_next_tsf)
- return;
-
- ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
-
- tsf = ath9k_hw_gettsf32(sc->sc_ah);
-
- target_tsf = avp->noa.next_tsf;
- if (!avp->noa.absent)
- target_tsf -= ATH_P2P_PS_STOP_TIME;
-
- if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
- target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
-
- ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
-}
-
static void ath9k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1236,16 +1206,11 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
- spin_lock_bh(&sc->sc_pcu_lock);
- if (avp == sc->p2p_ps_vif) {
- sc->p2p_ps_vif = NULL;
- ath9k_update_p2p_ps_timer(sc, NULL);
- }
- spin_unlock_bh(&sc->sc_pcu_lock);
+ ath9k_p2p_remove_vif(sc, vif);
- sc->nvifs--;
+ sc->cur_chan->nvifs--;
sc->tx99_vif = NULL;
- if (!ath9k_use_chanctx)
+ if (!ath9k_is_chanctx_enabled())
list_del(&avp->list);
if (ath9k_uses_beacons(vif->type))
@@ -1423,7 +1388,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
}
- if (!ath9k_use_chanctx && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+ if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL);
ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef);
}
@@ -1463,7 +1428,10 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
- sc->rx.rxfilter = *total_flags;
+ spin_lock_bh(&sc->chan_lock);
+ sc->cur_chan->rxfilter = *total_flags;
+ spin_unlock_bh(&sc->chan_lock);
+
ath9k_ps_wakeup(sc);
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
@@ -1687,70 +1655,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
return ret;
}
-void ath9k_p2p_ps_timer(void *priv)
-{
- struct ath_softc *sc = priv;
- struct ath_vif *avp = sc->p2p_ps_vif;
- struct ieee80211_vif *vif;
- struct ieee80211_sta *sta;
- struct ath_node *an;
- u32 tsf;
-
- del_timer_sync(&sc->sched.timer);
- ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
-
- if (!avp || avp->chanctx != sc->cur_chan)
- return;
-
- tsf = ath9k_hw_gettsf32(sc->sc_ah);
- if (!avp->noa.absent)
- tsf += ATH_P2P_PS_STOP_TIME;
-
- if (!avp->noa.has_next_tsf ||
- avp->noa.next_tsf - tsf > BIT(31))
- ieee80211_update_p2p_noa(&avp->noa, tsf);
-
- ath9k_update_p2p_ps_timer(sc, avp);
-
- rcu_read_lock();
-
- vif = avp->vif;
- sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
- if (!sta)
- goto out;
-
- an = (void *) sta->drv_priv;
- if (an->sleeping == !!avp->noa.absent)
- goto out;
-
- an->sleeping = avp->noa.absent;
- if (an->sleeping)
- ath_tx_aggr_sleep(sta, sc, an);
- else
- ath_tx_aggr_wakeup(sc, an);
-
-out:
- rcu_read_unlock();
-}
-
-void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
-{
- struct ath_vif *avp = (void *)vif->drv_priv;
- u32 tsf;
-
- if (!sc->p2p_ps_timer)
- return;
-
- if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
- return;
-
- sc->p2p_ps_vif = avp;
- tsf = ath9k_hw_gettsf32(sc->sc_ah);
- ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
- ath9k_update_p2p_ps_timer(sc, avp);
-}
-
static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1765,7 +1669,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
- unsigned long flags;
int slottime;
ath9k_ps_wakeup(sc);
@@ -1776,8 +1679,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->bssid, bss_conf->assoc);
ath9k_calculate_summary_state(sc, avp->chanctx);
- if (bss_conf->assoc)
- ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_ASSOC);
+
+ if (ath9k_is_chanctx_enabled()) {
+ if (bss_conf->assoc)
+ ath_chanctx_event(sc, vif,
+ ATH_CHANCTX_EVENT_ASSOC);
+ }
}
if (changed & BSS_CHANGED_IBSS) {
@@ -1789,9 +1696,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
(changed & BSS_CHANGED_BEACON_INT) ||
(changed & BSS_CHANGED_BEACON_INFO)) {
+ ath9k_beacon_config(sc, vif, changed);
if (changed & BSS_CHANGED_BEACON_ENABLED)
ath9k_calculate_summary_state(sc, avp->chanctx);
- ath9k_beacon_config(sc, vif, changed);
}
if ((avp->chanctx == sc->cur_chan) &&
@@ -1814,14 +1721,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
}
- if (changed & BSS_CHANGED_P2P_PS) {
- spin_lock_bh(&sc->sc_pcu_lock);
- spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (!(sc->ps_flags & PS_BEACON_SYNC))
- ath9k_update_p2p_ps(sc, vif);
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
- spin_unlock_bh(&sc->sc_pcu_lock);
- }
+ if (changed & BSS_CHANGED_P2P_PS)
+ ath9k_p2p_bss_info_changed(sc, vif);
if (changed & CHECK_ANI)
ath_check_ani(sc);
@@ -2207,207 +2108,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
clear_bit(ATH_OP_SCANNING, &common->op_flags);
}
-static int ath_scan_channel_duration(struct ath_softc *sc,
- struct ieee80211_channel *chan)
-{
- struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-
- if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
- return (HZ / 9); /* ~110 ms */
-
- return (HZ / 16); /* ~60 ms */
-}
-
-static void
-ath_scan_next_channel(struct ath_softc *sc)
-{
- struct cfg80211_scan_request *req = sc->offchannel.scan_req;
- struct ieee80211_channel *chan;
-
- if (sc->offchannel.scan_idx >= req->n_channels) {
- sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
- ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
- NULL);
- return;
- }
-
- chan = req->channels[sc->offchannel.scan_idx++];
- sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
- sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
- ath_chanctx_offchan_switch(sc, chan);
-}
-
-static void ath_offchannel_next(struct ath_softc *sc)
-{
- struct ieee80211_vif *vif;
-
- if (sc->offchannel.scan_req) {
- vif = sc->offchannel.scan_vif;
- sc->offchannel.chan.txpower = vif->bss_conf.txpower;
- ath_scan_next_channel(sc);
- } else if (sc->offchannel.roc_vif) {
- vif = sc->offchannel.roc_vif;
- sc->offchannel.chan.txpower = vif->bss_conf.txpower;
- sc->offchannel.duration = sc->offchannel.roc_duration;
- sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
- ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
- } else {
- ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
- NULL);
- sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
- if (sc->ps_idle)
- ath_cancel_work(sc);
- }
-}
-
-static void ath_roc_complete(struct ath_softc *sc, bool abort)
-{
- sc->offchannel.roc_vif = NULL;
- sc->offchannel.roc_chan = NULL;
- if (!abort)
- ieee80211_remain_on_channel_expired(sc->hw);
- ath_offchannel_next(sc);
- ath9k_ps_restore(sc);
-}
-
-static void ath_scan_complete(struct ath_softc *sc, bool abort)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
- sc->offchannel.scan_req = NULL;
- sc->offchannel.scan_vif = NULL;
- sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
- ieee80211_scan_completed(sc->hw, abort);
- clear_bit(ATH_OP_SCANNING, &common->op_flags);
- ath_offchannel_next(sc);
- ath9k_ps_restore(sc);
-}
-
-static void ath_scan_send_probe(struct ath_softc *sc,
- struct cfg80211_ssid *ssid)
-{
- struct cfg80211_scan_request *req = sc->offchannel.scan_req;
- struct ieee80211_vif *vif = sc->offchannel.scan_vif;
- struct ath_tx_control txctl = {};
- struct sk_buff *skb;
- struct ieee80211_tx_info *info;
- int band = sc->offchannel.chan.chandef.chan->band;
-
- skb = ieee80211_probereq_get(sc->hw, vif,
- ssid->ssid, ssid->ssid_len, req->ie_len);
- if (!skb)
- return;
-
- info = IEEE80211_SKB_CB(skb);
- if (req->no_cck)
- info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
-
- if (req->ie_len)
- memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
-
- skb_set_queue_mapping(skb, IEEE80211_AC_VO);
-
- if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
- goto error;
-
- txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel = true;
- if (ath_tx_start(sc->hw, skb, &txctl))
- goto error;
-
- return;
-
-error:
- ieee80211_free_txskb(sc->hw, skb);
-}
-
-static void ath_scan_channel_start(struct ath_softc *sc)
-{
- struct cfg80211_scan_request *req = sc->offchannel.scan_req;
- int i;
-
- if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
- req->n_ssids) {
- for (i = 0; i < req->n_ssids; i++)
- ath_scan_send_probe(sc, &req->ssids[i]);
-
- }
-
- sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
- mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
-}
-
-void ath_offchannel_channel_change(struct ath_softc *sc)
-{
- switch (sc->offchannel.state) {
- case ATH_OFFCHANNEL_PROBE_SEND:
- if (!sc->offchannel.scan_req)
- return;
-
- if (sc->cur_chan->chandef.chan !=
- sc->offchannel.chan.chandef.chan)
- return;
-
- ath_scan_channel_start(sc);
- break;
- case ATH_OFFCHANNEL_IDLE:
- if (!sc->offchannel.scan_req)
- return;
-
- ath_scan_complete(sc, false);
- break;
- case ATH_OFFCHANNEL_ROC_START:
- if (sc->cur_chan != &sc->offchannel.chan)
- break;
-
- sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
- mod_timer(&sc->offchannel.timer, jiffies +
- msecs_to_jiffies(sc->offchannel.duration));
- ieee80211_ready_on_channel(sc->hw);
- break;
- case ATH_OFFCHANNEL_ROC_DONE:
- ath_roc_complete(sc, false);
- break;
- default:
- break;
- }
-}
-
-void ath_offchannel_timer(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *)data;
- struct ath_chanctx *ctx;
-
- switch (sc->offchannel.state) {
- case ATH_OFFCHANNEL_PROBE_WAIT:
- if (!sc->offchannel.scan_req)
- return;
-
- /* get first active channel context */
- ctx = ath_chanctx_get_oper_chan(sc, true);
- if (ctx->active) {
- sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
- ath_chanctx_switch(sc, ctx, NULL);
- mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
- break;
- }
- /* fall through */
- case ATH_OFFCHANNEL_SUSPEND:
- if (!sc->offchannel.scan_req)
- return;
-
- ath_scan_next_channel(sc);
- break;
- case ATH_OFFCHANNEL_ROC_START:
- case ATH_OFFCHANNEL_ROC_WAIT:
- ctx = ath_chanctx_get_oper_chan(sc, false);
- sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
- ath_chanctx_switch(sc, ctx, NULL);
- break;
- default:
- break;
- }
-}
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req)
@@ -2430,8 +2131,13 @@ static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
sc->offchannel.scan_req = req;
sc->offchannel.scan_idx = 0;
- if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE)
+ ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n",
+ vif->addr);
+
+ if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
+ ath_dbg(common, CHAN_CTX, "Starting HW scan\n");
ath_offchannel_next(sc);
+ }
out:
mutex_unlock(&sc->mutex);
@@ -2443,6 +2149,9 @@ static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr);
mutex_lock(&sc->mutex);
del_timer_sync(&sc->offchannel.timer);
@@ -2456,6 +2165,7 @@ static int ath9k_remain_on_channel(struct ieee80211_hw *hw,
enum ieee80211_roc_type type)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0;
mutex_lock(&sc->mutex);
@@ -2470,8 +2180,14 @@ static int ath9k_remain_on_channel(struct ieee80211_hw *hw,
sc->offchannel.roc_chan = chan;
sc->offchannel.roc_duration = duration;
- if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE)
+ ath_dbg(common, CHAN_CTX,
+ "RoC request on vif: %pM, type: %d duration: %d\n",
+ vif->addr, type, duration);
+
+ if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
+ ath_dbg(common, CHAN_CTX, "Starting RoC period\n");
ath_offchannel_next(sc);
+ }
out:
mutex_unlock(&sc->mutex);
@@ -2482,9 +2198,11 @@ out:
static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
mutex_lock(&sc->mutex);
+ ath_dbg(common, CHAN_CTX, "Cancel RoC\n");
del_timer_sync(&sc->offchannel.timer);
if (sc->offchannel.roc_vif) {
@@ -2501,6 +2219,7 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_chanctx *ctx, **ptr;
int pos;
@@ -2515,10 +2234,18 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw,
ctx->assigned = true;
pos = ctx - &sc->chanctx[0];
ctx->hw_queue_base = pos * IEEE80211_NUM_ACS;
+
+ ath_dbg(common, CHAN_CTX,
+ "Add channel context: %d MHz\n",
+ conf->def.chan->center_freq);
+
ath_chanctx_set_channel(sc, ctx, &conf->def);
+ ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN);
+
mutex_unlock(&sc->mutex);
return 0;
}
+
mutex_unlock(&sc->mutex);
return -ENOSPC;
}
@@ -2528,12 +2255,19 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_chanctx *ctx = ath_chanctx_get(conf);
mutex_lock(&sc->mutex);
+
+ ath_dbg(common, CHAN_CTX,
+ "Remove channel context: %d MHz\n",
+ conf->def.chan->center_freq);
+
ctx->assigned = false;
ctx->hw_queue_base = -1;
ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN);
+
mutex_unlock(&sc->mutex);
}
@@ -2542,9 +2276,13 @@ static void ath9k_change_chanctx(struct ieee80211_hw *hw,
u32 changed)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_chanctx *ctx = ath_chanctx_get(conf);
mutex_lock(&sc->mutex);
+ ath_dbg(common, CHAN_CTX,
+ "Change channel context: %d MHz\n",
+ conf->def.chan->center_freq);
ath_chanctx_set_channel(sc, ctx, &conf->def);
mutex_unlock(&sc->mutex);
}
@@ -2554,16 +2292,24 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_chanctx *ctx = ath_chanctx_get(conf);
int i;
mutex_lock(&sc->mutex);
+
+ ath_dbg(common, CHAN_CTX,
+ "Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n",
+ vif->addr, vif->type, vif->p2p,
+ conf->def.chan->center_freq);
+
avp->chanctx = ctx;
list_add_tail(&avp->list, &ctx->vifs);
ath9k_calculate_summary_state(sc, ctx);
for (i = 0; i < IEEE80211_NUM_ACS; i++)
vif->hw_queue[i] = ctx->hw_queue_base + i;
+
mutex_unlock(&sc->mutex);
return 0;
@@ -2574,36 +2320,79 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_chanctx *ctx = ath_chanctx_get(conf);
int ac;
mutex_lock(&sc->mutex);
+
+ ath_dbg(common, CHAN_CTX,
+ "Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n",
+ vif->addr, vif->type, vif->p2p,
+ conf->def.chan->center_freq);
+
avp->chanctx = NULL;
list_del(&avp->list);
ath9k_calculate_summary_state(sc, ctx);
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE;
+
+ mutex_unlock(&sc->mutex);
+}
+
+static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
+ bool changed = false;
+
+ if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+ return;
+
+ if (!avp->chanctx)
+ return;
+
+ mutex_lock(&sc->mutex);
+
+ spin_lock_bh(&sc->chan_lock);
+ if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
+ sc->next_chan = avp->chanctx;
+ changed = true;
+ }
+ ath_dbg(common, CHAN_CTX,
+ "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
+ __func__, changed);
+ sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
+ spin_unlock_bh(&sc->chan_lock);
+
+ if (changed)
+ ath_chanctx_set_next(sc, true);
+
mutex_unlock(&sc->mutex);
}
void ath9k_fill_chanctx_ops(void)
{
- if (!ath9k_use_chanctx)
+ if (!ath9k_is_chanctx_enabled())
return;
- ath9k_ops.hw_scan = ath9k_hw_scan;
- ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan;
- ath9k_ops.remain_on_channel = ath9k_remain_on_channel;
+ ath9k_ops.hw_scan = ath9k_hw_scan;
+ ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan;
+ ath9k_ops.remain_on_channel = ath9k_remain_on_channel;
ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel;
- ath9k_ops.add_chanctx = ath9k_add_chanctx;
- ath9k_ops.remove_chanctx = ath9k_remove_chanctx;
- ath9k_ops.change_chanctx = ath9k_change_chanctx;
- ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx;
- ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx;
- ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active;
+ ath9k_ops.add_chanctx = ath9k_add_chanctx;
+ ath9k_ops.remove_chanctx = ath9k_remove_chanctx;
+ ath9k_ops.change_chanctx = ath9k_change_chanctx;
+ ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx;
+ ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx;
+ ath9k_ops.mgd_prepare_tx = ath9k_mgd_prepare_tx;
}
+#endif
+
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 74ab1d0..957a877 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -387,7 +387,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->hw->conf.radar_enabled)
rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR;
- if (sc->rx.rxfilter & FIF_PROBE_REQ)
+ spin_lock_bh(&sc->chan_lock);
+
+ if (sc->cur_chan->rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
/*
@@ -398,24 +400,24 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->sc_ah->is_monitoring)
rfilt |= ATH9K_RX_FILTER_PROM;
- if (sc->rx.rxfilter & FIF_CONTROL)
+ if (sc->cur_chan->rxfilter & FIF_CONTROL)
rfilt |= ATH9K_RX_FILTER_CONTROL;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
- (sc->nvifs <= 1) &&
- !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
+ (sc->cur_chan->nvifs <= 1) &&
+ !(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
else
rfilt |= ATH9K_RX_FILTER_BEACON;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
- (sc->rx.rxfilter & FIF_PSPOLL))
+ (sc->cur_chan->rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL;
- if (conf_is_ht(&sc->hw->conf))
+ if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
- if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
+ if (sc->cur_chan->nvifs > 1 || (sc->cur_chan->rxfilter & FIF_OTHER_BSS)) {
/* This is needed for older chips */
if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160)
rfilt |= ATH9K_RX_FILTER_PROM;
@@ -425,22 +427,24 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
rfilt |= ATH9K_RX_FILTER_4ADDRESS;
- if (ath9k_use_chanctx &&
+ if (ath9k_is_chanctx_enabled() &&
test_bit(ATH_OP_SCANNING, &common->op_flags))
rfilt |= ATH9K_RX_FILTER_BEACON;
+ spin_unlock_bh(&sc->chan_lock);
+
return rfilt;
}
-int ath_startrecv(struct ath_softc *sc)
+void ath_startrecv(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_rxbuf *bf, *tbf;
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
ath_edma_start_recv(sc);
- return 0;
+ return;
}
if (list_empty(&sc->rx.rxbuf))
@@ -463,8 +467,6 @@ int ath_startrecv(struct ath_softc *sc)
start_recv:
ath_opmode_init(sc);
ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel);
-
- return 0;
}
static void ath_flushrecv(struct ath_softc *sc)
@@ -547,8 +549,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
"Reconfigure beacon timers based on synchronized timestamp\n");
if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
ath9k_set_beacon(sc);
- if (sc->p2p_ps_vif)
- ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+
+ ath9k_p2p_beacon_sync(sc);
}
if (ath_beacon_dtim_pending_cab(skb)) {
@@ -867,8 +869,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
* everything but the rate is checked here, the rate check is done
* separately to avoid doing two lookups for a rate for each frame.
*/
- if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter))
+ spin_lock_bh(&sc->chan_lock);
+ if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error,
+ sc->cur_chan->rxfilter)) {
+ spin_unlock_bh(&sc->chan_lock);
return -EINVAL;
+ }
+ spin_unlock_bh(&sc->chan_lock);
if (ath_is_mybeacon(common, hdr)) {
RX_STAT_INC(rx_beacons);
@@ -892,9 +899,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
return -EINVAL;
}
- if (rx_stats->is_mybeacon) {
- sc->sched.next_tbtt = rx_stats->rs_tstamp;
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED);
+ if (ath9k_is_chanctx_enabled()) {
+ if (rx_stats->is_mybeacon)
+ ath_chanctx_beacon_recv_ev(sc, rx_stats->rs_tstamp,
+ ATH_CHANCTX_EVENT_BEACON_RECEIVED);
}
ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/spectral.c
index 5fe29b9..8f68426 100644
--- a/drivers/net/wireless/ath/ath9k/spectral.c
+++ b/drivers/net/wireless/ath/ath9k/spectral.c
@@ -253,7 +253,7 @@ static ssize_t write_file_spec_scan_ctl(struct file *file,
if (strncmp("trigger", buf, 7) == 0) {
ath9k_spectral_scan_trigger(sc->hw);
- } else if (strncmp("background", buf, 9) == 0) {
+ } else if (strncmp("background", buf, 10) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
} else if (strncmp("chanscan", buf, 8) == 0) {
diff --git a/drivers/net/wireless/ath/ath9k/spectral.h b/drivers/net/wireless/ath/ath9k/spectral.h
index ead6341..7b410c6 100644
--- a/drivers/net/wireless/ath/ath9k/spectral.h
+++ b/drivers/net/wireless/ath/ath9k/spectral.h
@@ -17,6 +17,8 @@
#ifndef SPECTRAL_H
#define SPECTRAL_H
+#include "../spectral_common.h"
+
/* enum spectral_mode:
*
* @SPECTRAL_DISABLED: spectral mode is disabled
@@ -54,8 +56,6 @@ struct ath_ht20_mag_info {
u8 max_exp;
} __packed;
-#define SPECTRAL_HT20_NUM_BINS 56
-
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data by -1/+2. This struct is for reference only.
*/
@@ -83,8 +83,6 @@ struct ath_ht20_40_mag_info {
u8 max_exp;
} __packed;
-#define SPECTRAL_HT20_40_NUM_BINS 128
-
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data. This struct is for reference only.
*/
@@ -125,71 +123,6 @@ static inline u8 spectral_bitmap_weight(u8 *bins)
return bins[0] & 0x3f;
}
-/* FFT sample format given to userspace via debugfs.
- *
- * Please keep the type/length at the front position and change
- * other fields after adding another sample type
- *
- * TODO: this might need rework when switching to nl80211-based
- * interface.
- */
-enum ath_fft_sample_type {
- ATH_FFT_SAMPLE_HT20 = 1,
- ATH_FFT_SAMPLE_HT20_40,
-};
-
-struct fft_sample_tlv {
- u8 type; /* see ath_fft_sample */
- __be16 length;
- /* type dependent data follows */
-} __packed;
-
-struct fft_sample_ht20 {
- struct fft_sample_tlv tlv;
-
- u8 max_exp;
-
- __be16 freq;
- s8 rssi;
- s8 noise;
-
- __be16 max_magnitude;
- u8 max_index;
- u8 bitmap_weight;
-
- __be64 tsf;
-
- u8 data[SPECTRAL_HT20_NUM_BINS];
-} __packed;
-
-struct fft_sample_ht20_40 {
- struct fft_sample_tlv tlv;
-
- u8 channel_type;
- __be16 freq;
-
- s8 lower_rssi;
- s8 upper_rssi;
-
- __be64 tsf;
-
- s8 lower_noise;
- s8 upper_noise;
-
- __be16 lower_max_magnitude;
- __be16 upper_max_magnitude;
-
- u8 lower_max_index;
- u8 upper_max_index;
-
- u8 lower_bitmap_weight;
- u8 upper_bitmap_weight;
-
- u8 max_exp;
-
- u8 data[SPECTRAL_HT20_40_NUM_BINS];
-} __packed;
-
void ath9k_spectral_init_debug(struct ath_softc *sc);
void ath9k_spectral_deinit_debug(struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index 2397292..8a69d08 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -174,7 +174,7 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
ssize_t len;
int r;
- if (sc->nvifs > 1)
+ if (sc->cur_chan->nvifs > 1)
return -EOPNOTSUPP;
len = min(count, sizeof(buf) - 1);
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c
index a4f4f0d..5f30e58 100644
--- a/drivers/net/wireless/ath/ath9k/wow.c
+++ b/drivers/net/wireless/ath/ath9k/wow.c
@@ -193,7 +193,8 @@ int ath9k_suspend(struct ieee80211_hw *hw,
u32 wow_triggers_enabled = 0;
int ret = 0;
- cancel_work_sync(&sc->chanctx_work);
+ ath9k_deinit_channel_context(sc);
+
mutex_lock(&sc->mutex);
ath_cancel_work(sc);
@@ -231,7 +232,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
goto fail_wow;
}
- if (sc->nvifs > 1) {
+ if (sc->cur_chan->nvifs > 1) {
ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
ret = 1;
goto fail_wow;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 704fcbc..2819866 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2632,8 +2632,11 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
sc->beacon.tx_processed = true;
sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
- ath_chanctx_event(sc, NULL,
- ATH_CHANCTX_EVENT_BEACON_SENT);
+ if (ath9k_is_chanctx_enabled()) {
+ ath_chanctx_event(sc, NULL,
+ ATH_CHANCTX_EVENT_BEACON_SENT);
+ }
+
ath9k_csa_update(sc);
continue;
}
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index f8ded84..ef5b6dc 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1430,18 +1430,10 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
if (!sta_info->ht_sta)
return -EOPNOTSUPP;
- rcu_read_lock();
- if (rcu_dereference(sta_info->agg[tid])) {
- rcu_read_unlock();
- return -EBUSY;
- }
-
tid_info = kzalloc(sizeof(struct carl9170_sta_tid),
GFP_ATOMIC);
- if (!tid_info) {
- rcu_read_unlock();
+ if (!tid_info)
return -ENOMEM;
- }
tid_info->hsn = tid_info->bsn = tid_info->snx = (*ssn);
tid_info->state = CARL9170_TID_STATE_PROGRESS;
@@ -1460,7 +1452,6 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
list_add_tail_rcu(&tid_info->list, &ar->tx_ampdu_list);
rcu_assign_pointer(sta_info->agg[tid], tid_info);
spin_unlock_bh(&ar->tx_ampdu_list_lock);
- rcu_read_unlock();
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index 4cadfd4..ae86a600 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -1557,7 +1557,7 @@ static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar)
}
out:
- rcu_assign_pointer(ar->beacon_iter, cvif);
+ RCU_INIT_POINTER(ar->beacon_iter, cvif);
return cvif;
}
diff --git a/drivers/net/wireless/ath/spectral_common.h b/drivers/net/wireless/ath/spectral_common.h
new file mode 100644
index 0000000..0d742ac
--- /dev/null
+++ b/drivers/net/wireless/ath/spectral_common.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SPECTRAL_COMMON_H
+#define SPECTRAL_COMMON_H
+
+#define SPECTRAL_HT20_NUM_BINS 56
+#define SPECTRAL_HT20_40_NUM_BINS 128
+
+/* TODO: could possibly be 512, but no samples this large
+ * could be acquired so far.
+ */
+#define SPECTRAL_ATH10K_MAX_NUM_BINS 256
+
+/* FFT sample format given to userspace via debugfs.
+ *
+ * Please keep the type/length at the front position and change
+ * other fields after adding another sample type
+ *
+ * TODO: this might need rework when switching to nl80211-based
+ * interface.
+ */
+enum ath_fft_sample_type {
+ ATH_FFT_SAMPLE_HT20 = 1,
+ ATH_FFT_SAMPLE_HT20_40,
+ ATH_FFT_SAMPLE_ATH10K,
+};
+
+struct fft_sample_tlv {
+ u8 type; /* see ath_fft_sample */
+ __be16 length;
+ /* type dependent data follows */
+} __packed;
+
+struct fft_sample_ht20 {
+ struct fft_sample_tlv tlv;
+
+ u8 max_exp;
+
+ __be16 freq;
+ s8 rssi;
+ s8 noise;
+
+ __be16 max_magnitude;
+ u8 max_index;
+ u8 bitmap_weight;
+
+ __be64 tsf;
+
+ u8 data[SPECTRAL_HT20_NUM_BINS];
+} __packed;
+
+struct fft_sample_ht20_40 {
+ struct fft_sample_tlv tlv;
+
+ u8 channel_type;
+ __be16 freq;
+
+ s8 lower_rssi;
+ s8 upper_rssi;
+
+ __be64 tsf;
+
+ s8 lower_noise;
+ s8 upper_noise;
+
+ __be16 lower_max_magnitude;
+ __be16 upper_max_magnitude;
+
+ u8 lower_max_index;
+ u8 upper_max_index;
+
+ u8 lower_bitmap_weight;
+ u8 upper_bitmap_weight;
+
+ u8 max_exp;
+
+ u8 data[SPECTRAL_HT20_40_NUM_BINS];
+} __packed;
+
+struct fft_sample_ath10k {
+ struct fft_sample_tlv tlv;
+ u8 chan_width_mhz;
+ __be16 freq1;
+ __be16 freq2;
+ __be16 noise;
+ __be16 max_magnitude;
+ __be16 total_gain_db;
+ __be16 base_pwr_db;
+ __be64 tsf;
+ s8 max_index;
+ u8 rssi;
+ u8 relpwr_db;
+ u8 avgpwr_db;
+ u8 max_exp;
+
+ u8 data[0];
+} __packed;
+
+#endif /* SPECTRAL_COMMON_H */
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index ce8c038..481680a 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -39,3 +39,12 @@ config WIL6210_TRACING
option if you are interested in debugging the driver.
If unsure, say Y to make it easier to debug problems.
+
+config WIL6210_PLATFORM_MSM
+ bool "wil6210 MSM platform specific support"
+ depends on WIL6210
+ depends on ARCH_MSM
+ default y
+ ---help---
+ Say Y here to enable wil6210 driver support for MSM
+ platform specific features
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index c7a3465..a471d74 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -10,7 +10,10 @@ wil6210-y += interrupt.o
wil6210-y += txrx.o
wil6210-y += debug.o
wil6210-y += rx_reorder.o
+wil6210-y += fw.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
+wil6210-y += wil_platform.o
+wil6210-$(CONFIG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 4ac2c20..f3a31e8 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -296,6 +296,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
n = min(request->n_channels, 4U);
for (i = 0; i < n; i++) {
int ch = request->channels[i]->hw_value;
+
if (ch == 0) {
wil_err(wil,
"Scan requested for unknown frequency %dMhz\n",
@@ -308,15 +309,47 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
request->channels[i]->center_freq);
}
+ if (request->ie_len)
+ print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET,
+ request->ie, request->ie_len);
+ else
+ wil_dbg_misc(wil, "Scan has no IE's\n");
+
+ rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len,
+ request->ie);
+ if (rc) {
+ wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc);
+ goto out;
+ }
+
rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
- if (rc)
+out:
+ if (rc) {
+ del_timer_sync(&wil->scan_timer);
wil->scan_request = NULL;
+ }
return rc;
}
+static void wil_print_connect_params(struct wil6210_priv *wil,
+ struct cfg80211_connect_params *sme)
+{
+ wil_info(wil, "Connecting to:\n");
+ if (sme->channel) {
+ wil_info(wil, " Channel: %d freq %d\n",
+ sme->channel->hw_value, sme->channel->center_freq);
+ }
+ if (sme->bssid)
+ wil_info(wil, " BSSID: %pM\n", sme->bssid);
+ if (sme->ssid)
+ print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
+ 16, 1, sme->ssid, sme->ssid_len, true);
+ wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
+}
+
static int wil_cfg80211_connect(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_connect_params *sme)
@@ -333,6 +366,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
test_bit(wil_status_fwconnected, &wil->status))
return -EALREADY;
+ wil_print_connect_params(wil, sme);
+
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
sme->ssid, sme->ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@@ -358,22 +393,22 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
sme->ie_len);
goto out;
}
- /*
- * For secure assoc, send:
- * (1) WMI_DELETE_CIPHER_KEY_CMD
- * (2) WMI_SET_APPIE_CMD
- */
+ /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
rc = wmi_del_cipher_key(wil, 0, bss->bssid);
if (rc) {
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
goto out;
}
- /* WMI_SET_APPIE_CMD */
- rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
- if (rc) {
- wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
- goto out;
- }
+ }
+
+ /* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
+ * elements. Send it also in case it's empty, to erase previously set
+ * ies in FW.
+ */
+ rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
+ if (rc) {
+ wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
+ goto out;
}
/* WMI_CONNECT_CMD */
@@ -619,6 +654,45 @@ static int wil_fix_bcon(struct wil6210_priv *wil,
return rc;
}
+static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_beacon_data *bcon)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int rc;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ if (wil_fix_bcon(wil, bcon)) {
+ wil_dbg_misc(wil, "Fixed bcon\n");
+ wil_print_bcon_data(bcon);
+ }
+
+ /* FW do not form regular beacon, so bcon IE's are not set
+ * For the DMG bcon, when it will be supported, bcon IE's will
+ * be reused; add something like:
+ * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
+ * bcon->beacon_ies);
+ */
+ rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
+ bcon->proberesp_ies_len,
+ bcon->proberesp_ies);
+ if (rc) {
+ wil_err(wil, "set_ie(PROBE_RESP) failed\n");
+ return rc;
+ }
+
+ rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
+ bcon->assocresp_ies_len,
+ bcon->assocresp_ies);
+ if (rc) {
+ wil_err(wil, "set_ie(ASSOC_RESP) failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
static int wil_cfg80211_start_ap(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_ap_settings *info)
@@ -656,12 +730,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
- rc = wil_reset(wil);
- if (rc)
- goto out;
-
- /* Rx VRING. */
- rc = wil_rx_init(wil);
+ __wil_down(wil);
+ rc = __wil_up(wil);
if (rc)
goto out;
@@ -669,9 +739,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
if (rc)
goto out;
- /* MAC address - pre-requisite for other commands */
- wmi_set_mac_address(wil, ndev->dev_addr);
-
/* IE's */
/* bcon 'head IE's are not relevant for 60g band */
/*
@@ -693,7 +760,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
if (rc)
goto out;
-
netif_carrier_on(ndev);
out:
@@ -704,7 +770,7 @@ out:
static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
struct net_device *ndev)
{
- int rc = 0;
+ int rc, rc1;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "%s()\n", __func__);
@@ -713,8 +779,12 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
rc = wmi_pcp_stop(wil);
+ __wil_down(wil);
+ rc1 = __wil_up(wil);
+
mutex_unlock(&wil->mutex);
- return rc;
+
+ return min(rc, rc1);
}
static int wil_cfg80211_del_station(struct wiphy *wiphy,
@@ -744,6 +814,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.del_key = wil_cfg80211_del_key,
.set_default_key = wil_cfg80211_set_default_key,
/* AP mode */
+ .change_beacon = wil_cfg80211_change_beacon,
.start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap,
.del_station = wil_cfg80211_del_station,
@@ -753,6 +824,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
{
/* TODO: set real value */
wiphy->max_scan_ssids = 10;
+ wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
wiphy->max_num_pmkids = 0 /* TODO: */;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
@@ -762,8 +834,8 @@ static void wil_wiphy_init(struct wiphy *wiphy)
*/
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
- dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
- __func__, wiphy->flags);
+ dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
+ __func__, wiphy->flags);
wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
@@ -784,7 +856,9 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev)
int rc = 0;
struct wireless_dev *wdev;
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ dev_dbg(dev, "%s()\n", __func__);
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
if (!wdev)
return ERR_PTR(-ENOMEM);
@@ -816,6 +890,8 @@ void wil_wdev_free(struct wil6210_priv *wil)
{
struct wireless_dev *wdev = wil_to_wdev(wil);
+ dev_dbg(wil_to_dev(wil), "%s()\n", __func__);
+
if (!wdev)
return;
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 8f66186..eb2204e 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -22,6 +22,7 @@
#include <linux/power_supply.h>
#include "wil6210.h"
+#include "wmi.h"
#include "txrx.h"
/* Nasty hack. Better have per device instances */
@@ -29,6 +30,21 @@ static u32 mem_addr;
static u32 dbg_txdesc_index;
static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
+enum dbg_off_type {
+ doff_u32 = 0,
+ doff_x32 = 1,
+ doff_ulong = 2,
+ doff_io32 = 3,
+};
+
+/* offset to "wil" */
+struct dbg_off {
+ const char *name;
+ umode_t mode;
+ ulong off;
+ enum dbg_off_type type;
+};
+
static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
const char *name, struct vring *vring,
char _s, char _h)
@@ -45,20 +61,22 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
if (x)
seq_printf(s, "0x%08x\n", ioread32(x));
else
- seq_printf(s, "???\n");
+ seq_puts(s, "???\n");
if (vring->va && (vring->size < 1025)) {
uint i;
+
for (i = 0; i < vring->size; i++) {
volatile struct vring_tx_desc *d = &vring->va[i].tx;
+
if ((i % 64) == 0 && (i != 0))
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
_s : (vring->ctx[i].skb ? _h : 'h'));
}
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
}
- seq_printf(s, "}\n");
+ seq_puts(s, "}\n");
}
static int wil_vring_debugfs_show(struct seq_file *s, void *data)
@@ -69,7 +87,7 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
- struct vring *vring = &(wil->vring_tx[i]);
+ struct vring *vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
if (vring->va) {
@@ -147,7 +165,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
if (!wmi_addr(wil, r.base) ||
!wmi_addr(wil, r.tail) ||
!wmi_addr(wil, r.head)) {
- seq_printf(s, " ??? pointers are garbage?\n");
+ seq_puts(s, " ??? pointers are garbage?\n");
goto out;
}
@@ -166,6 +184,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
le32_to_cpu(d.addr));
if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
u16 len = le16_to_cpu(hdr.len);
+
seq_printf(s, " -> %04x %04x %04x %02x\n",
le16_to_cpu(hdr.seq), len,
le16_to_cpu(hdr.type), hdr.flags);
@@ -183,6 +202,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
wil_memcpy_fromio_32(databuf, src, len);
while (n < len) {
int l = min(len - n, 16);
+
hex_dump_to_buffer(databuf + n, l,
16, 1, printbuf,
sizeof(printbuf),
@@ -192,11 +212,11 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
}
}
} else {
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
}
}
out:
- seq_printf(s, "}\n");
+ seq_puts(s, "}\n");
}
static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
@@ -244,9 +264,9 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
umode_t mode,
struct dentry *parent,
- void __iomem *value)
+ void *value)
{
- return debugfs_create_file(name, mode, parent, (void * __force)value,
+ return debugfs_create_file(name, mode, parent, value,
&fops_iomem_x32);
}
@@ -255,11 +275,13 @@ static int wil_debugfs_ulong_set(void *data, u64 val)
*(ulong *)data = val;
return 0;
}
+
static int wil_debugfs_ulong_get(void *data, u64 *val)
{
*val = *(ulong *)data;
return 0;
}
+
DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
wil_debugfs_ulong_set, "%llu\n");
@@ -270,6 +292,62 @@ static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
}
+/**
+ * wil6210_debugfs_init_offset - create set of debugfs files
+ * @wil - driver's context, used for printing
+ * @dbg - directory on the debugfs, where files will be created
+ * @base - base address used in address calculation
+ * @tbl - table with file descriptions. Should be terminated with empty element.
+ *
+ * Creates files accordingly to the @tbl.
+ */
+static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
+ struct dentry *dbg, void *base,
+ const struct dbg_off * const tbl)
+{
+ int i;
+
+ for (i = 0; tbl[i].name; i++) {
+ struct dentry *f;
+
+ switch (tbl[i].type) {
+ case doff_u32:
+ f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ case doff_x32:
+ f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ case doff_ulong:
+ f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
+ dbg, base + tbl[i].off);
+ break;
+ case doff_io32:
+ f = wil_debugfs_create_iomem_x32(tbl[i].name,
+ tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ default:
+ f = ERR_PTR(-EINVAL);
+ }
+ if (IS_ERR_OR_NULL(f))
+ wil_err(wil, "Create file \"%s\": err %ld\n",
+ tbl[i].name, PTR_ERR(f));
+ }
+}
+
+static const struct dbg_off isr_off[] = {
+ {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
+ {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
+ {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
+ {"ICS", S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
+ {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
+ {"IMS", S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
+ {"IMC", S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
const char *name,
struct dentry *parent, u32 off)
@@ -279,24 +357,19 @@ static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d,
- wil->csr + off);
- wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 4);
- wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 8);
- wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d,
- wil->csr + off + 12);
- wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 16);
- wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d,
- wil->csr + off + 20);
- wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d,
- wil->csr + off + 24);
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
+ isr_off);
return 0;
}
+static const struct dbg_off pseudo_isr_off[] = {
+ {"CAUSE", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
+ {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
+ {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
struct dentry *parent)
{
@@ -305,16 +378,19 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
- wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
- wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW));
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+ pseudo_isr_off);
return 0;
}
+static const struct dbg_off itr_cnt_off[] = {
+ {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
+ {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
+ {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
struct dentry *parent)
{
@@ -323,12 +399,8 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
- wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_DATA));
- wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+ itr_cnt_off);
return 0;
}
@@ -359,7 +431,7 @@ static const struct file_operations fops_memread = {
};
static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
enum { max_count = 4096 };
struct debugfs_blob_wrapper *blob = file->private_data;
@@ -411,6 +483,7 @@ struct dentry *wil_debugfs_create_ioblob(const char *name,
{
return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
}
+
/*---reset---*/
static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
@@ -436,6 +509,7 @@ static const struct file_operations fops_reset = {
.write = wil_write_file_reset,
.open = simple_open,
};
+
/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
@@ -446,6 +520,7 @@ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
bool on;
char *kbuf = kmalloc(len + 1, GFP_KERNEL);
+
if (!kbuf)
return -ENOMEM;
if (copy_from_user(kbuf, buf, len)) {
@@ -482,6 +557,7 @@ static const struct file_operations fops_rxon = {
.write = wil_write_file_rxon,
.open = simple_open,
};
+
/*---tx_mgmt---*/
/* Write mgmt frame to this file to send it */
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@@ -492,8 +568,8 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
struct wireless_dev *wdev = wil_to_wdev(wil);
struct cfg80211_mgmt_tx_params params;
int rc;
-
void *frame = kmalloc(len, GFP_KERNEL);
+
if (!frame)
return -ENOMEM;
@@ -562,8 +638,10 @@ static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
{
char printbuf[16 * 3 + 2];
int i = 0;
+
while (i < len) {
int l = min(len - i, 16);
+
hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
sizeof(printbuf), false);
seq_printf(s, "%s%s\n", prefix, printbuf);
@@ -601,10 +679,8 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
struct wil6210_priv *wil = s->private;
struct vring *vring;
bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
- if (tx)
- vring = &(wil->vring_tx[dbg_vring_index]);
- else
- vring = &wil->vring_rx;
+
+ vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
if (!vring->va) {
if (tx)
@@ -619,7 +695,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
* only field used, .dma.length, is the same
*/
volatile struct vring_tx_desc *d =
- &(vring->va[dbg_txdesc_index].tx);
+ &vring->va[dbg_txdesc_index].tx;
volatile u32 *u = (volatile u32 *)d;
struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
@@ -639,7 +715,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
wil_seq_print_skb(s, skb);
kfree_skb(skb);
}
- seq_printf(s, "}\n");
+ seq_puts(s, "}\n");
} else {
if (tx)
seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
@@ -666,16 +742,79 @@ static const struct file_operations fops_txdesc = {
};
/*---------beamforming------------*/
+static char *wil_bfstatus_str(u32 status)
+{
+ switch (status) {
+ case 0:
+ return "Failed";
+ case 1:
+ return "OK";
+ case 2:
+ return "Retrying";
+ default:
+ return "??";
+ }
+}
+
+static bool is_all_zeros(void * const x_, size_t sz)
+{
+ /* if reply is all-0, ignore this CID */
+ u32 *x = x_;
+ int n;
+
+ for (n = 0; n < sz / sizeof(*x); n++)
+ if (x[n])
+ return false;
+
+ return true;
+}
+
static int wil_bf_debugfs_show(struct seq_file *s, void *data)
{
+ int rc;
+ int i;
struct wil6210_priv *wil = s->private;
- seq_printf(s,
- "TSF : 0x%016llx\n"
- "TxMCS : %d\n"
- "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
- wil->stats.tsf, wil->stats.bf_mcs,
- wil->stats.my_rx_sector, wil->stats.my_tx_sector,
- wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
+ struct wmi_notify_req_cmd cmd = {
+ .interval_usec = 0,
+ };
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_notify_req_done_event evt;
+ } __packed reply;
+
+ for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ u32 status;
+
+ cmd.cid = i;
+ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
+ WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
+ sizeof(reply), 20);
+ /* if reply is all-0, ignore this CID */
+ if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
+ continue;
+
+ status = le32_to_cpu(reply.evt.status);
+ seq_printf(s, "CID %d {\n"
+ " TSF = 0x%016llx\n"
+ " TxMCS = %2d TxTpt = %4d\n"
+ " SQI = %4d\n"
+ " Status = 0x%08x %s\n"
+ " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
+ " Goodput(rx:tx) %4d:%4d\n"
+ "}\n",
+ i,
+ le64_to_cpu(reply.evt.tsf),
+ le16_to_cpu(reply.evt.bf_mcs),
+ le32_to_cpu(reply.evt.tx_tpt),
+ reply.evt.sqi,
+ status, wil_bfstatus_str(status),
+ le16_to_cpu(reply.evt.my_rx_sector),
+ le16_to_cpu(reply.evt.my_tx_sector),
+ le16_to_cpu(reply.evt.other_rx_sector),
+ le16_to_cpu(reply.evt.other_tx_sector),
+ le32_to_cpu(reply.evt.rx_goodput),
+ le32_to_cpu(reply.evt.tx_goodput));
+ }
return 0;
}
@@ -690,6 +829,7 @@ static const struct file_operations fops_bf = {
.read = seq_read,
.llseek = seq_lseek,
};
+
/*---------SSID------------*/
static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -752,10 +892,10 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
u32 t_m, t_r;
-
int rc = wmi_get_temperature(wil, &t_m, &t_r);
+
if (rc) {
- seq_printf(s, "Failed\n");
+ seq_puts(s, "Failed\n");
return 0;
}
@@ -811,6 +951,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
+
switch (p->status) {
case wil_sta_unused:
status = "unused ";
@@ -871,7 +1012,6 @@ static int wil_info_debugfs_show(struct seq_file *s, void *data)
rxf_old = rxf;
txf_old = txf;
-
#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
" " __stringify(x) : ""
@@ -906,6 +1046,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
{
int i;
u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
+
seq_printf(s, "0x%03x [", r->head_seq_num);
for (i = 0; i < r->buf_size; i++) {
if (i == index)
@@ -920,10 +1061,12 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
int i, tid;
+ unsigned long flags;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
+
switch (p->status) {
case wil_sta_unused:
status = "unused ";
@@ -939,13 +1082,16 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
(p->data_port_open ? " data_port_open" : ""));
if (p->status == wil_sta_connected) {
+ spin_lock_irqsave(&p->tid_rx_lock, flags);
for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
+
if (r) {
seq_printf(s, "[%2d] ", tid);
wil_print_rxtid(s, r);
}
}
+ spin_unlock_irqrestore(&p->tid_rx_lock, flags);
}
}
@@ -985,6 +1131,87 @@ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
}
}
+/* misc files */
+static const struct {
+ const char *name;
+ umode_t mode;
+ const struct file_operations *fops;
+} dbg_files[] = {
+ {"mbox", S_IRUGO, &fops_mbox},
+ {"vrings", S_IRUGO, &fops_vring},
+ {"stations", S_IRUGO, &fops_sta},
+ {"desc", S_IRUGO, &fops_txdesc},
+ {"bf", S_IRUGO, &fops_bf},
+ {"ssid", S_IRUGO | S_IWUSR, &fops_ssid},
+ {"mem_val", S_IRUGO, &fops_memread},
+ {"reset", S_IWUSR, &fops_reset},
+ {"rxon", S_IWUSR, &fops_rxon},
+ {"tx_mgmt", S_IWUSR, &fops_txmgmt},
+ {"wmi_send", S_IWUSR, &fops_wmi},
+ {"temp", S_IRUGO, &fops_temp},
+ {"freq", S_IRUGO, &fops_freq},
+ {"link", S_IRUGO, &fops_link},
+ {"info", S_IRUGO, &fops_info},
+};
+
+static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
+ struct dentry *dbg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
+ debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
+ wil, dbg_files[i].fops);
+}
+
+/* interrupt control blocks */
+static const struct {
+ const char *name;
+ u32 icr_off;
+} dbg_icr[] = {
+ {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR)},
+ {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR)},
+ {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR)},
+ {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR)},
+};
+
+static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
+ struct dentry *dbg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
+ wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
+ dbg_icr[i].icr_off);
+}
+
+#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
+ offsetof(struct wil6210_priv, name), type}
+
+/* fields in struct wil6210_priv */
+static const struct dbg_off dbg_wil_off[] = {
+ WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32),
+ WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong),
+ WIL_FIELD(fw_version, S_IRUGO, doff_u32),
+ WIL_FIELD(hw_version, S_IRUGO, doff_x32),
+ {},
+};
+
+static const struct dbg_off dbg_wil_regs[] = {
+ {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
+ doff_io32},
+ {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
+ {},
+};
+
+/* static parameters */
+static const struct dbg_off dbg_statics[] = {
+ {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
+ {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
+ {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
+ {},
+};
+
int wil6210_debugfs_init(struct wil6210_priv *wil)
{
struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
@@ -993,51 +1220,17 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
if (IS_ERR_OR_NULL(dbg))
return -ENODEV;
- debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
- debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
- debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
- debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
- debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
- &dbg_txdesc_index);
- debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg,
- &dbg_vring_index);
-
- debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
- debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
- debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
- &wil->secure_pcp);
- wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg,
- &wil->status);
- debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version);
- debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version);
-
- wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
- HOSTADDR(RGF_USER_USER_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_TX_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_RX_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_MISC_ICR));
- wil6210_debugfs_create_pseudo_ISR(wil, dbg);
- wil6210_debugfs_create_ITR_CNT(wil, dbg);
+ wil6210_debugfs_init_files(wil, dbg);
+ wil6210_debugfs_init_isr(wil, dbg);
+ wil6210_debugfs_init_blobs(wil, dbg);
+ wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
+ wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
+ dbg_wil_regs);
+ wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
- wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg,
- wil->csr +
- HOSTADDR(RGF_USER_USAGE_1));
- debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
- debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
-
- debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
- debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon);
- debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt);
- debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi);
- debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp);
- debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq);
- debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link);
- debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info);
+ wil6210_debugfs_create_pseudo_ISR(wil, dbg);
- wil6210_debugfs_init_blobs(wil, dbg);
+ wil6210_debugfs_create_ITR_CNT(wil, dbg);
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c
new file mode 100644
index 0000000..8c6f3b0
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/crc32.h>
+#include "wil6210.h"
+#include "fw.h"
+
+MODULE_FIRMWARE(WIL_FW_NAME);
+
+/* target operations */
+/* register read */
+#define R(a) ioread32(wil->csr + HOSTADDR(a))
+/* register write. wmb() to make sure it is completed */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+/* register set = read, OR, write */
+#define S(a, v) W(a, R(a) | v)
+/* register clear = read, AND with inverted, write */
+#define C(a, v) W(a, R(a) & ~v)
+
+static
+void wil_memset_toio_32(volatile void __iomem *dst, u32 val,
+ size_t count)
+{
+ volatile u32 __iomem *d = dst;
+
+ for (count += 4; count > 4; count -= 4)
+ __raw_writel(val, d++);
+}
+
+#include "fw_inc.c"
diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h
new file mode 100644
index 0000000..7a2c6c1
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */
+#define WIL_FW_FMT_VERSION (1) /* format version driver supports */
+
+enum wil_fw_record_type {
+ wil_fw_type_comment = 1,
+ wil_fw_type_data = 2,
+ wil_fw_type_fill = 3,
+ wil_fw_type_action = 4,
+ wil_fw_type_verify = 5,
+ wil_fw_type_file_header = 6,
+ wil_fw_type_direct_write = 7,
+ wil_fw_type_gateway_data = 8,
+ wil_fw_type_gateway_data4 = 9,
+};
+
+struct wil_fw_record_head {
+ __le16 type; /* enum wil_fw_record_type */
+ __le16 flags; /* to be defined */
+ __le32 size; /* whole record, bytes after head */
+} __packed;
+
+/* data block. write starting from @addr
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_data, data)
+ */
+struct wil_fw_record_data { /* type == wil_fw_type_data */
+ __le32 addr;
+ __le32 data[0]; /* [data_size], see above */
+} __packed;
+
+/* fill with constant @value, @size bytes starting from @addr */
+struct wil_fw_record_fill { /* type == wil_fw_type_fill */
+ __le32 addr;
+ __le32 value;
+ __le32 size;
+} __packed;
+
+/* free-form comment
+ * for informational purpose, data_size is @head.size from record header
+ */
+struct wil_fw_record_comment { /* type == wil_fw_type_comment */
+ u8 data[0]; /* free-form data [data_size], see above */
+} __packed;
+
+/* perform action
+ * data_size = @head.size - offsetof(struct wil_fw_record_action, data)
+ */
+struct wil_fw_record_action { /* type == wil_fw_type_action */
+ __le32 action; /* action to perform: reset, wait for fw ready etc. */
+ __le32 data[0]; /* action specific, [data_size], see above */
+} __packed;
+
+/* data block for struct wil_fw_record_direct_write */
+struct wil_fw_data_dwrite {
+ __le32 addr;
+ __le32 value;
+ __le32 mask;
+} __packed;
+
+/* write @value to the @addr,
+ * preserve original bits accordingly to the @mask
+ * data_size is @head.size where @head is record header
+ */
+struct wil_fw_record_direct_write { /* type == wil_fw_type_direct_write */
+ struct wil_fw_data_dwrite data[0];
+} __packed;
+
+/* verify condition: [@addr] & @mask == @value
+ * if condition not met, firmware download fails
+ */
+struct wil_fw_record_verify { /* type == wil_fw_verify */
+ __le32 addr; /* read from this address */
+ __le32 value; /* reference value */
+ __le32 mask; /* mask for verification */
+} __packed;
+
+/* file header
+ * First record of every file
+ */
+struct wil_fw_record_file_header {
+ __le32 signature ; /* Wilocity signature */
+ __le32 reserved;
+ __le32 crc; /* crc32 of the following data */
+ __le32 version; /* format version */
+ __le32 data_len; /* total data in file, including this record */
+ u8 comment[32]; /* short description */
+} __packed;
+
+/* 1-dword gateway */
+/* data block for the struct wil_fw_record_gateway_data */
+struct wil_fw_data_gw {
+ __le32 addr;
+ __le32 value;
+} __packed;
+
+/* gateway write block.
+ * write starting address and values from the data buffer
+ * through the gateway
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_gateway_data, data)
+ */
+struct wil_fw_record_gateway_data { /* type == wil_fw_type_gateway_data */
+ __le32 gateway_addr_addr;
+ __le32 gateway_value_addr;
+ __le32 gateway_cmd_addr;
+ __le32 gateway_ctrl_address;
+#define WIL_FW_GW_CTL_BUSY BIT(29) /* gateway busy performing operation */
+#define WIL_FW_GW_CTL_RUN BIT(30) /* start gateway operation */
+ __le32 command;
+ struct wil_fw_data_gw data[0]; /* total size [data_size], see above */
+} __packed;
+
+/* 4-dword gateway */
+/* data block for the struct wil_fw_record_gateway_data4 */
+struct wil_fw_data_gw4 {
+ __le32 addr;
+ __le32 value[4];
+} __packed;
+
+/* gateway write block.
+ * write starting address and values from the data buffer
+ * through the gateway
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_gateway_data4, data)
+ */
+struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
+ __le32 gateway_addr_addr;
+ __le32 gateway_value_addr[4];
+ __le32 gateway_cmd_addr;
+ __le32 gateway_ctrl_address; /* same logic as for 1-dword gw */
+ __le32 command;
+ struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
+} __packed;
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
new file mode 100644
index 0000000..44cb71f
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Algorithmic part of the firmware download.
+ * To be included in the container file providing framework
+ */
+
+#define wil_err_fw(wil, fmt, arg...) wil_err(wil, "ERR[ FW ]" fmt, ##arg)
+#define wil_dbg_fw(wil, fmt, arg...) wil_dbg(wil, "DBG[ FW ]" fmt, ##arg)
+#define wil_hex_dump_fw(prefix_str, prefix_type, rowsize, \
+ groupsize, buf, len, ascii) \
+ print_hex_dump_debug("DBG[ FW ]" prefix_str, \
+ prefix_type, rowsize, \
+ groupsize, buf, len, ascii)
+
+#define FW_ADDR_CHECK(ioaddr, val, msg) do { \
+ ioaddr = wmi_buffer(wil, val); \
+ if (!ioaddr) { \
+ wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
+ le32_to_cpu(val)); \
+ return -EINVAL; \
+ } \
+ } while (0)
+
+/**
+ * wil_fw_verify - verify firmware file validity
+ *
+ * perform various checks for the firmware file header.
+ * records are not validated.
+ *
+ * Return file size or negative error
+ */
+static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size)
+{
+ const struct wil_fw_record_head *hdr = (const void *)data;
+ struct wil_fw_record_file_header fh;
+ const struct wil_fw_record_file_header *fh_;
+ u32 crc;
+ u32 dlen;
+
+ if (size % 4) {
+ wil_err_fw(wil, "image size not aligned: %zu\n", size);
+ return -EINVAL;
+ }
+ /* have enough data for the file header? */
+ if (size < sizeof(*hdr) + sizeof(fh)) {
+ wil_err_fw(wil, "file too short: %zu bytes\n", size);
+ return -EINVAL;
+ }
+
+ /* start with the file header? */
+ if (le16_to_cpu(hdr->type) != wil_fw_type_file_header) {
+ wil_err_fw(wil, "no file header\n");
+ return -EINVAL;
+ }
+
+ /* data_len */
+ fh_ = (struct wil_fw_record_file_header *)&hdr[1];
+ dlen = le32_to_cpu(fh_->data_len);
+ if (dlen % 4) {
+ wil_err_fw(wil, "data length not aligned: %lu\n", (ulong)dlen);
+ return -EINVAL;
+ }
+ if (size < dlen) {
+ wil_err_fw(wil, "file truncated at %zu/%lu\n",
+ size, (ulong)dlen);
+ return -EINVAL;
+ }
+ if (dlen < sizeof(*hdr) + sizeof(fh)) {
+ wil_err_fw(wil, "data length too short: %lu\n", (ulong)dlen);
+ return -EINVAL;
+ }
+
+ /* signature */
+ if (le32_to_cpu(fh_->signature) != WIL_FW_SIGNATURE) {
+ wil_err_fw(wil, "bad header signature: 0x%08x\n",
+ le32_to_cpu(fh_->signature));
+ return -EINVAL;
+ }
+
+ /* version */
+ if (le32_to_cpu(fh_->version) > WIL_FW_FMT_VERSION) {
+ wil_err_fw(wil, "unsupported header version: %d\n",
+ le32_to_cpu(fh_->version));
+ return -EINVAL;
+ }
+
+ /* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/
+ fh = *fh_;
+ fh.crc = 0;
+
+ crc = crc32_le(~0, (unsigned char const *)hdr, sizeof(*hdr));
+ crc = crc32_le(crc, (unsigned char const *)&fh, sizeof(fh));
+ crc = crc32_le(crc, (unsigned char const *)&fh_[1],
+ dlen - sizeof(*hdr) - sizeof(fh));
+ crc = ~crc;
+
+ if (crc != le32_to_cpu(fh_->crc)) {
+ wil_err_fw(wil, "checksum mismatch:"
+ " calculated for %lu bytes 0x%08x != 0x%08x\n",
+ (ulong)dlen, crc, le32_to_cpu(fh_->crc));
+ return -EINVAL;
+ }
+
+ return (int)dlen;
+}
+
+static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
+
+ return 0;
+}
+
+static int fw_handle_data(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_data *d = data;
+ void __iomem *dst;
+ size_t s = size - sizeof(*d);
+
+ if (size < sizeof(*d) + sizeof(u32)) {
+ wil_err_fw(wil, "data record too short: %zu\n", size);
+ return -EINVAL;
+ }
+
+ FW_ADDR_CHECK(dst, d->addr, "address");
+ wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
+ s);
+ wil_memcpy_toio_32(dst, d->data, s);
+ wmb(); /* finish before processing next record */
+
+ return 0;
+}
+
+static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_fill *d = data;
+ void __iomem *dst;
+ u32 v;
+ size_t s = (size_t)le32_to_cpu(d->size);
+
+ if (size != sizeof(*d)) {
+ wil_err_fw(wil, "bad size for fill record: %zu\n", size);
+ return -EINVAL;
+ }
+
+ if (s < sizeof(u32)) {
+ wil_err_fw(wil, "fill size too short: %zu\n", s);
+ return -EINVAL;
+ }
+
+ if (s % sizeof(u32)) {
+ wil_err_fw(wil, "fill size not aligned: %zu\n", s);
+ return -EINVAL;
+ }
+
+ FW_ADDR_CHECK(dst, d->addr, "address");
+
+ v = le32_to_cpu(d->value);
+ wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
+ le32_to_cpu(d->addr), v, s);
+ wil_memset_toio_32(dst, v, s);
+ wmb(); /* finish before processing next record */
+
+ return 0;
+}
+
+static int fw_handle_file_header(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_file_header *d = data;
+
+ if (size != sizeof(*d)) {
+ wil_err_fw(wil, "file header length incorrect: %zu\n", size);
+ return -EINVAL;
+ }
+
+ wil_dbg_fw(wil, "new file, ver. %d, %i bytes\n",
+ d->version, d->data_len);
+ wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, d->comment,
+ sizeof(d->comment), true);
+
+ return 0;
+}
+
+static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_direct_write *d = data;
+ const struct wil_fw_data_dwrite *block = d->data;
+ int n, i;
+
+ if (size % sizeof(*block)) {
+ wil_err_fw(wil, "record size not aligned on %zu: %zu\n",
+ sizeof(*block), size);
+ return -EINVAL;
+ }
+ n = size / sizeof(*block);
+
+ for (i = 0; i < n; i++) {
+ void __iomem *dst;
+ u32 m = le32_to_cpu(block[i].mask);
+ u32 v = le32_to_cpu(block[i].value);
+ u32 x, y;
+
+ FW_ADDR_CHECK(dst, block[i].addr, "address");
+
+ x = ioread32(dst);
+ y = (x & m) | (v & ~m);
+ wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x "
+ "(old 0x%08x val 0x%08x mask 0x%08x)\n",
+ le32_to_cpu(block[i].addr), y, x, v, m);
+ iowrite32(y, dst);
+ wmb(); /* finish before processing next record */
+ }
+
+ return 0;
+}
+
+static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr,
+ void __iomem *gwa_cmd, void __iomem *gwa_ctl, u32 gw_cmd,
+ u32 a)
+{
+ unsigned delay = 0;
+
+ iowrite32(a, gwa_addr);
+ iowrite32(gw_cmd, gwa_cmd);
+ wmb(); /* finish before activate gw */
+
+ iowrite32(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */
+ do {
+ udelay(1); /* typical time is few usec */
+ if (delay++ > 100) {
+ wil_err_fw(wil, "gw timeout\n");
+ return -EINVAL;
+ }
+ } while (ioread32(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */
+
+ return 0;
+}
+
+static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_gateway_data *d = data;
+ const struct wil_fw_data_gw *block = d->data;
+ void __iomem *gwa_addr;
+ void __iomem *gwa_val;
+ void __iomem *gwa_cmd;
+ void __iomem *gwa_ctl;
+ u32 gw_cmd;
+ int n, i;
+
+ if (size < sizeof(*d) + sizeof(*block)) {
+ wil_err_fw(wil, "gateway record too short: %zu\n", size);
+ return -EINVAL;
+ }
+
+ if ((size - sizeof(*d)) % sizeof(*block)) {
+ wil_err_fw(wil, "gateway record data size"
+ " not aligned on %zu: %zu\n",
+ sizeof(*block), size - sizeof(*d));
+ return -EINVAL;
+ }
+ n = (size - sizeof(*d)) / sizeof(*block);
+
+ gw_cmd = le32_to_cpu(d->command);
+
+ wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
+ n, gw_cmd);
+
+ FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
+ FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
+ FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
+ FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
+
+ wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
+ " cmd 0x%08x ctl 0x%08x\n",
+ le32_to_cpu(d->gateway_addr_addr),
+ le32_to_cpu(d->gateway_value_addr),
+ le32_to_cpu(d->gateway_cmd_addr),
+ le32_to_cpu(d->gateway_ctrl_address));
+
+ for (i = 0; i < n; i++) {
+ int rc;
+ u32 a = le32_to_cpu(block[i].addr);
+ u32 v = le32_to_cpu(block[i].value);
+
+ wil_dbg_fw(wil, " gw write[%3d] [0x%08x] <== 0x%08x\n",
+ i, a, v);
+
+ iowrite32(v, gwa_val);
+ rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_gateway_data4 *d = data;
+ const struct wil_fw_data_gw4 *block = d->data;
+ void __iomem *gwa_addr;
+ void __iomem *gwa_val[ARRAY_SIZE(block->value)];
+ void __iomem *gwa_cmd;
+ void __iomem *gwa_ctl;
+ u32 gw_cmd;
+ int n, i, k;
+
+ if (size < sizeof(*d) + sizeof(*block)) {
+ wil_err_fw(wil, "gateway4 record too short: %zu\n", size);
+ return -EINVAL;
+ }
+
+ if ((size - sizeof(*d)) % sizeof(*block)) {
+ wil_err_fw(wil, "gateway4 record data size"
+ " not aligned on %zu: %zu\n",
+ sizeof(*block), size - sizeof(*d));
+ return -EINVAL;
+ }
+ n = (size - sizeof(*d)) / sizeof(*block);
+
+ gw_cmd = le32_to_cpu(d->command);
+
+ wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
+ n, gw_cmd);
+
+ FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
+ for (k = 0; k < ARRAY_SIZE(block->value); k++)
+ FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
+ "gateway_value_addr");
+ FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
+ FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
+
+ wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
+ le32_to_cpu(d->gateway_addr_addr),
+ le32_to_cpu(d->gateway_cmd_addr),
+ le32_to_cpu(d->gateway_ctrl_address));
+ wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE, 16, 4,
+ d->gateway_value_addr, sizeof(d->gateway_value_addr),
+ false);
+
+ for (i = 0; i < n; i++) {
+ int rc;
+ u32 a = le32_to_cpu(block[i].addr);
+ u32 v[ARRAY_SIZE(block->value)];
+
+ for (k = 0; k < ARRAY_SIZE(block->value); k++)
+ v[k] = le32_to_cpu(block[i].value[k]);
+
+ wil_dbg_fw(wil, " gw4 write[%3d] [0x%08x] <==\n", i, a);
+ wil_hex_dump_fw(" val ", DUMP_PREFIX_NONE, 16, 4, v,
+ sizeof(v), false);
+
+ for (k = 0; k < ARRAY_SIZE(block->value); k++)
+ iowrite32(v[k], gwa_val[k]);
+ rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static const struct {
+ int type;
+ int (*handler)(struct wil6210_priv *wil, const void *data, size_t size);
+} wil_fw_handlers[] = {
+ {wil_fw_type_comment, fw_handle_comment},
+ {wil_fw_type_data, fw_handle_data},
+ {wil_fw_type_fill, fw_handle_fill},
+ /* wil_fw_type_action */
+ /* wil_fw_type_verify */
+ {wil_fw_type_file_header, fw_handle_file_header},
+ {wil_fw_type_direct_write, fw_handle_direct_write},
+ {wil_fw_type_gateway_data, fw_handle_gateway_data},
+ {wil_fw_type_gateway_data4, fw_handle_gateway_data4},
+};
+
+static int wil_fw_handle_record(struct wil6210_priv *wil, int type,
+ const void *data, size_t size)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++) {
+ if (wil_fw_handlers[i].type == type)
+ return wil_fw_handlers[i].handler(wil, data, size);
+ }
+
+ wil_err_fw(wil, "unknown record type: %d\n", type);
+ return -EINVAL;
+}
+
+/**
+ * wil_fw_load - load FW into device
+ *
+ * Load the FW and uCode code and data to the corresponding device
+ * memory regions
+ *
+ * Return error code
+ */
+static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
+{
+ int rc = 0;
+ const struct wil_fw_record_head *hdr;
+ size_t s, hdr_sz;
+
+ for (hdr = data;; hdr = (const void *)hdr + s, size -= s) {
+ if (size < sizeof(*hdr))
+ break;
+ hdr_sz = le32_to_cpu(hdr->size);
+ s = sizeof(*hdr) + hdr_sz;
+ if (s > size)
+ break;
+ if (hdr_sz % 4) {
+ wil_err_fw(wil, "unaligned record size: %zu\n",
+ hdr_sz);
+ return -EINVAL;
+ }
+ rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type),
+ &hdr[1], hdr_sz);
+ if (rc)
+ return rc;
+ }
+ if (size) {
+ wil_err_fw(wil, "unprocessed bytes: %zu\n", size);
+ if (size >= sizeof(*hdr)) {
+ wil_err_fw(wil, "Stop at offset %ld"
+ " record type %d [%zd bytes]\n",
+ (const void *)hdr - data,
+ le16_to_cpu(hdr->type), hdr_sz);
+ }
+ return -EINVAL;
+ }
+ /* Mark FW as loaded from host */
+ S(RGF_USER_USAGE_6, 1);
+
+ return rc;
+}
+
+/**
+ * wil_request_firmware - Request firmware and load to device
+ *
+ * Request firmware image from the file and load it to device
+ *
+ * Return error code
+ */
+int wil_request_firmware(struct wil6210_priv *wil, const char *name)
+{
+ int rc, rc1;
+ const struct firmware *fw;
+ size_t sz;
+ const void *d;
+
+ rc = request_firmware(&fw, name, wil_to_pcie_dev(wil));
+ if (rc) {
+ wil_err_fw(wil, "Failed to load firmware %s\n", name);
+ return rc;
+ }
+ wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
+
+ for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) {
+ rc1 = wil_fw_verify(wil, d, sz);
+ if (rc1 < 0) {
+ rc = rc1;
+ goto out;
+ }
+ rc = wil_fw_load(wil, d, rc1);
+ if (rc < 0)
+ goto out;
+ }
+
+out:
+ release_firmware(fw);
+ return rc;
+}
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 67f1002..7269bac 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -135,7 +135,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
}
-void wil6210_disable_irq(struct wil6210_priv *wil)
+void wil_mask_irq(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@@ -145,7 +145,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil)
wil6210_mask_irq_pseudo(wil);
}
-void wil6210_enable_irq(struct wil6210_priv *wil)
+void wil_unmask_irq(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@@ -196,8 +196,13 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
wil_dbg_irq(wil, "RX done\n");
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
if (test_bit(wil_status_reset_done, &wil->status)) {
- wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
- napi_schedule(&wil->napi_rx);
+ if (test_bit(wil_status_napi_en, &wil->status)) {
+ wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
+ napi_schedule(&wil->napi_rx);
+ } else {
+ wil_err(wil, "Got Rx interrupt while "
+ "stopping interface\n");
+ }
} else {
wil_err(wil, "Got Rx interrupt while in reset\n");
}
@@ -506,7 +511,8 @@ free0:
return rc;
}
-/* can't use wil_ioread32_and_clear because ICC value is not ser yet */
+
+/* can't use wil_ioread32_and_clear because ICC value is not set yet */
static inline void wil_clear32(void __iomem *addr)
{
u32 x = ioread32(addr);
@@ -522,11 +528,15 @@ void wil6210_clear_irq(struct wil6210_priv *wil)
offsetof(struct RGF_ICR, ICR));
wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICR));
+ wmb(); /* make sure write completed */
}
int wil6210_init_irq(struct wil6210_priv *wil, int irq)
{
int rc;
+
+ wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi);
+
if (wil->n_msi == 3)
rc = wil6210_request_3msi(wil, irq);
else
@@ -534,17 +544,14 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq)
wil6210_thread_irq,
wil->n_msi ? 0 : IRQF_SHARED,
WIL_NAME, wil);
- if (rc)
- return rc;
-
- wil6210_enable_irq(wil);
-
- return 0;
+ return rc;
}
void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
{
- wil6210_disable_irq(wil);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ wil_mask_irq(wil);
free_irq(irq, wil);
if (wil->n_msi == 3) {
free_irq(irq + 1, wil);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 3704d2a..21667e0 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,11 +20,22 @@
#include "wil6210.h"
#include "txrx.h"
+#include "wmi.h"
+
+#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
+#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
static bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
+static bool no_fw_load = true;
+module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
+
+#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
+#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
+
/*
* Due to a hardware issue,
* one has to read/write to/from NIC in 32-bit chunks;
@@ -64,6 +75,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wil_sta_info *sta = &wil->sta[cid];
+
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
sta->status);
@@ -83,9 +95,16 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
}
for (i = 0; i < WIL_STA_TID_NUM; i++) {
- struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+ struct wil_tid_ampdu_rx *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+ r = sta->tid_rx[i];
sta->tid_rx[i] = NULL;
wil_tid_ampdu_rx_free(wil, r);
+
+ spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
}
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
if (wil->vring2cid_tid[i][0] == cid)
@@ -202,10 +221,8 @@ static void wil_fw_error_worker(struct work_struct *work)
case NL80211_IFTYPE_MONITOR:
wil_info(wil, "fw error recovery started (try %d)...\n",
wil->recovery_count);
- wil_reset(wil);
-
- /* need to re-allocate Rx ring after reset */
- wil_rx_init(wil);
+ __wil_down(wil);
+ __wil_up(wil);
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
@@ -220,6 +237,7 @@ static void wil_fw_error_worker(struct work_struct *work)
static int wil_find_free_vring(struct wil6210_priv *wil)
{
int i;
+
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
if (!wil->vring_tx[i].va)
return i;
@@ -254,14 +272,19 @@ static void wil_connect_worker(struct work_struct *work)
int wil_priv_init(struct wil6210_priv *wil)
{
+ uint i;
+
wil_dbg_misc(wil, "%s()\n", __func__);
memset(wil->sta, 0, sizeof(wil->sta));
+ for (i = 0; i < WIL6210_MAX_CID; i++)
+ spin_lock_init(&wil->sta[i].tid_rx_lock);
mutex_init(&wil->mutex);
mutex_init(&wil->wmi_mutex);
init_completion(&wil->wmi_ready);
+ init_completion(&wil->wmi_call);
wil->pending_connect_cid = -1;
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
@@ -292,12 +315,16 @@ int wil_priv_init(struct wil6210_priv *wil)
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
{
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
del_timer_sync(&wil->connect_timer);
_wil6210_disconnect(wil, bssid);
}
void wil_priv_deinit(struct wil6210_priv *wil)
{
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
del_timer_sync(&wil->scan_timer);
cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
@@ -309,7 +336,29 @@ void wil_priv_deinit(struct wil6210_priv *wil)
destroy_workqueue(wil->wmi_wq);
}
-static void wil_target_reset(struct wil6210_priv *wil)
+/* target operations */
+/* register read */
+#define R(a) ioread32(wil->csr + HOSTADDR(a))
+/* register write. wmb() to make sure it is completed */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+/* register set = read, OR, write */
+#define S(a, v) W(a, R(a) | v)
+/* register clear = read, AND with inverted, write */
+#define C(a, v) W(a, R(a) & ~v)
+
+static inline void wil_halt_cpu(struct wil6210_priv *wil)
+{
+ W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
+ W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
+}
+
+static inline void wil_release_cpu(struct wil6210_priv *wil)
+{
+ /* Start CPU */
+ W(RGF_USER_USER_CPU_0, 1);
+}
+
+static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
u32 hw_state;
@@ -318,57 +367,41 @@ static void wil_target_reset(struct wil6210_priv *wil)
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
- /* register read */
-#define R(a) ioread32(wil->csr + HOSTADDR(a))
- /* register write */
-#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
- /* register set = read, OR, write */
-#define S(a, v) W(a, R(a) | v)
- /* register clear = read, AND with inverted, write */
-#define C(a, v) W(a, R(a) & ~v)
-
wil->hw_version = R(RGF_USER_FW_REV_ID);
rev_id = wil->hw_version & 0xff;
/* Clear MAC link up */
S(RGF_HP_CTRL, BIT(15));
- /* hpal_perst_from_pad_src_n_mask */
- S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
- /* car_perst_rst_src_n_mask */
- S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
- wmb(); /* order is important here */
+ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
+ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
+
+ wil_halt_cpu(wil);
+ C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
- wmb(); /* order is important here */
+ W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
}
- W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
- W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
- wmb(); /* order is important here */
-
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000B0 : 0x00000170);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
- wmb(); /* order is important here */
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
- wmb(); /* order is important here */
+ W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
}
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
- wmb(); /* order is important here */
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
/* reset A2 PCIE AHB */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
-
} else {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
if (rev_id == 1) {
@@ -378,21 +411,19 @@ static void wil_target_reset(struct wil6210_priv *wil)
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
}
-
}
/* TODO: check order here!!! Erez code is different */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
- wmb(); /* order is important here */
- /* wait until device ready */
+ /* wait until device ready. typical time is 200..250 msec */
do {
- msleep(1);
+ msleep(RST_DELAY);
hw_state = R(RGF_USER_HW_MACHINE_STATE);
- if (delay++ > 100) {
+ if (delay++ > RST_COUNT) {
wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
hw_state);
- return;
+ return -ETIME;
}
} while (hw_state != HW_MACHINE_BOOT_DONE);
@@ -401,15 +432,15 @@ static void wil_target_reset(struct wil6210_priv *wil)
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
- wmb(); /* order is important here */
- wil_dbg_misc(wil, "Reset completed in %d ms\n", delay);
+ wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
+ return 0;
+}
#undef R
#undef W
#undef S
#undef C
-}
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
{
@@ -424,6 +455,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
{
ulong to = msecs_to_jiffies(1000);
ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
+
if (0 == left) {
wil_err(wil, "Firmware not ready\n");
return -ETIME;
@@ -443,15 +475,15 @@ int wil_reset(struct wil6210_priv *wil)
{
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
WARN_ON(!mutex_is_locked(&wil->mutex));
+ WARN_ON(test_bit(wil_status_napi_en, &wil->status));
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL);
wil->status = 0; /* prevent NAPI from being scheduled */
- if (test_bit(wil_status_napi_en, &wil->status)) {
- napi_synchronize(&wil->napi_rx);
- }
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -461,24 +493,50 @@ int wil_reset(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
- wil6210_disable_irq(wil);
+ wil_mask_irq(wil);
wmi_event_flush(wil);
flush_workqueue(wil->wmi_wq_conn);
flush_workqueue(wil->wmi_wq);
- /* TODO: put MAC in reset */
- wil_target_reset(wil);
-
+ rc = wil_target_reset(wil);
wil_rx_fini(wil);
+ if (rc)
+ return rc;
+
+ if (!no_fw_load) {
+ wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME);
+ wil_halt_cpu(wil);
+ /* Loading f/w from the file */
+ rc = wil_request_firmware(wil, WIL_FW_NAME);
+ if (rc)
+ return rc;
+
+ /* clear any interrupts which on-card-firmware may have set */
+ wil6210_clear_irq(wil);
+ { /* CAF_ICR - clear and mask */
+ u32 a = HOSTADDR(RGF_CAF_ICR) +
+ offsetof(struct RGF_ICR, ICR);
+ u32 m = HOSTADDR(RGF_CAF_ICR) +
+ offsetof(struct RGF_ICR, IMV);
+ u32 icr = ioread32(wil->csr + a);
+
+ iowrite32(icr, wil->csr + a); /* W1C */
+ iowrite32(~0, wil->csr + m);
+ wmb(); /* wait for completion */
+ }
+ wil_release_cpu(wil);
+ } else {
+ wil_info(wil, "Use firmware from on-card flash\n");
+ }
/* init after reset */
wil->pending_connect_cid = -1;
reinit_completion(&wil->wmi_ready);
+ reinit_completion(&wil->wmi_call);
- /* TODO: release MAC reset */
- wil6210_enable_irq(wil);
+ wil_unmask_irq(wil);
/* we just started MAC, wait for FW ready */
rc = wil_wait_for_fw_ready(wil);
@@ -514,7 +572,7 @@ void wil_link_off(struct wil6210_priv *wil)
netif_carrier_off(ndev);
}
-static int __wil_up(struct wil6210_priv *wil)
+int __wil_up(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
@@ -560,11 +618,15 @@ static int __wil_up(struct wil6210_priv *wil)
/* MAC address - pre-requisite for other commands */
wmi_set_mac_address(wil, ndev->dev_addr);
-
+ wil_dbg_misc(wil, "NAPI enable\n");
napi_enable(&wil->napi_rx);
napi_enable(&wil->napi_tx);
set_bit(wil_status_napi_en, &wil->status);
+ if (wil->platform_ops.bus_request)
+ wil->platform_ops.bus_request(wil->platform_handle,
+ WIL_MAX_BUS_REQUEST_KBPS);
+
return 0;
}
@@ -572,6 +634,8 @@ int wil_up(struct wil6210_priv *wil)
{
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
mutex_lock(&wil->mutex);
rc = __wil_up(wil);
mutex_unlock(&wil->mutex);
@@ -579,13 +643,23 @@ int wil_up(struct wil6210_priv *wil)
return rc;
}
-static int __wil_down(struct wil6210_priv *wil)
+int __wil_down(struct wil6210_priv *wil)
{
+ int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
+ WAIT_FOR_DISCONNECT_INTERVAL_MS;
+
WARN_ON(!mutex_is_locked(&wil->mutex));
- clear_bit(wil_status_napi_en, &wil->status);
- napi_disable(&wil->napi_rx);
- napi_disable(&wil->napi_tx);
+ if (wil->platform_ops.bus_request)
+ wil->platform_ops.bus_request(wil->platform_handle, 0);
+
+ wil_disable_irq(wil);
+ if (test_and_clear_bit(wil_status_napi_en, &wil->status)) {
+ napi_disable(&wil->napi_rx);
+ napi_disable(&wil->napi_tx);
+ wil_dbg_misc(wil, "NAPI disable\n");
+ }
+ wil_enable_irq(wil);
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -595,7 +669,24 @@ static int __wil_down(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
- wil6210_disconnect(wil, NULL);
+ if (test_bit(wil_status_fwconnected, &wil->status) ||
+ test_bit(wil_status_fwconnecting, &wil->status))
+ wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
+
+ /* make sure wil is idle (not connected) */
+ mutex_unlock(&wil->mutex);
+ while (iter--) {
+ int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
+ !test_bit(wil_status_fwconnecting, &wil->status);
+ if (idle)
+ break;
+ msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
+ }
+ mutex_lock(&wil->mutex);
+
+ if (!iter)
+ wil_err(wil, "timeout waiting for idle FW/HW\n");
+
wil_rx_fini(wil);
return 0;
@@ -605,6 +696,8 @@ int wil_down(struct wil6210_priv *wil)
{
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
mutex_lock(&wil->mutex);
rc = __wil_down(wil);
mutex_unlock(&wil->mutex);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 7afce6e..1c0c77d 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,11 +17,14 @@
#include <linux/etherdevice.h>
#include "wil6210.h"
+#include "txrx.h"
static int wil_open(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
return wil_up(wil);
}
@@ -29,6 +32,8 @@ static int wil_stop(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
return wil_down(wil);
}
@@ -36,8 +41,10 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- if (new_mtu < 68 || new_mtu > IEEE80211_MAX_DATA_LEN_DMG)
+ if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) {
+ wil_err(wil, "invalid MTU %d\n", new_mtu);
return -EINVAL;
+ }
wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu);
ndev->mtu = new_mtu;
@@ -121,6 +128,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
wil->csr = csr;
wil->wdev = wdev;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
rc = wil_priv_init(wil);
if (rc) {
dev_err(dev, "wil_priv_init failed\n");
@@ -168,11 +177,17 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
void wil_if_free(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
if (!ndev)
return;
- free_netdev(ndev);
wil_priv_deinit(wil);
+
+ wil_to_ndev(wil) = NULL;
+ free_netdev(ndev);
+
wil_wdev_free(wil);
}
@@ -181,6 +196,8 @@ int wil_if_add(struct wil6210_priv *wil)
struct net_device *ndev = wil_to_ndev(wil);
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
rc = register_netdev(ndev);
if (rc < 0) {
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
@@ -196,5 +213,7 @@ void wil_if_remove(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
unregister_netdev(ndev);
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index d3fbfa2..66626a8 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
#include "wil6210.h"
@@ -30,6 +31,28 @@ static bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
+void wil_disable_irq(struct wil6210_priv *wil)
+{
+ int irq = wil->pdev->irq;
+
+ disable_irq(irq);
+ if (wil->n_msi == 3) {
+ disable_irq(irq + 1);
+ disable_irq(irq + 2);
+ }
+}
+
+void wil_enable_irq(struct wil6210_priv *wil)
+{
+ int irq = wil->pdev->irq;
+
+ enable_irq(irq);
+ if (wil->n_msi == 3) {
+ enable_irq(irq + 1);
+ enable_irq(irq + 2);
+ }
+}
+
/* Bus ops */
static int wil_if_pcie_enable(struct wil6210_priv *wil)
{
@@ -41,6 +64,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
*/
int msi_only = pdev->msi_enabled;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
pdev->msi_enabled = 0;
pci_set_master(pdev);
@@ -107,6 +132,8 @@ static int wil_if_pcie_disable(struct wil6210_priv *wil)
{
struct pci_dev *pdev = wil->pdev;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
pci_clear_master(pdev);
/* disable and release IRQ */
wil6210_fini_irq(wil, pdev->irq);
@@ -180,6 +207,10 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
wil->board = board;
wil6210_clear_irq(wil);
+
+ wil->platform_handle =
+ wil_platform_init(&pdev->dev, &wil->platform_ops);
+
/* FW should raise IRQ when ready */
rc = wil_if_pcie_enable(wil);
if (rc) {
@@ -204,6 +235,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
bus_disable:
wil_if_pcie_disable(wil);
if_free:
+ if (wil->platform_ops.uninit)
+ wil->platform_ops.uninit(wil->platform_handle);
wil_if_free(wil);
err_iounmap:
pci_iounmap(pdev, csr);
@@ -218,12 +251,17 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
static void wil_pcie_remove(struct pci_dev *pdev)
{
struct wil6210_priv *wil = pci_get_drvdata(pdev);
+ void __iomem *csr = wil->csr;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
wil6210_debugfs_remove(wil);
- wil_if_pcie_disable(wil);
wil_if_remove(wil);
+ wil_if_pcie_disable(wil);
+ if (wil->platform_ops.uninit)
+ wil->platform_ops.uninit(wil->platform_handle);
wil_if_free(wil);
- pci_iounmap(pdev, wil->csr);
+ pci_iounmap(pdev, csr);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
}
@@ -243,6 +281,8 @@ static const struct pci_device_id wil6210_pcie_ids[] = {
.driver_data = (kernel_ulong_t)&wil_board_marlon },
{ PCI_DEVICE(0x1ae9, 0x0310),
.driver_data = (kernel_ulong_t)&wil_board_sparrow },
+ { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
+ .driver_data = (kernel_ulong_t)&wil_board_sparrow },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 180ca47..489cb73 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
#include "wil6210.h"
#include "txrx.h"
@@ -82,22 +98,25 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
int mid = wil_rxdesc_mid(d);
u16 seq = wil_rxdesc_seq(d);
struct wil_sta_info *sta = &wil->sta[cid];
- struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
+ struct wil_tid_ampdu_rx *r;
u16 hseq;
int index;
+ unsigned long flags;
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
mid, cid, tid, seq);
+ spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+ r = sta->tid_rx[tid];
if (!r) {
+ spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
wil_netif_rx_any(skb, ndev);
return;
}
hseq = r->head_seq_num;
- spin_lock(&r->reorder_lock);
-
/** Due to the race between WMI events, where BACK establishment
* reported, and data Rx, few packets may be pass up before reorder
* buffer get allocated. Catch up by pretending SSN is what we
@@ -160,13 +179,14 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
wil_reorder_release(wil, r);
out:
- spin_unlock(&r->reorder_lock);
+ spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
}
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
int size, u16 ssn)
{
struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
+
if (!r)
return NULL;
@@ -181,7 +201,6 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
return NULL;
}
- spin_lock_init(&r->reorder_lock);
r->ssn = ssn;
r->head_seq_num = ssn;
r->buf_size = size;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index d346794..2936ef0 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -52,6 +52,7 @@ static inline int wil_vring_is_full(struct vring *vring)
{
return wil_vring_next_tail(vring) == vring->swhead;
}
+
/*
* Available space in Tx Vring
*/
@@ -86,6 +87,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
size_t sz = vring->size * sizeof(vring->va[0]);
uint i;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
BUILD_BUG_ON(sizeof(vring->va[0]) != 32);
vring->swhead = 0;
@@ -110,7 +113,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
* we can use any
*/
for (i = 0; i < vring->size; i++) {
- volatile struct vring_tx_desc *_d = &(vring->va[i].tx);
+ volatile struct vring_tx_desc *_d = &vring->va[i].tx;
+
_d->dma.status = TX_DMA_STATUS_DU;
}
@@ -125,6 +129,7 @@ static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d,
{
dma_addr_t pa = wil_desc_addr(&d->dma.addr);
u16 dmalen = le16_to_cpu(d->dma.length);
+
switch (ctx->mapped_as) {
case wil_mapped_as_single:
dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
@@ -143,6 +148,18 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
struct device *dev = wil_to_dev(wil);
size_t sz = vring->size * sizeof(vring->va[0]);
+ if (tx) {
+ int vring_index = vring - wil->vring_tx;
+
+ wil_dbg_misc(wil, "free Tx vring %d [%d] 0x%p:%pad 0x%p\n",
+ vring_index, vring->size, vring->va,
+ &vring->pa, vring->ctx);
+ } else {
+ wil_dbg_misc(wil, "free Rx vring [%d] 0x%p:%pad 0x%p\n",
+ vring->size, vring->va,
+ &vring->pa, vring->ctx);
+ }
+
while (!wil_vring_is_empty(vring)) {
dma_addr_t pa;
u16 dmalen;
@@ -191,11 +208,12 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
struct device *dev = wil_to_dev(wil);
unsigned int sz = RX_BUF_LEN;
struct vring_rx_desc dd, *d = &dd;
- volatile struct vring_rx_desc *_d = &(vring->va[i].rx);
+ volatile struct vring_rx_desc *_d = &vring->va[i].rx;
dma_addr_t pa;
/* TODO align */
struct sk_buff *skb = dev_alloc_skb(sz + headroom);
+
if (unlikely(!skb))
return -ENOMEM;
@@ -274,9 +292,11 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
*/
int len = min_t(int, 8 + sizeof(phy_data),
wil_rxdesc_phy_length(d));
+
if (len > 8) {
void *p = skb_tail_pointer(skb);
void *pa = PTR_ALIGN(p, 8);
+
if (skb_tailroom(skb) >= len + (pa - p)) {
phy_length = len - 8;
memcpy(phy_data, pa, phy_length);
@@ -372,13 +392,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
int cid;
struct wil_net_stats *stats;
-
BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
if (wil_vring_is_empty(vring))
return NULL;
- _d = &(vring->va[vring->swhead].rx);
+ _d = &vring->va[vring->swhead].rx;
if (!(_d->dma.status & RX_DMA_STATUS_DU)) {
/* it is not error, we just reached end of Rx done area */
return NULL;
@@ -414,7 +433,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
cid = wil_rxdesc_cid(d);
stats = &wil->sta[cid].stats;
stats->last_mcs_rx = wil_rxdesc_mcs(d);
- wil->stats.last_mcs_rx = stats->last_mcs_rx;
/* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
@@ -533,7 +551,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
[GRO_NORMAL] = "GRO_NORMAL",
[GRO_DROP] = "GRO_DROP",
};
- wil_dbg_txrx(wil, "Rx complete %d bytes => %s,\n",
+ wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
len, gro_res_str[rc]);
}
}
@@ -574,7 +592,6 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
else
wil_netif_rx_any(skb, ndev);
}
-
}
wil_rx_refill(wil, v->size);
}
@@ -584,6 +601,8 @@ int wil_rx_init(struct wil6210_priv *wil)
struct vring *vring = &wil->vring_rx;
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
if (vring->va) {
wil_err(wil, "Rx ring already allocated\n");
return -EINVAL;
@@ -613,6 +632,8 @@ void wil_rx_fini(struct wil6210_priv *wil)
{
struct vring *vring = &wil->vring_rx;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
if (vring->va)
wil_vring_free(wil, vring, 0);
}
@@ -647,6 +668,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
struct vring *vring = &wil->vring_tx[id];
struct vring_tx_data *txdata = &wil->vring_tx_data[id];
+ wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
+ cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
+
if (vring->va) {
wil_err(wil, "Tx ring [%d] already allocated\n", id);
rc = -EINVAL;
@@ -696,6 +720,8 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
if (!vring->va)
return;
+ wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
+
/* make sure NAPI won't touch this vring */
wil->vring_tx_data[id].enabled = 0;
if (test_bit(wil_status_napi_en, &wil->status))
@@ -722,6 +748,7 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
if (wil->vring2cid_tid[i][0] == cid) {
struct vring *v = &wil->vring_tx[i];
+
wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
__func__, eth->h_dest, i);
if (v->va) {
@@ -741,6 +768,7 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil,
{
struct ethhdr *eth = (void *)skb->data;
int cid = wil->vring2cid_tid[vring_index][0];
+
memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
}
@@ -751,7 +779,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
* duplicate skb and send it to other active vrings
*/
static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
struct vring *v, *v2;
struct sk_buff *skb2;
@@ -834,8 +862,8 @@ void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)
}
static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
- struct vring_tx_desc *d,
- struct sk_buff *skb)
+ struct vring_tx_desc *d,
+ struct sk_buff *skb)
{
int protocol;
@@ -903,10 +931,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
1 + nr_frags);
return -ENOMEM;
}
- _d = &(vring->va[i].tx);
+ _d = &vring->va[i].tx;
- pa = dma_map_single(dev, skb->data,
- skb_headlen(skb), DMA_TO_DEVICE);
+ pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb),
skb->data, &pa);
@@ -935,10 +962,11 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
const struct skb_frag_struct *frag =
&skb_shinfo(skb)->frags[f];
int len = skb_frag_size(frag);
+
i = (swhead + f + 1) % vring->size;
- _d = &(vring->va[i].tx);
+ _d = &vring->va[i].tx;
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
- DMA_TO_DEVICE);
+ DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, pa)))
goto dma_error;
vring->ctx[i].mapped_as = wil_mapped_as_page;
@@ -983,7 +1011,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
i = (swhead + f) % vring->size;
ctx = &vring->ctx[i];
- _d = &(vring->va[i].tx);
+ _d = &vring->va[i].tx;
*d = *_d;
_d->dma.status = TX_DMA_STATUS_DU;
wil_txdesc_unmap(dev, d, ctx);
@@ -997,7 +1025,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
return -EINVAL;
}
-
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -1025,15 +1052,15 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
pr_once_fw = false;
/* find vring */
- if (is_unicast_ether_addr(eth->h_dest)) {
+ if (is_unicast_ether_addr(eth->h_dest))
vring = wil_find_tx_vring(wil, skb);
- } else {
+ else
vring = wil_tx_bcast(wil, skb);
- }
if (!vring) {
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
goto drop;
}
+
/* set up vring entry */
rc = wil_tx_vring(wil, vring, skb);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index bc5706a..de04671 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,9 +20,9 @@
#define BUF_SW_OWNED (1)
#define BUF_HW_OWNED (0)
-/* size of max. Rx packet */
-#define RX_BUF_LEN (2048)
-#define TX_BUF_LEN (2048)
+/* size of max. Tx/Rx buffers, as supported by FW */
+#define RX_BUF_LEN (2242)
+#define TX_BUF_LEN (2242)
/* how many bytes to reserve for rtap header? */
#define WIL6210_RTAP_SIZE (128)
@@ -237,7 +237,6 @@ struct vring_tx_mac {
#define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2
#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 /* L4 type: 0-UDP, 2-TCP */
-
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_POS 0
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_LEN 7
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_MSK 0x7F /* MAC hdr len */
@@ -246,7 +245,6 @@ struct vring_tx_mac {
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_LEN 1
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_MSK 0x80 /* 1-IPv4, 0-IPv6 */
-
#define TX_DMA_STATUS_DU BIT(0)
struct vring_tx_dma {
@@ -347,7 +345,6 @@ struct vring_rx_mac {
#define RX_DMA_ERROR_L3_ERR BIT(4)
#define RX_DMA_ERROR_L4_ERR BIT(5)
-
/* Status field */
#define RX_DMA_STATUS_DU BIT(0)
#define RX_DMA_STATUS_ERROR BIT(2)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 67e9624..0ff0dd9 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -21,8 +21,13 @@
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/timex.h>
+#include "wil_platform.h"
+
#define WIL_NAME "wil6210"
+#define WIL_FW_NAME "wil6210.fw"
+
+#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
struct wil_board {
int board;
@@ -86,22 +91,29 @@ struct RGF_ICR {
/* registers - FW addresses */
#define RGF_USER_USAGE_1 (0x880004)
+#define RGF_USER_USAGE_6 (0x880018)
#define RGF_USER_HW_MACHINE_STATE (0x8801dc)
#define HW_MACHINE_BOOT_DONE (0x3fffffd)
#define RGF_USER_USER_CPU_0 (0x8801e0)
+ #define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */
#define RGF_USER_MAC_CPU_0 (0x8801fc)
+ #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */
#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */
#define RGF_USER_CLKS_CTL_0 (0x880abc)
+ #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */
#define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */
#define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10)
#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14)
+ #define BIT_HPAL_PERST_FROM_PAD BIT(6)
+ #define BIT_CAR_PERST_RST BIT(7)
#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */
#define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18)
+#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c)
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
@@ -133,6 +145,11 @@ struct RGF_ICR {
#define RGF_HP_CTRL (0x88265c)
#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4)
+/* MAC timer, usec, for packet lifetime */
+#define RGF_MAC_MTRL_COUNTER_0 (0x886aa8)
+
+#define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */
+
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -151,6 +168,7 @@ struct fw_map {
u32 host; /* PCI/Host address - BAR0 + 0x880000 */
const char *name; /* for debugfs */
};
+
/* array size should be in sync with actual definition in the wmi.c */
extern const struct fw_map fw_mapping[7];
@@ -300,18 +318,12 @@ struct pci_dev;
* @timeout: reset timer value (in TUs).
* @dialog_token: dialog token for aggregation session
* @rcu_head: RCU head used for freeing this struct
- * @reorder_lock: serializes access to reorder buffer, see below.
*
* This structure's lifetime is managed by RCU, assignments to
* the array holding it must hold the aggregation mutex.
*
- * The @reorder_lock is used to protect the members of this
- * struct, except for @timeout, @buf_size and @dialog_token,
- * which are constant across the lifetime of the struct (the
- * dialog token being used only for debugging).
*/
struct wil_tid_ampdu_rx {
- spinlock_t reorder_lock; /* see above */
struct sk_buff **reorder_buf;
unsigned long *reorder_time;
struct timer_list session_timer;
@@ -327,17 +339,6 @@ struct wil_tid_ampdu_rx {
bool first_time; /* is it 1-st time this buffer used? */
};
-struct wil6210_stats {
- u64 tsf;
- u32 snr;
- u16 last_mcs_rx;
- u16 bf_mcs; /* last BF, used for Tx */
- u16 my_rx_sector;
- u16 my_tx_sector;
- u16 peer_rx_sector;
- u16 peer_tx_sector;
-};
-
enum wil_sta_status {
wil_sta_unused = 0,
wil_sta_conn_pending = 1,
@@ -371,6 +372,7 @@ struct wil_sta_info {
bool data_port_open; /* can send any data, not only EAPOL */
/* Rx BACK */
struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
+ spinlock_t tid_rx_lock; /* guarding tid_rx array */
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
};
@@ -397,6 +399,7 @@ struct wil6210_priv {
struct mutex wmi_mutex;
struct wil6210_mbox_ctl mbox_ctl;
struct completion wmi_ready;
+ struct completion wmi_call;
u16 wmi_seq;
u16 reply_id; /**< wait for this WMI event */
void *reply_buf;
@@ -430,11 +433,13 @@ struct wil6210_priv {
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
/* statistics */
- struct wil6210_stats stats;
atomic_t isr_count_rx, isr_count_tx;
/* debugfs */
struct dentry *debug;
struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
+
+ void *platform_handle;
+ struct wil_platform_ops platform_ops;
};
#define wil_to_wiphy(i) (i->wdev->wiphy)
@@ -444,6 +449,7 @@ struct wil6210_priv {
#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
+#define wil_to_pcie_dev(i) (&i->pdev->dev)
int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
int wil_err(struct wil6210_priv *wil, const char *fmt, ...);
@@ -458,6 +464,7 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
+#if defined(CONFIG_DYNAMIC_DEBUG)
#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
print_hex_dump_debug("DBG[TXRX]" prefix_str,\
@@ -469,6 +476,12 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
print_hex_dump_debug("DBG[ WMI]" prefix_str,\
prefix_type, rowsize, \
groupsize, buf, len, ascii)
+#else
+#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \
+ groupsize, buf, len, ascii)
+#define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize, \
+ groupsize, buf, len, ascii)
+#endif
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
size_t count);
@@ -486,7 +499,9 @@ void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_link_on(struct wil6210_priv *wil);
void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
+int __wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
+int __wil_down(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
@@ -519,8 +534,10 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
void wil6210_clear_irq(struct wil6210_priv *wil);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
-void wil6210_disable_irq(struct wil6210_priv *wil);
-void wil6210_enable_irq(struct wil6210_priv *wil);
+void wil_mask_irq(struct wil6210_priv *wil);
+void wil_unmask_irq(struct wil6210_priv *wil);
+void wil_disable_irq(struct wil6210_priv *wil);
+void wil_enable_irq(struct wil6210_priv *wil);
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
u64 *cookie);
@@ -556,4 +573,5 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
int wil_iftype_nl2wmi(enum nl80211_iftype type);
+int wil_request_firmware(struct wil6210_priv *wil, const char *name);
#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
new file mode 100644
index 0000000..8f1d78f
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "linux/device.h"
+#include "wil_platform.h"
+
+#ifdef CONFIG_WIL6210_PLATFORM_MSM
+#include "wil_platform_msm.h"
+#endif
+
+/**
+ * wil_platform_init() - wil6210 platform module init
+ *
+ * The function must be called before all other functions in this module.
+ * It returns a handle which is used with the rest of the API
+ *
+ */
+void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
+{
+ void *handle = NULL;
+
+ if (!ops) {
+ dev_err(dev, "Invalid parameter. Cannot init platform module\n");
+ return NULL;
+ }
+
+#ifdef CONFIG_WIL6210_PLATFORM_MSM
+ handle = wil_platform_msm_init(dev, ops);
+ if (handle)
+ return handle;
+#endif
+
+ /* other platform specific init functions should be called here */
+
+ return handle;
+}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
new file mode 100644
index 0000000..158c73b
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL_PLATFORM_H__
+#define __WIL_PLATFORM_H__
+
+struct device;
+
+/**
+ * struct wil_platform_ops - wil platform module callbacks
+ */
+struct wil_platform_ops {
+ int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */);
+ int (*suspend)(void *handle);
+ int (*resume)(void *handle);
+ void (*uninit)(void *handle);
+};
+
+void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops);
+
+#endif /* __WIL_PLATFORM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
new file mode 100644
index 0000000..b354a74
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/msm-bus.h>
+
+#include "wil_platform.h"
+#include "wil_platform_msm.h"
+
+/**
+ * struct wil_platform_msm - wil6210 msm platform module info
+ *
+ * @dev: device object
+ * @msm_bus_handle: handle for using msm_bus API
+ * @pdata: bus scale info retrieved from DT
+ */
+struct wil_platform_msm {
+ struct device *dev;
+ uint32_t msm_bus_handle;
+ struct msm_bus_scale_pdata *pdata;
+};
+
+#define KBTOB(a) (a * 1000ULL)
+
+/**
+ * wil_platform_get_pdata() - Generate bus client data from device tree
+ * provided by clients.
+ *
+ * dev: device object
+ * of_node: Device tree node to extract information from
+ *
+ * The function returns a valid pointer to the allocated bus-scale-pdata
+ * if the vectors were correctly read from the client's device node.
+ * Any error in reading or parsing the device node will return NULL
+ * to the caller.
+ */
+static struct msm_bus_scale_pdata *wil_platform_get_pdata(
+ struct device *dev,
+ struct device_node *of_node)
+{
+ struct msm_bus_scale_pdata *pdata;
+ struct msm_bus_paths *usecase;
+ int i, j, ret, len;
+ unsigned int num_usecases, num_paths, mem_size;
+ const uint32_t *vec_arr;
+ struct msm_bus_vectors *vectors;
+
+ /* first read num_usecases and num_paths so we can calculate
+ * amount of memory to allocate
+ */
+ ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
+ &num_usecases);
+ if (ret) {
+ dev_err(dev, "Error: num-usecases not found\n");
+ return NULL;
+ }
+
+ ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
+ &num_paths);
+ if (ret) {
+ dev_err(dev, "Error: num_paths not found\n");
+ return NULL;
+ }
+
+ /* pdata memory layout:
+ * msm_bus_scale_pdata
+ * msm_bus_paths[num_usecases]
+ * msm_bus_vectors[num_usecases][num_paths]
+ */
+ mem_size = sizeof(struct msm_bus_scale_pdata) +
+ sizeof(struct msm_bus_paths) * num_usecases +
+ sizeof(struct msm_bus_vectors) * num_usecases * num_paths;
+
+ pdata = kzalloc(mem_size, GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ ret = of_property_read_string(of_node, "qcom,msm-bus,name",
+ &pdata->name);
+ if (ret) {
+ dev_err(dev, "Error: Client name not found\n");
+ goto err;
+ }
+
+ if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) {
+ pdata->active_only = 1;
+ } else {
+ dev_info(dev, "active_only flag absent.\n");
+ dev_info(dev, "Using dual context by default\n");
+ }
+
+ pdata->num_usecases = num_usecases;
+ pdata->usecase = (struct msm_bus_paths *)(pdata + 1);
+
+ vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
+ if (vec_arr == NULL) {
+ dev_err(dev, "Error: Vector array not found\n");
+ goto err;
+ }
+
+ if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
+ dev_err(dev, "Error: Length-error on getting vectors\n");
+ goto err;
+ }
+
+ vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases);
+ for (i = 0; i < num_usecases; i++) {
+ usecase = &pdata->usecase[i];
+ usecase->num_paths = num_paths;
+ usecase->vectors = &vectors[i];
+
+ for (j = 0; j < num_paths; j++) {
+ int index = ((i * num_paths) + j) * 4;
+
+ usecase->vectors[j].src = be32_to_cpu(vec_arr[index]);
+ usecase->vectors[j].dst =
+ be32_to_cpu(vec_arr[index + 1]);
+ usecase->vectors[j].ab = (uint64_t)
+ KBTOB(be32_to_cpu(vec_arr[index + 2]));
+ usecase->vectors[j].ib = (uint64_t)
+ KBTOB(be32_to_cpu(vec_arr[index + 3]));
+ }
+ }
+
+ return pdata;
+
+err:
+ kfree(pdata);
+
+ return NULL;
+}
+
+/* wil_platform API (callbacks) */
+
+static int wil_platform_bus_request(void *handle,
+ uint32_t kbps /* KBytes/Sec */)
+{
+ int rc, i;
+ struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
+ int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
+ struct msm_bus_paths *usecase;
+ uint32_t usecase_kbps;
+ uint32_t min_kbps = ~0;
+
+ /* find the lowest usecase that is bigger than requested kbps */
+ for (i = 0; i < msm->pdata->num_usecases; i++) {
+ usecase = &msm->pdata->usecase[i];
+ /* assume we have single path (vectors[0]). If we ever
+ * have multiple paths, need to define the behavior */
+ usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
+ if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
+ min_kbps = usecase_kbps;
+ vote = i;
+ }
+ }
+
+ rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote);
+ if (rc)
+ dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
+ kbps, vote, rc);
+ else
+ /* TOOD: remove */
+ dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n",
+ kbps, vote);
+
+ return rc;
+}
+
+static void wil_platform_uninit(void *handle)
+{
+ struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
+
+ dev_info(msm->dev, "wil_platform_uninit\n");
+
+ if (msm->msm_bus_handle)
+ msm_bus_scale_unregister_client(msm->msm_bus_handle);
+
+ kfree(msm->pdata);
+ kfree(msm);
+}
+
+static int wil_platform_msm_bus_register(struct wil_platform_msm *msm,
+ struct device_node *node)
+{
+ msm->pdata = wil_platform_get_pdata(msm->dev, node);
+ if (!msm->pdata) {
+ dev_err(msm->dev, "Failed getting DT info\n");
+ return -EINVAL;
+ }
+
+ msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata);
+ if (!msm->msm_bus_handle) {
+ dev_err(msm->dev, "Failed msm_bus registration\n");
+ return -EINVAL;
+ }
+
+ dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n",
+ msm->msm_bus_handle);
+
+ return 0;
+}
+
+/**
+ * wil_platform_msm_init() - wil6210 msm platform module init
+ *
+ * The function must be called before all other functions in this module.
+ * It returns a handle which is used with the rest of the API
+ *
+ */
+void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops)
+{
+ struct device_node *of_node;
+ struct wil_platform_msm *msm;
+ int rc;
+
+ of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210");
+ if (!of_node) {
+ /* this could mean non-msm platform */
+ dev_err(dev, "DT node not found\n");
+ return NULL;
+ }
+
+ msm = kzalloc(sizeof(*msm), GFP_KERNEL);
+ if (!msm)
+ return NULL;
+
+ msm->dev = dev;
+
+ /* register with msm_bus module for scaling requests */
+ rc = wil_platform_msm_bus_register(msm, of_node);
+ if (rc)
+ goto cleanup;
+
+ memset(ops, 0, sizeof(*ops));
+ ops->bus_request = wil_platform_bus_request;
+ ops->uninit = wil_platform_uninit;
+
+ return (void *)msm;
+
+cleanup:
+ kfree(msm);
+ return NULL;
+}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
new file mode 100644
index 0000000..2f2229e
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL_PLATFORM__MSM_H__
+#define __WIL_PLATFORM_MSM_H__
+
+#include "wil_platform.h"
+
+void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops);
+
+#endif /* __WIL_PLATFORM__MSM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 1d1d0af..bd781c7 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/moduleparam.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
@@ -22,6 +23,10 @@
#include "wmi.h"
#include "trace.h"
+static uint max_assoc_sta = 1;
+module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
+
/**
* WMI event receiving - theory of operations
*
@@ -152,6 +157,7 @@ int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
struct wil6210_mbox_hdr *hdr)
{
void __iomem *src = wmi_buffer(wil, ptr);
+
if (!src)
return -EINVAL;
@@ -273,6 +279,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wmi_ready_event *evt = d;
+
wil->fw_version = le32_to_cpu(evt->sw_version);
wil->n_mids = evt->numof_additional_mids;
@@ -293,7 +300,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
wil_dbg_wmi(wil, "WMI: got FW ready event\n");
set_bit(wil_status_fwready, &wil->status);
- /* reuse wmi_ready for the firmware ready indication */
+ /* let the reset sequence continue */
complete(&wil->wmi_ready);
}
@@ -346,11 +353,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
rx_mgmt_frame->bssid);
cfg80211_put_bss(wiphy, bss);
} else {
- wil_err(wil, "cfg80211_inform_bss() failed\n");
+ wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
}
} else {
cfg80211_rx_mgmt(wil->wdev, freq, signal,
- (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL);
+ (void *)rx_mgmt_frame, d_len, 0);
}
}
@@ -482,33 +489,6 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
mutex_unlock(&wil->mutex);
}
-static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
-{
- struct wmi_notify_req_done_event *evt = d;
-
- if (len < sizeof(*evt)) {
- wil_err(wil, "Short NOTIFY event\n");
- return;
- }
-
- wil->stats.tsf = le64_to_cpu(evt->tsf);
- wil->stats.snr = le32_to_cpu(evt->snr_val);
- wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
- wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
- wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
- wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
- wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
- wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
- "BF status 0x%08x SNR 0x%08x SQI %d%%\n"
- "Tx Tpt %d goodput %d Rx goodput %d\n"
- "Sectors(rx:tx) my %d:%d peer %d:%d\n",
- wil->stats.bf_mcs, wil->stats.tsf, evt->status,
- wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),
- le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
- wil->stats.my_rx_sector, wil->stats.my_tx_sector,
- wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
-}
-
/*
* Firmware reports EAPOL frame using WME event.
* Reconstruct Ethernet frame and deliver it via normal Rx
@@ -617,27 +597,40 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
return;
}
+ mutex_lock(&wil->mutex);
+
cid = wil->vring2cid_tid[evt->ringid][0];
if (cid >= WIL6210_MAX_CID) {
wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
- return;
+ goto out;
}
sta = &wil->sta[cid];
if (sta->status == wil_sta_unused) {
wil_err(wil, "CID %d unused\n", cid);
- return;
+ goto out;
}
wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
for (i = 0; i < WIL_STA_TID_NUM; i++) {
- struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+ struct wil_tid_ampdu_rx *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+ r = sta->tid_rx[i];
sta->tid_rx[i] = NULL;
wil_tid_ampdu_rx_free(wil, r);
+
+ spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+
if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
evt->agg_wsize, 0);
}
+
+out:
+ mutex_unlock(&wil->mutex);
}
static const struct {
@@ -651,7 +644,6 @@ static const struct {
{WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
{WMI_CONNECT_EVENTID, wmi_evt_connect},
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
- {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify},
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
{WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
@@ -676,7 +668,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
unsigned n;
if (!test_bit(wil_status_reset_done, &wil->status)) {
- wil_err(wil, "Reset not completed\n");
+ wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
return;
}
@@ -731,6 +723,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
u16 id = le16_to_cpu(wmi->id);
u32 tstamp = le32_to_cpu(wmi->timestamp);
+
wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
id, wmi->mid, tstamp);
trace_wil6210_wmi_event(wmi, &wmi[1],
@@ -771,8 +764,8 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
wil->reply_id = reply_id;
wil->reply_buf = reply;
wil->reply_size = reply_size;
- remain = wait_for_completion_timeout(&wil->wmi_ready,
- msecs_to_jiffies(to_msec));
+ remain = wait_for_completion_timeout(&wil->wmi_call,
+ msecs_to_jiffies(to_msec));
if (0 == remain) {
wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
cmdid, reply_id, to_msec);
@@ -822,7 +815,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
.network_type = wmi_nettype,
.disable_sec_offload = 1,
.channel = chan - 1,
- .pcp_max_assoc_sta = WIL6210_MAX_CID,
+ .pcp_max_assoc_sta = max_assoc_sta,
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -832,6 +825,14 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
if (!wil->secure_pcp)
cmd.disable_sec = 1;
+ if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
+ (cmd.pcp_max_assoc_sta <= 0)) {
+ wil_info(wil,
+ "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
+ max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
+ cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
+ }
+
/*
* Processing time may be huge, in case of secure AP it takes about
* 3500ms for FW to start AP
@@ -968,8 +969,11 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
int rc;
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
+
if (!cmd)
return -ENOMEM;
+ if (!ie)
+ ie_len = 0;
cmd->mgmt_frm_type = type;
/* BUG: FW API define ieLen as u8. Will fix FW */
@@ -1143,6 +1147,9 @@ static void wmi_event_handle(struct wil6210_priv *wil,
struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
void *evt_data = (void *)(&wmi[1]);
u16 id = le16_to_cpu(wmi->id);
+
+ wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n",
+ id, wil->reply_id);
/* check if someone waits for this event */
if (wil->reply_id && wil->reply_id == id) {
if (wil->reply_buf) {
@@ -1153,7 +1160,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
len - sizeof(*wmi));
}
wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
- complete(&wil->wmi_ready);
+ complete(&wil->wmi_call);
return;
}
/* unsolicited event */
@@ -1199,9 +1206,11 @@ void wmi_event_worker(struct work_struct *work)
struct pending_wmi_event *evt;
struct list_head *lh;
+ wil_dbg_wmi(wil, "Start %s\n", __func__);
while ((lh = next_wmi_ev(wil)) != NULL) {
evt = list_entry(lh, struct pending_wmi_event, list);
wmi_event_handle(wil, &evt->event.hdr);
kfree(evt);
}
+ wil_dbg_wmi(wil, "Finished %s\n", __func__);
}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 17334c8..27b9743 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity .
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -179,7 +179,6 @@ enum wmi_crypto_type {
WMI_CRYPT_AES_GCMP = 0x20,
};
-
enum wmi_connect_ctrl_flag_bits {
WMI_CONNECT_ASSOC_POLICY_USER = 0x0001,
WMI_CONNECT_SEND_REASSOC = 0x0002,
@@ -219,7 +218,6 @@ struct wmi_disconnect_sta_cmd {
__le16 disconnect_reason;
} __packed;
-
/*
* WMI_SET_PMK_CMDID
*/
@@ -234,7 +232,6 @@ struct wmi_set_pmk_cmd {
u8 pmk[WMI_PMK_LEN];
} __packed;
-
/*
* WMI_SET_PASSPHRASE_CMDID
*/
@@ -273,7 +270,6 @@ struct wmi_delete_cipher_key_cmd {
u8 mac[WMI_MAC_LEN];
} __packed;
-
/*
* WMI_START_SCAN_CMDID
*
@@ -325,7 +321,6 @@ struct wmi_probed_ssid_cmd {
u8 ssid[WMI_MAX_SSID_LEN];
} __packed;
-
/*
* WMI_SET_APPIE_CMDID
* Add Application specified IE to a management frame
@@ -351,7 +346,6 @@ struct wmi_set_appie_cmd {
u8 ie_info[0];
} __packed;
-
/*
* WMI_PXMT_RANGE_CFG_CMDID
*/
@@ -380,7 +374,6 @@ struct wmi_rf_mgmt_cmd {
__le32 rf_mgmt_type;
} __packed;
-
/*
* WMI_RF_RX_TEST_CMDID
*/
@@ -426,7 +419,6 @@ struct wmi_bcon_ctrl_cmd {
u8 disable_sec;
} __packed;
-
/******* P2P ***********/
/*
@@ -797,7 +789,6 @@ struct wmi_temp_sense_cmd {
__le32 measure_marlon_r_en;
} __packed;
-
/*
* WMI Events
*/
@@ -887,7 +878,6 @@ enum wmi_event_id {
* Events data structures
*/
-
enum wmi_fw_status {
WMI_FW_STATUS_SUCCESS,
WMI_FW_STATUS_FAILURE,
@@ -980,7 +970,7 @@ struct wmi_ready_event {
* WMI_NOTIFY_REQ_DONE_EVENTID
*/
struct wmi_notify_req_done_event {
- __le32 status;
+ __le32 status; /* beamforming status, 0: fail; 1: OK; 2: retrying */
__le64 tsf;
__le32 snr_val;
__le32 tx_tpt;
@@ -1038,8 +1028,8 @@ struct wmi_disconnect_event {
__le16 protocol_reason_status; /* reason code, see 802.11 spec. */
u8 bssid[WMI_MAC_LEN]; /* set if known */
u8 disconnect_reason; /* see wmi_disconnect_reason */
- u8 assoc_resp_len; /* not in use */
- u8 assoc_info[0]; /* not in use */
+ u8 assoc_resp_len; /* not used */
+ u8 assoc_info[0]; /* not used */
} __packed;
/*
@@ -1081,7 +1071,6 @@ struct wmi_delba_event {
__le16 reason;
} __packed;
-
/*
* WMI_VRING_CFG_DONE_EVENTID
*/
@@ -1147,7 +1136,6 @@ struct wmi_data_port_open_event {
u8 reserved[3];
} __packed;
-
/*
* WMI_GET_PCP_CHANNEL_EVENTID
*/
@@ -1156,7 +1144,6 @@ struct wmi_get_pcp_channel_event {
u8 reserved[3];
} __packed;
-
/*
* WMI_PORT_ALLOCATED_EVENTID
*/
@@ -1260,7 +1247,6 @@ struct wmi_rx_mgmt_info {
u8 channel; /* From Radio MNGR */
} __packed;
-
/*
* WMI_TX_MGMT_PACKET_EVENTID
*/
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 4cfb4d99..7afc9c5 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -66,18 +66,18 @@ static void atmel_release(struct pcmcia_device *link);
static void atmel_detach(struct pcmcia_device *p_dev);
-typedef struct local_info_t {
+struct local_info {
struct net_device *eth_dev;
-} local_info_t;
+};
static int atmel_probe(struct pcmcia_device *p_dev)
{
- local_info_t *local;
+ struct local_info *local;
dev_dbg(&p_dev->dev, "atmel_attach()\n");
/* Allocate space for private device-specific data */
- local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(*local), GFP_KERNEL);
if (!local)
return -ENOMEM;
@@ -117,7 +117,7 @@ static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data)
static int atmel_config(struct pcmcia_device *link)
{
- local_info_t *dev;
+ struct local_info *dev;
int ret;
const struct pcmcia_device_id *did;
@@ -141,14 +141,14 @@ static int atmel_config(struct pcmcia_device *link)
if (ret)
goto failed;
- ((local_info_t*)link->priv)->eth_dev =
+ ((struct local_info *)link->priv)->eth_dev =
init_atmel_card(link->irq,
link->resource[0]->start,
did ? did->driver_info : ATMEL_FW_TYPE_NONE,
&link->dev,
card_present,
link);
- if (!((local_info_t*)link->priv)->eth_dev)
+ if (!((struct local_info *)link->priv)->eth_dev)
goto failed;
@@ -161,20 +161,20 @@ static int atmel_config(struct pcmcia_device *link)
static void atmel_release(struct pcmcia_device *link)
{
- struct net_device *dev = ((local_info_t*)link->priv)->eth_dev;
+ struct net_device *dev = ((struct local_info *)link->priv)->eth_dev;
dev_dbg(&link->dev, "atmel_release\n");
if (dev)
stop_atmel_card(dev);
- ((local_info_t*)link->priv)->eth_dev = NULL;
+ ((struct local_info *)link->priv)->eth_dev = NULL;
pcmcia_disable_device(link);
}
static int atmel_suspend(struct pcmcia_device *link)
{
- local_info_t *local = link->priv;
+ struct local_info *local = link->priv;
netif_device_detach(local->eth_dev);
@@ -183,7 +183,7 @@ static int atmel_suspend(struct pcmcia_device *link)
static int atmel_resume(struct pcmcia_device *link)
{
- local_info_t *local = link->priv;
+ struct local_info *local = link->priv;
atmel_open(local->eth_dev);
netif_device_attach(local->eth_dev);
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 6e00b88..9f7965a 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -18,6 +18,7 @@ b43-y += xmit.o
b43-y += dma.o
b43-y += pio.o
b43-y += rfkill.o
+b43-y += ppr.o
b43-$(CONFIG_B43_LEDS) += leds.o
b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
b43-$(CONFIG_B43_SDIO) += sdio.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 4113b69..95a9433 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -457,6 +457,7 @@ enum {
#define B43_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */
#define B43_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */
#define B43_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */
+#define B43_MACCTL_PHY_LOCK 0x00200000
#define B43_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
#define B43_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
#define B43_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
@@ -791,6 +792,13 @@ struct b43_firmware {
bool pcm_request_failed;
};
+enum b43_band {
+ B43_BAND_2G = 0,
+ B43_BAND_5G_LO = 1,
+ B43_BAND_5G_MI = 2,
+ B43_BAND_5G_HI = 3,
+};
+
/* Device (802.11 core) initialization status. */
enum {
B43_STAT_UNINIT = 0, /* Uninitialized. */
@@ -1012,6 +1020,16 @@ static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
dev->dev->write16(dev->dev, offset, value);
}
+/* To optimize this check for flush_writes on BCM47XX_BCMA only. */
+static inline void b43_write16f(struct b43_wldev *dev, u16 offset, u16 value)
+{
+ b43_write16(dev, offset, value);
+#if defined(CONFIG_BCM47XX_BCMA)
+ if (dev->dev->flush_writes)
+ b43_read16(dev, offset);
+#endif
+}
+
static inline void b43_maskset16(struct b43_wldev *dev, u16 offset, u16 mask,
u16 set)
{
diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c
index 565fdbd..17d16a3 100644
--- a/drivers/net/wireless/b43/bus.c
+++ b/drivers/net/wireless/b43/bus.c
@@ -22,6 +22,10 @@
*/
+#ifdef CONFIG_BCM47XX_BCMA
+#include <asm/mach-bcm47xx/bcm47xx.h>
+#endif
+
#include "b43.h"
#include "bus.h"
@@ -102,6 +106,12 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core)
dev->write32 = b43_bus_bcma_write32;
dev->block_read = b43_bus_bcma_block_read;
dev->block_write = b43_bus_bcma_block_write;
+#ifdef CONFIG_BCM47XX_BCMA
+ if (b43_bus_host_is_pci(dev) &&
+ bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA &&
+ bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4716)
+ dev->flush_writes = true;
+#endif
dev->dev = &core->dev;
dev->dma_dev = core->dma_dev;
diff --git a/drivers/net/wireless/b43/bus.h b/drivers/net/wireless/b43/bus.h
index f3205c6..256c2c1 100644
--- a/drivers/net/wireless/b43/bus.h
+++ b/drivers/net/wireless/b43/bus.h
@@ -33,6 +33,7 @@ struct b43_bus_dev {
size_t count, u16 offset, u8 reg_width);
void (*block_write)(struct b43_bus_dev *dev, const void *buffer,
size_t count, u16 offset, u8 reg_width);
+ bool flush_writes;
struct device *dev;
struct device *dma_dev;
@@ -60,7 +61,21 @@ static inline bool b43_bus_host_is_pcmcia(struct b43_bus_dev *dev)
#else
return false;
#endif
+};
+
+static inline bool b43_bus_host_is_pci(struct b43_bus_dev *dev)
+{
+#ifdef CONFIG_B43_BCMA
+ if (dev->bus_type == B43_BUS_BCMA)
+ return (dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI);
+#endif
+#ifdef CONFIG_B43_SSB
+ if (dev->bus_type == B43_BUS_SSB)
+ return (dev->sdev->bus->bustype == SSB_BUSTYPE_PCI);
+#endif
+ return false;
}
+
static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev)
{
#ifdef CONFIG_B43_SSB
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 2af1ac3..165dbc3 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2985,7 +2985,22 @@ void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode)
{
u16 chip_id = dev->dev->chip_id;
- if (chip_id == BCMA_CHIP_ID_BCM43131 ||
+ if (chip_id == BCMA_CHIP_ID_BCM4331) {
+ switch (spurmode) {
+ case 2: /* 168 Mhz: 2^26/168 = 0x61862 */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x1862);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+ break;
+ case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x3e70);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+ break;
+ default: /* 160 Mhz: 2^26/160 = 0x66666 */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x6666);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+ break;
+ }
+ } else if (chip_id == BCMA_CHIP_ID_BCM43131 ||
chip_id == BCMA_CHIP_ID_BCM43217 ||
chip_id == BCMA_CHIP_ID_BCM43222 ||
chip_id == BCMA_CHIP_ID_BCM43224 ||
@@ -4466,10 +4481,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
if (core_rev == 40 || core_rev == 42) {
radio_manuf = 0x17F;
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 0);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 0);
radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA);
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 1);
radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA);
radio_ver = 0; /* Is there version somewhere? */
@@ -4477,7 +4492,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
u16 radio24[3];
for (tmp = 0; tmp < 3; tmp++) {
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, tmp);
radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
}
@@ -4494,13 +4509,12 @@ static int b43_phy_versioning(struct b43_wldev *dev)
else
tmp = 0x5205017F;
} else {
- b43_write16(dev, B43_MMIO_RADIO_CONTROL,
- B43_RADIOCTL_ID);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+ B43_RADIOCTL_ID);
tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
- b43_write16(dev, B43_MMIO_RADIO_CONTROL,
- B43_RADIOCTL_ID);
- tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH)
- << 16;
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+ B43_RADIOCTL_ID);
+ tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
}
radio_manuf = (tmp & 0x00000FFF);
radio_id = (tmp & 0x0FFFF000) >> 12;
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c
index 25e4043..99c036f 100644
--- a/drivers/net/wireless/b43/phy_a.c
+++ b/drivers/net/wireless/b43/phy_a.c
@@ -444,14 +444,14 @@ static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset)
static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg)
{
reg = adjust_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
reg = adjust_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 3cbef21..1dfc682 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -222,12 +222,18 @@ static inline void assert_mac_suspended(struct b43_wldev *dev)
u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
{
assert_mac_suspended(dev);
+ dev->phy.writes_counter = 0;
return dev->phy.ops->radio_read(dev, reg);
}
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
assert_mac_suspended(dev);
+ if (b43_bus_host_is_pci(dev->dev) &&
+ ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
+ b43_read32(dev, B43_MMIO_MACCTL);
+ dev->phy.writes_counter = 1;
+ }
dev->phy.ops->radio_write(dev, reg, value);
}
@@ -268,17 +274,28 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{
assert_mac_suspended(dev);
dev->phy.writes_counter = 0;
- return dev->phy.ops->phy_read(dev, reg);
+
+ if (dev->phy.ops->phy_read)
+ return dev->phy.ops->phy_read(dev, reg);
+
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_PHY_DATA);
}
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
{
assert_mac_suspended(dev);
- dev->phy.ops->phy_write(dev, reg, value);
- if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) {
+ if (b43_bus_host_is_pci(dev->dev) &&
+ ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
b43_read16(dev, B43_MMIO_PHY_VER);
- dev->phy.writes_counter = 0;
+ dev->phy.writes_counter = 1;
}
+
+ if (dev->phy.ops->phy_write)
+ return dev->phy.ops->phy_write(dev, reg, value);
+
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 8f5c14b..727ce6e 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -2555,13 +2555,13 @@ static void b43_gphy_op_exit(struct b43_wldev *dev)
static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
@@ -2572,7 +2572,7 @@ static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg)
/* G-PHY needs 0x80 for read access. */
reg |= 0x80;
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
@@ -2581,7 +2581,7 @@ static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c
index f2974c6..a379602 100644
--- a/drivers/net/wireless/b43/phy_ht.c
+++ b/drivers/net/wireless/b43/phy_ht.c
@@ -81,80 +81,104 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
udelay(50);
/* Calibration */
- b43_radio_mask(dev, 0x2b, ~0x1);
- b43_radio_mask(dev, 0x2e, ~0x4);
- b43_radio_set(dev, 0x2e, 0x4);
- b43_radio_set(dev, 0x2b, 0x1);
+ b43_radio_mask(dev, R2059_RFPLL_MISC_EN, ~0x1);
+ b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x4);
+ b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x4);
+ b43_radio_set(dev, R2059_RFPLL_MISC_EN, 0x1);
udelay(300);
}
-static void b43_radio_2059_init(struct b43_wldev *dev)
+/* Calibrate resistors in LPF of PLL? */
+static void b43_radio_2059_rcal(struct b43_wldev *dev)
+{
+ /* Enable */
+ b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x1);
+ usleep_range(10, 20);
+
+ b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
+ b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
+
+ /* Start */
+ b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x2);
+ usleep_range(100, 200);
+
+ /* Stop */
+ b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x2);
+
+ if (!b43_radio_wait_value(dev, R2059_C3 | R2059_RCAL_STATUS, 1, 1, 100,
+ 1000000))
+ b43err(dev->wl, "Radio 0x2059 rcal timeout\n");
+
+ /* Disable */
+ b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x1);
+
+ b43_radio_set(dev, 0xa, 0x60);
+}
+
+/* Calibrate the internal RC oscillator? */
+static void b43_radio_2057_rccal(struct b43_wldev *dev)
{
- const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 };
const u16 radio_values[3][2] = {
{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
};
- u16 i, j;
+ int i;
- b43_radio_write(dev, R2059_ALL | 0x51, 0x0070);
- b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003);
+ for (i = 0; i < 3; i++) {
+ b43_radio_write(dev, R2059_RCCAL_MASTER, radio_values[i][0]);
+ b43_radio_write(dev, R2059_RCCAL_X1, 0x6E);
+ b43_radio_write(dev, R2059_RCCAL_TRC0, radio_values[i][1]);
- for (i = 0; i < ARRAY_SIZE(routing); i++)
- b43_radio_set(dev, routing[i] | 0x146, 0x3);
+ /* Start */
+ b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x55);
- b43_radio_set(dev, 0x2e, 0x0078);
- b43_radio_set(dev, 0xc0, 0x0080);
- msleep(2);
- b43_radio_mask(dev, 0x2e, ~0x0078);
- b43_radio_mask(dev, 0xc0, ~0x0080);
+ /* Wait */
+ if (!b43_radio_wait_value(dev, R2059_RCCAL_DONE_OSCCAP, 2, 2,
+ 500, 5000000))
+ b43err(dev->wl, "Radio 0x2059 rccal timeout\n");
- if (1) { /* FIXME */
- b43_radio_set(dev, R2059_C3 | 0x4, 0x1);
- udelay(10);
- b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
- b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
+ /* Stop */
+ b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x15);
+ }
- b43_radio_set(dev, R2059_C3 | 0x4, 0x2);
- udelay(100);
- b43_radio_mask(dev, R2059_C3 | 0x4, ~0x2);
+ b43_radio_mask(dev, R2059_RCCAL_MASTER, ~0x1);
+}
- for (i = 0; i < 10000; i++) {
- if (b43_radio_read(dev, R2059_C3 | 0x145) & 1) {
- i = 0;
- break;
- }
- udelay(100);
- }
- if (i)
- b43err(dev->wl, "radio 0x945 timeout\n");
-
- b43_radio_mask(dev, R2059_C3 | 0x4, ~0x1);
- b43_radio_set(dev, 0xa, 0x60);
-
- for (i = 0; i < 3; i++) {
- b43_radio_write(dev, 0x17F, radio_values[i][0]);
- b43_radio_write(dev, 0x13D, 0x6E);
- b43_radio_write(dev, 0x13E, radio_values[i][1]);
- b43_radio_write(dev, 0x13C, 0x55);
-
- for (j = 0; j < 10000; j++) {
- if (b43_radio_read(dev, 0x140) & 2) {
- j = 0;
- break;
- }
- udelay(500);
- }
- if (j)
- b43err(dev->wl, "radio 0x140 timeout\n");
+static void b43_radio_2059_init_pre(struct b43_wldev *dev)
+{
+ b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
+ b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_FORCE);
+ b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_FORCE);
+ b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
+}
- b43_radio_write(dev, 0x13C, 0x15);
- }
+static void b43_radio_2059_init(struct b43_wldev *dev)
+{
+ const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 };
+ int i;
+
+ /* Prepare (reset?) radio */
+ b43_radio_2059_init_pre(dev);
- b43_radio_mask(dev, 0x17F, ~0x1);
+ r2059_upload_inittabs(dev);
+
+ for (i = 0; i < ARRAY_SIZE(routing); i++)
+ b43_radio_set(dev, routing[i] | 0x146, 0x3);
+
+ /* Post init starts below */
+
+ b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x0078);
+ b43_radio_set(dev, R2059_XTAL_CONFIG2, 0x0080);
+ msleep(2);
+ b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x0078);
+ b43_radio_mask(dev, R2059_XTAL_CONFIG2, ~0x0080);
+
+ if (1) { /* FIXME */
+ b43_radio_2059_rcal(dev);
+ b43_radio_2057_rccal(dev);
}
- b43_radio_mask(dev, 0x11, ~0x0008);
+ b43_radio_mask(dev, R2059_RFPLL_MASTER, ~0x0008);
}
/**************************************************
@@ -704,7 +728,6 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
{
struct bcma_device *core = dev->dev->bdev;
int spuravoid = 0;
- u16 tmp;
/* Check for 13 and 14 is just a guess, we don't have enough logs. */
if (new_channel->hw_value == 13 || new_channel->hw_value == 14)
@@ -717,20 +740,7 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
B43_BCMA_CLKCTLST_80211_PLL_ST |
B43_BCMA_CLKCTLST_PHY_PLL_ST, false);
- /* Values has been taken from wlc_bmac_switch_macfreq comments */
- switch (spuravoid) {
- case 2: /* 126MHz */
- tmp = 0x2082;
- break;
- case 1: /* 123MHz */
- tmp = 0x5341;
- break;
- default: /* 120MHz */
- tmp = 0x8889;
- }
-
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, tmp);
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+ b43_mac_switch_freq(dev, spuravoid);
/* TODO: reset PLL */
@@ -1002,19 +1012,10 @@ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev,
if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
b43err(dev->wl, "MAC not suspended\n");
- /* In the following PHY ops we copy wl's dummy behaviour.
- * TODO: Find out if reads (currently hidden in masks/masksets) are
- * needed and replace following ops with just writes or w&r.
- * Note: B43_PHY_HT_RF_CTL1 register is tricky, wrong operation can
- * cause delayed (!) machine lock up. */
if (blocked) {
- b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
+ b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD,
+ ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
} else {
- b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
- b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x1);
- b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
- b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x2);
-
if (dev->phy.radio_ver == 0x2059)
b43_radio_2059_init(dev);
else
@@ -1071,22 +1072,10 @@ static unsigned int b43_phy_ht_op_get_default_chan(struct b43_wldev *dev)
* R/W ops.
**************************************************/
-static u16 b43_phy_ht_op_read(struct b43_wldev *dev, u16 reg)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_phy_ht_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA,
(b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
}
@@ -1096,14 +1085,14 @@ static u16 b43_phy_ht_op_radio_read(struct b43_wldev *dev, u16 reg)
/* HT-PHY needs 0x200 for read access */
reg |= 0x200;
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO24_DATA);
}
static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg,
u16 value)
{
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
}
@@ -1126,8 +1115,6 @@ const struct b43_phy_operations b43_phyops_ht = {
.free = b43_phy_ht_op_free,
.prepare_structs = b43_phy_ht_op_prepare_structs,
.init = b43_phy_ht_op_init,
- .phy_read = b43_phy_ht_op_read,
- .phy_write = b43_phy_ht_op_write,
.phy_maskset = b43_phy_ht_op_maskset,
.radio_read = b43_phy_ht_op_radio_read,
.radio_write = b43_phy_ht_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h
index 6cae370..67b208e 100644
--- a/drivers/net/wireless/b43/phy_ht.h
+++ b/drivers/net/wireless/b43/phy_ht.h
@@ -81,7 +81,9 @@
#define B43_PHY_HT_RF_SEQ_STATUS B43_PHY_EXTG(0x004)
/* Values for the status are the same as for the trigger */
-#define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010)
+#define B43_PHY_HT_RF_CTL_CMD 0x810
+#define B43_PHY_HT_RF_CTL_CMD_FORCE 0x0001
+#define B43_PHY_HT_RF_CTL_CMD_CHIP0_PU 0x0002
#define B43_PHY_HT_RF_CTL_INT_C1 B43_PHY_EXTG(0x04c)
#define B43_PHY_HT_RF_CTL_INT_C2 B43_PHY_EXTG(0x06c)
diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c
index e76bbdf..97461cc 100644
--- a/drivers/net/wireless/b43/phy_lcn.c
+++ b/drivers/net/wireless/b43/phy_lcn.c
@@ -810,22 +810,10 @@ static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
* R/W ops.
**************************************************/
-static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA,
(b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
}
@@ -835,14 +823,14 @@ static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
/* LCN-PHY needs 0x200 for read access */
reg |= 0x200;
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO24_DATA);
}
static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
u16 value)
{
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
}
@@ -855,8 +843,6 @@ const struct b43_phy_operations b43_phyops_lcn = {
.free = b43_phy_lcn_op_free,
.prepare_structs = b43_phy_lcn_op_prepare_structs,
.init = b43_phy_lcn_op_init,
- .phy_read = b43_phy_lcn_op_read,
- .phy_write = b43_phy_lcn_op_write,
.phy_maskset = b43_phy_lcn_op_maskset,
.radio_read = b43_phy_lcn_op_radio_read,
.radio_write = b43_phy_lcn_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 92190da..058a9f2 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -1985,22 +1985,10 @@ static void lpphy_calibration(struct b43_wldev *dev)
b43_mac_enable(dev);
}
-static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA,
(b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
}
@@ -2016,7 +2004,7 @@ static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
} else
reg |= 0x200;
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
@@ -2025,7 +2013,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
@@ -2713,8 +2701,6 @@ const struct b43_phy_operations b43_phyops_lp = {
.free = b43_lpphy_op_free,
.prepare_structs = b43_lpphy_op_prepare_structs,
.init = b43_lpphy_op_init,
- .phy_read = b43_lpphy_op_read,
- .phy_write = b43_lpphy_op_write,
.phy_maskset = b43_lpphy_op_maskset,
.radio_read = b43_lpphy_op_radio_read,
.radio_write = b43_lpphy_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index e2a3f0d..cf625d8 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -34,6 +34,7 @@
#include "radio_2056.h"
#include "radio_2057.h"
#include "main.h"
+#include "ppr.h"
struct nphy_txgains {
u16 tx_lpf[2];
@@ -3606,16 +3607,6 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
* Tx and Rx
**************************************************/
-static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
-{//TODO
-}
-
-static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
- bool ignore_tssi)
-{//TODO
- return B43_TXPWR_RES_DONE;
-}
-
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
{
@@ -4069,6 +4060,7 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
s16 a1[2], b0[2], b1[2];
u8 idle[2];
+ u8 ppr_max;
s8 target[2];
s32 num, den, pwr;
u32 regval[64];
@@ -4147,7 +4139,12 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
b1[0] = b1[1] = -1393;
}
}
- /* target[0] = target[1] = nphy->tx_power_max; */
+
+ ppr_max = b43_ppr_get_max(dev, &nphy->tx_pwr_max_ppr);
+ if (ppr_max) {
+ target[0] = ppr_max;
+ target[1] = ppr_max;
+ }
if (dev->phy.rev >= 3) {
if (sprom->fem.ghz2.tssipos)
@@ -4235,8 +4232,9 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
const u32 *table = NULL;
u32 rfpwr_offset;
- u8 pga_gain;
+ u8 pga_gain, pad_gain;
int i;
+ const s16 *uninitialized_var(rf_pwr_offset_table);
table = b43_nphy_get_tx_gain_table(dev);
if (!table)
@@ -4252,13 +4250,27 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
nphy->gmval = (table[0] >> 16) & 0x7000;
#endif
+ if (phy->rev >= 19) {
+ return;
+ } else if (phy->rev >= 7) {
+ rf_pwr_offset_table = b43_ntab_get_rf_pwr_offset_table(dev);
+ if (!rf_pwr_offset_table)
+ return;
+ /* TODO: Enable this once we have gains configured */
+ return;
+ }
+
for (i = 0; i < 128; i++) {
if (phy->rev >= 19) {
/* TODO */
return;
} else if (phy->rev >= 7) {
- /* TODO */
- return;
+ pga_gain = (table[i] >> 24) & 0xf;
+ pad_gain = (table[i] >> 19) & 0x1f;
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ rfpwr_offset = rf_pwr_offset_table[pad_gain];
+ else
+ rfpwr_offset = rf_pwr_offset_table[pga_gain];
} else {
pga_gain = (table[i] >> 24) & 0xF;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -5874,6 +5886,69 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
b43_mac_enable(dev);
}
+static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
+ bool ignore_tssi)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = dev->phy.n;
+ struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
+ struct b43_ppr *ppr = &nphy->tx_pwr_max_ppr;
+ u8 max; /* qdBm */
+ bool tx_pwr_state;
+
+ if (nphy->tx_pwr_last_recalc_freq == channel->center_freq &&
+ nphy->tx_pwr_last_recalc_limit == phy->desired_txpower)
+ return B43_TXPWR_RES_DONE;
+
+ /* Make sure we have a clean PPR */
+ b43_ppr_clear(dev, ppr);
+
+ /* HW limitations */
+ b43_ppr_load_max_from_sprom(dev, ppr, B43_BAND_2G);
+
+ /* Regulatory & user settings */
+ max = INT_TO_Q52(phy->chandef->chan->max_power);
+ if (phy->desired_txpower)
+ max = min_t(u8, max, INT_TO_Q52(phy->desired_txpower));
+ b43_ppr_apply_max(dev, ppr, max);
+ if (b43_debug(dev, B43_DBG_XMITPOWER))
+ b43dbg(dev->wl, "Calculated TX power: " Q52_FMT "\n",
+ Q52_ARG(b43_ppr_get_max(dev, ppr)));
+
+ /* TODO: Enable this once we get gains working */
+#if 0
+ /* Some extra gains */
+ hw_gain = 6; /* N-PHY specific */
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ hw_gain += sprom->antenna_gain.a0;
+ else
+ hw_gain += sprom->antenna_gain.a1;
+ b43_ppr_add(dev, ppr, -hw_gain);
+#endif
+
+ /* Make sure we didn't go too low */
+ b43_ppr_apply_min(dev, ppr, INT_TO_Q52(8));
+
+ /* Apply */
+ tx_pwr_state = nphy->txpwrctrl;
+ b43_mac_suspend(dev);
+ b43_nphy_tx_power_ctl_setup(dev);
+ if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12) {
+ b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_PHY_LOCK);
+ b43_read32(dev, B43_MMIO_MACCTL);
+ udelay(1);
+ }
+ b43_nphy_tx_power_ctrl(dev, nphy->txpwrctrl);
+ if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12)
+ b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PHY_LOCK, 0);
+ b43_mac_enable(dev);
+
+ nphy->tx_pwr_last_recalc_freq = channel->center_freq;
+ nphy->tx_pwr_last_recalc_limit = phy->desired_txpower;
+
+ return B43_TXPWR_RES_DONE;
+}
+
/**************************************************
* N-PHY init
**************************************************/
@@ -6407,6 +6482,7 @@ static int b43_nphy_op_allocate(struct b43_wldev *dev)
nphy = kzalloc(sizeof(*nphy), GFP_KERNEL);
if (!nphy)
return -ENOMEM;
+
dev->phy.n = nphy;
return 0;
@@ -6497,26 +6573,13 @@ static inline void check_phyreg(struct b43_wldev *dev, u16 offset)
#endif /* B43_DEBUG */
}
-static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
-{
- check_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
- check_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
check_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set);
+ dev->phy.writes_counter = 1;
}
static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
@@ -6529,7 +6592,7 @@ static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
else
reg |= 0x100;
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
@@ -6538,7 +6601,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
/* Register 1 is a 32-bit register. */
B43_WARN_ON(dev->phy.rev < 7 && reg == 1);
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
@@ -6652,8 +6715,6 @@ const struct b43_phy_operations b43_phyops_n = {
.free = b43_nphy_op_free,
.prepare_structs = b43_nphy_op_prepare_structs,
.init = b43_nphy_op_init,
- .phy_read = b43_nphy_op_read,
- .phy_write = b43_nphy_op_write,
.phy_maskset = b43_nphy_op_maskset,
.radio_read = b43_nphy_op_radio_read,
.radio_write = b43_nphy_op_radio_write,
@@ -6662,5 +6723,4 @@ const struct b43_phy_operations b43_phyops_n = {
.switch_channel = b43_nphy_op_switch_channel,
.get_default_chan = b43_nphy_op_get_default_chan,
.recalc_txpower = b43_nphy_op_recalc_txpower,
- .adjust_txpower = b43_nphy_op_adjust_txpower,
};
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index 30bec81..a6da2c3 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -2,6 +2,7 @@
#define B43_NPHY_H_
#include "phy_common.h"
+#include "ppr.h"
/* N-PHY registers. */
@@ -967,6 +968,9 @@ struct b43_phy_n {
struct b43_phy_n_txpwrindex txpwrindex[2];
struct b43_phy_n_pwr_ctl_info pwr_ctl_info[2];
struct b43_chanspec txiqlocal_chanspec;
+ struct b43_ppr tx_pwr_max_ppr;
+ u16 tx_pwr_last_recalc_freq;
+ int tx_pwr_last_recalc_limit;
u8 txrx_chain;
u16 tx_rx_cal_phy_saveregs[11];
diff --git a/drivers/net/wireless/b43/ppr.c b/drivers/net/wireless/b43/ppr.c
new file mode 100644
index 0000000..9a77027
--- /dev/null
+++ b/drivers/net/wireless/b43/ppr.c
@@ -0,0 +1,199 @@
+/*
+ * Broadcom B43 wireless driver
+ * PPR (Power Per Rate) management
+ *
+ * Copyright (c) 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "ppr.h"
+#include "b43.h"
+
+#define ppr_for_each_entry(ppr, i, entry) \
+ for (i = 0, entry = &(ppr)->__all_rates[i]; \
+ i < B43_PPR_RATES_NUM; \
+ i++, entry++)
+
+void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr)
+{
+ memset(ppr, 0, sizeof(*ppr));
+
+ /* Compile-time PPR check */
+ BUILD_BUG_ON(sizeof(struct b43_ppr) != B43_PPR_RATES_NUM * sizeof(u8));
+}
+
+void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff)
+{
+ int i;
+ u8 *rate;
+
+ ppr_for_each_entry(ppr, i, rate) {
+ *rate = clamp_val(*rate + diff, 0, 127);
+ }
+}
+
+void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max)
+{
+ int i;
+ u8 *rate;
+
+ ppr_for_each_entry(ppr, i, rate) {
+ *rate = min(*rate, max);
+ }
+}
+
+void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min)
+{
+ int i;
+ u8 *rate;
+
+ ppr_for_each_entry(ppr, i, rate) {
+ *rate = max(*rate, min);
+ }
+}
+
+u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr)
+{
+ u8 res = 0;
+ int i;
+ u8 *rate;
+
+ ppr_for_each_entry(ppr, i, rate) {
+ res = max(*rate, res);
+ }
+
+ return res;
+}
+
+bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
+ enum b43_band band)
+{
+ struct b43_ppr_rates *rates = &ppr->rates;
+ struct ssb_sprom *sprom = dev->dev->bus_sprom;
+ struct b43_phy *phy = &dev->phy;
+ u8 maxpwr, off;
+ u32 sprom_ofdm_po;
+ u16 *sprom_mcs_po;
+ u8 extra_cdd_po, extra_stbc_po;
+ int i;
+
+ switch (band) {
+ case B43_BAND_2G:
+ maxpwr = min(sprom->core_pwr_info[0].maxpwr_2g,
+ sprom->core_pwr_info[1].maxpwr_2g);
+ sprom_ofdm_po = sprom->ofdm2gpo;
+ sprom_mcs_po = sprom->mcs2gpo;
+ extra_cdd_po = (sprom->cddpo >> 0) & 0xf;
+ extra_stbc_po = (sprom->stbcpo >> 0) & 0xf;
+ break;
+ case B43_BAND_5G_LO:
+ maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gl,
+ sprom->core_pwr_info[1].maxpwr_5gl);
+ sprom_ofdm_po = sprom->ofdm5glpo;
+ sprom_mcs_po = sprom->mcs5glpo;
+ extra_cdd_po = (sprom->cddpo >> 8) & 0xf;
+ extra_stbc_po = (sprom->stbcpo >> 8) & 0xf;
+ break;
+ case B43_BAND_5G_MI:
+ maxpwr = min(sprom->core_pwr_info[0].maxpwr_5g,
+ sprom->core_pwr_info[1].maxpwr_5g);
+ sprom_ofdm_po = sprom->ofdm5gpo;
+ sprom_mcs_po = sprom->mcs5gpo;
+ extra_cdd_po = (sprom->cddpo >> 4) & 0xf;
+ extra_stbc_po = (sprom->stbcpo >> 4) & 0xf;
+ break;
+ case B43_BAND_5G_HI:
+ maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gh,
+ sprom->core_pwr_info[1].maxpwr_5gh);
+ sprom_ofdm_po = sprom->ofdm5ghpo;
+ sprom_mcs_po = sprom->mcs5ghpo;
+ extra_cdd_po = (sprom->cddpo >> 12) & 0xf;
+ extra_stbc_po = (sprom->stbcpo >> 12) & 0xf;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return false;
+ }
+
+ if (band == B43_BAND_2G) {
+ for (i = 0; i < 4; i++) {
+ off = ((sprom->cck2gpo >> (i * 4)) & 0xf) * 2;
+ rates->cck[i] = maxpwr - off;
+ }
+ }
+
+ /* OFDM */
+ for (i = 0; i < 8; i++) {
+ off = ((sprom_ofdm_po >> (i * 4)) & 0xf) * 2;
+ rates->ofdm[i] = maxpwr - off;
+ }
+
+ /* MCS 20 SISO */
+ rates->mcs_20[0] = rates->ofdm[0];
+ rates->mcs_20[1] = rates->ofdm[2];
+ rates->mcs_20[2] = rates->ofdm[3];
+ rates->mcs_20[3] = rates->ofdm[4];
+ rates->mcs_20[4] = rates->ofdm[5];
+ rates->mcs_20[5] = rates->ofdm[6];
+ rates->mcs_20[6] = rates->ofdm[7];
+ rates->mcs_20[7] = rates->ofdm[7];
+
+ /* MCS 20 CDD */
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_cdd[i] = maxpwr - off;
+ if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+ rates->mcs_20_cdd[i] -= extra_cdd_po;
+ }
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_cdd[4 + i] = maxpwr - off;
+ if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+ rates->mcs_20_cdd[4 + i] -= extra_cdd_po;
+ }
+
+ /* OFDM 20 CDD */
+ rates->ofdm_20_cdd[0] = rates->mcs_20_cdd[0];
+ rates->ofdm_20_cdd[1] = rates->mcs_20_cdd[0];
+ rates->ofdm_20_cdd[2] = rates->mcs_20_cdd[1];
+ rates->ofdm_20_cdd[3] = rates->mcs_20_cdd[2];
+ rates->ofdm_20_cdd[4] = rates->mcs_20_cdd[3];
+ rates->ofdm_20_cdd[5] = rates->mcs_20_cdd[4];
+ rates->ofdm_20_cdd[6] = rates->mcs_20_cdd[5];
+ rates->ofdm_20_cdd[7] = rates->mcs_20_cdd[6];
+
+ /* MCS 20 STBC */
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_stbc[i] = maxpwr - off;
+ if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+ rates->mcs_20_stbc[i] -= extra_stbc_po;
+ }
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_stbc[4 + i] = maxpwr - off;
+ if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+ rates->mcs_20_stbc[4 + i] -= extra_stbc_po;
+ }
+
+ /* MCS 20 SDM */
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[2] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_sdm[i] = maxpwr - off;
+ }
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[3] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_sdm[4 + i] = maxpwr - off;
+ }
+
+ return true;
+}
diff --git a/drivers/net/wireless/b43/ppr.h b/drivers/net/wireless/b43/ppr.h
new file mode 100644
index 0000000..24d7447
--- /dev/null
+++ b/drivers/net/wireless/b43/ppr.h
@@ -0,0 +1,45 @@
+#ifndef LINUX_B43_PPR_H_
+#define LINUX_B43_PPR_H_
+
+#include <linux/types.h>
+
+#define B43_PPR_CCK_RATES_NUM 4
+#define B43_PPR_OFDM_RATES_NUM 8
+#define B43_PPR_MCS_RATES_NUM 8
+
+#define B43_PPR_RATES_NUM (B43_PPR_CCK_RATES_NUM + \
+ B43_PPR_OFDM_RATES_NUM * 2 + \
+ B43_PPR_MCS_RATES_NUM * 4)
+
+struct b43_ppr_rates {
+ u8 cck[B43_PPR_CCK_RATES_NUM];
+ u8 ofdm[B43_PPR_OFDM_RATES_NUM];
+ u8 ofdm_20_cdd[B43_PPR_OFDM_RATES_NUM];
+ u8 mcs_20[B43_PPR_MCS_RATES_NUM]; /* SISO */
+ u8 mcs_20_cdd[B43_PPR_MCS_RATES_NUM];
+ u8 mcs_20_stbc[B43_PPR_MCS_RATES_NUM];
+ u8 mcs_20_sdm[B43_PPR_MCS_RATES_NUM];
+};
+
+struct b43_ppr {
+ /* All powers are in qdbm (Q5.2) */
+ union {
+ u8 __all_rates[B43_PPR_RATES_NUM];
+ struct b43_ppr_rates rates;
+ };
+};
+
+struct b43_wldev;
+enum b43_band;
+
+void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr);
+
+void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff);
+void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max);
+void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min);
+u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr);
+
+bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
+ enum b43_band band);
+
+#endif /* LINUX_B43_PPR_H_ */
diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c
index 38e31d8..b2a53b2 100644
--- a/drivers/net/wireless/b43/radio_2059.c
+++ b/drivers/net/wireless/b43/radio_2059.c
@@ -25,6 +25,13 @@
#include "b43.h"
#include "radio_2059.h"
+/* Extracted from MMIO dump of 6.30.223.141 */
+static u16 r2059_phy_rev1_init[][2] = {
+ { 0x051, 0x70 }, { 0x05a, 0x03 }, { 0x079, 0x01 }, { 0x082, 0x70 },
+ { 0x083, 0x00 }, { 0x084, 0x70 }, { 0x09a, 0x7f }, { 0x0b6, 0x10 },
+ { 0x188, 0x05 },
+};
+
#define RADIOREGS(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
r20) \
@@ -139,6 +146,26 @@ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radi
},
};
+void r2059_upload_inittabs(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 *table = NULL;
+ u16 size, i;
+
+ switch (phy->rev) {
+ case 1:
+ table = r2059_phy_rev1_init[0];
+ size = ARRAY_SIZE(r2059_phy_rev1_init);
+ break;
+ default:
+ B43_WARN_ON(1);
+ return;
+ }
+
+ for (i = 0; i < size; i++, table += 2)
+ b43_radio_write(dev, R2059_ALL | table[0], table[1]);
+}
+
const struct b43_phy_ht_channeltab_e_radio2059
*b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq)
{
diff --git a/drivers/net/wireless/b43/radio_2059.h b/drivers/net/wireless/b43/radio_2059.h
index 40a82d7..9e22fb6 100644
--- a/drivers/net/wireless/b43/radio_2059.h
+++ b/drivers/net/wireless/b43/radio_2059.h
@@ -10,6 +10,18 @@
#define R2059_C3 0x800
#define R2059_ALL 0xC00
+#define R2059_RCAL_CONFIG 0x004
+#define R2059_RFPLL_MASTER 0x011
+#define R2059_RFPLL_MISC_EN 0x02b
+#define R2059_RFPLL_MISC_CAL_RESETN 0x02e
+#define R2059_XTAL_CONFIG2 0x0c0
+#define R2059_RCCAL_START_R1_Q1_P1 0x13c
+#define R2059_RCCAL_X1 0x13d
+#define R2059_RCCAL_TRC0 0x13e
+#define R2059_RCCAL_DONE_OSCCAP 0x140
+#define R2059_RCAL_STATUS 0x145
+#define R2059_RCCAL_MASTER 0x17f
+
/* Values for various registers uploaded on channel switching */
struct b43_phy_ht_channeltab_e_radio2059 {
/* The channel frequency in MHz */
@@ -40,6 +52,8 @@ struct b43_phy_ht_channeltab_e_radio2059 {
struct b43_phy_ht_channeltab_e_phy phy_regs;
};
+void r2059_upload_inittabs(struct b43_wldev *dev);
+
const struct b43_phy_ht_channeltab_e_radio2059
*b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq);
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 4b58850..25d1cbd 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -2878,6 +2878,40 @@ const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[] = {
-54, -46, -39, -31, -23, -15, -8, 0
};
+/* Extracted from MMIO dump of 6.30.223.248
+ * Entries: 0, 15, 17, 21, 24, 26, 27, 29, 30 were guessed
+ */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev9_2g[] = {
+ -133, -133, -107, -92, -81,
+ -73, -66, -61, -56, -52,
+ -48, -44, -41, -37, -34,
+ -31, -28, -25, -22, -19,
+ -17, -14, -12, -10, -9,
+ -7, -5, -4, -3, -2,
+ -1, 0,
+};
+
+/* Extracted from MMIO dump of 6.30.223.248 */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev9_5g[] = {
+ -101, -94, -86, -79, -72,
+ -65, -57, -50, -42, -35,
+ -28, -21, -16, -9, -4,
+ 0,
+};
+
+/* Extracted from MMIO dump of 6.30.223.248
+ * Entries: 0, 26, 28, 29, 30, 31 were guessed
+ */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev14_2g[] = {
+ -111, -111, -111, -84, -70,
+ -59, -52, -45, -40, -36,
+ -32, -29, -26, -23, -21,
+ -18, -16, -15, -13, -11,
+ -10, -8, -7, -6, -5,
+ -4, -4, -3, -3, -2,
+ -2, -1,
+};
+
const u16 tbl_iqcal_gainparams[2][9][8] = {
{
{ 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 },
@@ -3197,7 +3231,7 @@ static struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = {
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
0x527E, /* invalid for external LNA! */
{ 0x513F, 0x513F, 0x513F, 0x513F }, /* invalid for external LNA! */
- 0x1076, 0x0066, 0x0000, /* low is invalid (the last one) */
+ 0x007E, 0x0066, 0x0000, /* low is invalid (the last one) */
0x18, 0x18, 0x18,
0x01D0, 0x5,
},
@@ -3708,9 +3742,43 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)
}
}
+const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ switch (phy->rev) {
+ case 17:
+ if (phy->radio_rev == 14)
+ return b43_ntab_rf_pwr_offset_2057_rev14_2g;
+ break;
+ case 16:
+ if (phy->radio_rev == 9)
+ return b43_ntab_rf_pwr_offset_2057_rev9_2g;
+ break;
+ }
+
+ b43err(dev->wl,
+ "No 2GHz RF power table available for this device\n");
+ return NULL;
+ } else {
+ switch (phy->rev) {
+ case 16:
+ if (phy->radio_rev == 9)
+ return b43_ntab_rf_pwr_offset_2057_rev9_5g;
+ break;
+ }
+
+ b43err(dev->wl,
+ "No 5GHz RF power table available for this device\n");
+ return NULL;
+ }
+}
+
struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
struct b43_wldev *dev, bool ghz5, bool ext_lna)
{
+ struct b43_phy *phy = &dev->phy;
struct nphy_gain_ctl_workaround_entry *e;
u8 phy_idx;
@@ -3729,37 +3797,49 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
e = &nphy_gain_ctl_workaround[ghz5][phy_idx];
/* Some workarounds to the workarounds... */
- if (ghz5 && dev->phy.rev >= 6) {
- if (dev->phy.radio_rev == 11 &&
- !b43_is_40mhz(dev))
- e->cliplo_gain = 0x2d;
- } else if (!ghz5 && dev->phy.rev >= 5) {
- static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
- 0x106c, 0x1074, 0x107c, 0x207c};
+ if (!ghz5) {
u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
- if (ext_lna) {
+ if (tr_iso > 7)
+ tr_iso = 3;
+
+ if (phy->rev >= 6) {
+ static const int gain_data[] = { 0x106a, 0x106c, 0x1074,
+ 0x107c, 0x007e, 0x107e,
+ 0x207e, 0x307e, };
+
+ e->cliplo_gain = gain_data[tr_iso];
+ } else if (phy->rev == 5) {
+ static const int gain_data[] = { 0x0062, 0x0064, 0x006a,
+ 0x106a, 0x106c, 0x1074,
+ 0x107c, 0x207c, };
+
+ e->cliplo_gain = gain_data[tr_iso];
+ }
+
+ if (phy->rev >= 5 && ext_lna) {
e->rfseq_init[0] &= ~0x4000;
e->rfseq_init[1] &= ~0x4000;
e->rfseq_init[2] &= ~0x4000;
e->rfseq_init[3] &= ~0x4000;
e->init_gain &= ~0x4000;
}
- if (tr_iso > 7)
- tr_iso = 3;
- e->cliplo_gain = gain_data[tr_iso];
-
- } else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
- e->rfseq_init[0] &= ~0x4000;
- e->rfseq_init[1] &= ~0x4000;
- e->rfseq_init[2] &= ~0x4000;
- e->rfseq_init[3] &= ~0x4000;
- e->init_gain &= ~0x4000;
- e->rfseq_init[0] |= 0x1000;
- e->rfseq_init[1] |= 0x1000;
- e->rfseq_init[2] |= 0x1000;
- e->rfseq_init[3] |= 0x1000;
- e->init_gain |= 0x1000;
+ } else {
+ if (phy->rev >= 6) {
+ if (phy->radio_rev == 11 && !b43_is_40mhz(dev))
+ e->crsminu = 0x2d;
+ } else if (phy->rev == 4 && ext_lna) {
+ e->rfseq_init[0] &= ~0x4000;
+ e->rfseq_init[1] &= ~0x4000;
+ e->rfseq_init[2] &= ~0x4000;
+ e->rfseq_init[3] &= ~0x4000;
+ e->init_gain &= ~0x4000;
+ e->rfseq_init[0] |= 0x1000;
+ e->rfseq_init[1] |= 0x1000;
+ e->rfseq_init[2] |= 0x1000;
+ e->rfseq_init[3] |= 0x1000;
+ e->init_gain |= 0x1000;
+ }
}
return e;
diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h
index 3ce2e6f..b51f386 100644
--- a/drivers/net/wireless/b43/tables_nphy.h
+++ b/drivers/net/wireless/b43/tables_nphy.h
@@ -191,6 +191,8 @@ void b43_nphy_tables_init(struct b43_wldev *dev);
const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev);
+const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev);
+
extern const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[];
extern const u16 tbl_iqcal_gainparams[2][9][8];
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index 057b982..1d78a91 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -1431,8 +1431,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
IEEE80211_BAND_5GHZ);
wdev = &ifp->vif->wdev;
- cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0,
- GFP_ATOMIC);
+ cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0);
kfree(mgmt_frame);
return 0;
@@ -1896,8 +1895,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
IEEE80211_BAND_2GHZ :
IEEE80211_BAND_5GHZ);
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0,
- GFP_ATOMIC);
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
mgmt_frame_len, e->datalen, chanspec, freq);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 02fe706..12a60ca 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -2394,9 +2394,13 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
- bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
- 0, notify_capability, notify_interval, notify_ie,
- notify_ielen, notify_signal, GFP_KERNEL);
+ bss = cfg80211_inform_bss(wiphy, notify_channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
+ (const u8 *)bi->BSSID,
+ 0, notify_capability,
+ notify_interval, notify_ie,
+ notify_ielen, notify_signal,
+ GFP_KERNEL);
if (!bss)
return -ENOMEM;
@@ -2498,9 +2502,11 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
brcmf_dbg(CONN, "signal: %d\n", notify_signal);
- bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
- 0, notify_capability, notify_interval,
- notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+ bss = cfg80211_inform_bss(wiphy, notify_channel,
+ CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
+ notify_capability, notify_interval,
+ notify_ie, notify_ielen, notify_signal,
+ GFP_KERNEL);
if (!bss) {
err = -ENOMEM;
diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c
index 40078f5..964b64a 100644
--- a/drivers/net/wireless/cw1200/cw1200_spi.c
+++ b/drivers/net/wireless/cw1200/cw1200_spi.c
@@ -398,7 +398,7 @@ static int cw1200_spi_probe(struct spi_device *func)
return -1;
}
- self = kzalloc(sizeof(*self), GFP_KERNEL);
+ self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL);
if (!self) {
pr_err("Can't allocate SPI hwbus_priv.");
return -ENOMEM;
@@ -424,7 +424,6 @@ static int cw1200_spi_probe(struct spi_device *func)
if (status) {
cw1200_spi_irq_unsubscribe(self);
cw1200_spi_off(plat_data);
- kfree(self);
}
return status;
@@ -441,7 +440,6 @@ static int cw1200_spi_disconnect(struct spi_device *func)
cw1200_core_release(self->core);
self->core = NULL;
}
- kfree(self);
}
cw1200_spi_off(dev_get_platdata(&func->dev));
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index a42f9c3..f0c3c77 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -5552,7 +5552,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
min(network->ssid_len, priv->essid_len)))) {
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- strncpy(escaped,
+ strlcpy(escaped,
print_ssid(ssid, network->ssid,
network->ssid_len),
sizeof(escaped));
@@ -5765,7 +5765,7 @@ static int ipw_best_network(struct ipw_priv *priv,
memcmp(network->ssid, priv->essid,
min(network->ssid_len, priv->essid_len)))) {
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- strncpy(escaped,
+ strlcpy(escaped,
print_ssid(ssid, network->ssid,
network->ssid_len),
sizeof(escaped));
@@ -5782,7 +5782,7 @@ static int ipw_best_network(struct ipw_priv *priv,
* testing everything else. */
if (match->network && match->network->stats.rssi > network->stats.rssi) {
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- strncpy(escaped,
+ strlcpy(escaped,
print_ssid(ssid, network->ssid, network->ssid_len),
sizeof(escaped));
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because "
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 3dcbe2c..cf7996f 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -4633,7 +4633,7 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr,
else {
ret = il_set_tx_power(il, val, false);
if (ret)
- IL_ERR("failed setting tx power (0x%d).\n", ret);
+ IL_ERR("failed setting tx power (0x%08x).\n", ret);
else
ret = count;
}
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 47a998d..22884ba 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -653,6 +653,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
if (channel &&
!(channel->flags & IEEE80211_CHAN_DISABLED)) {
bss = cfg80211_inform_bss(wiphy, channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
bssid, get_unaligned_le64(tsfdesc),
capa, intvl, ie, ielen,
LBS_SCAN_RSSI_TO_MBM(rssi),
@@ -1754,6 +1755,7 @@ static void lbs_join_post(struct lbs_private *priv,
bss = cfg80211_inform_bss(priv->wdev->wiphy,
params->chandef.chan,
+ CFG80211_BSS_FTYPE_UNKNOWN,
bssid,
0,
capability,
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index e2e6bf1..c4723b0 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -246,7 +246,7 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
}
if (priv->roc_cfg.cookie) {
- wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llu\n",
+ wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llx\n",
priv->roc_cfg.cookie);
return -EBUSY;
}
@@ -1557,6 +1557,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
band));
bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ CFG80211_BSS_FTYPE_UNKNOWN,
bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
0, ie_buf, ie_len, 0, GFP_KERNEL);
cfg80211_put_bss(priv->wdev->wiphy, bss);
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index baf0aab..985f6c2 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -1470,7 +1470,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_ie_types_header *tlv;
- struct hw_spec_fw_api_rev *api_rev;
+ struct hw_spec_api_rev *api_rev;
u16 resp_size, api_id;
int i, left_len, parsed_len = 0;
@@ -1508,7 +1508,6 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
}
adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
- adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff;
adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) {
@@ -1538,23 +1537,30 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
while (left_len > sizeof(struct mwifiex_ie_types_header)) {
tlv = (void *)&hw_spec->tlvs + parsed_len;
switch (le16_to_cpu(tlv->type)) {
- case TLV_TYPE_FW_API_REV:
- api_rev = (struct hw_spec_fw_api_rev *)tlv;
+ case TLV_TYPE_API_REV:
+ api_rev = (struct hw_spec_api_rev *)tlv;
api_id = le16_to_cpu(api_rev->api_id);
switch (api_id) {
case KEY_API_VER_ID:
- adapter->fw_key_api_major_ver =
+ adapter->key_api_major_ver =
api_rev->major_ver;
- adapter->fw_key_api_minor_ver =
+ adapter->key_api_minor_ver =
api_rev->minor_ver;
dev_dbg(adapter->dev,
- "fw_key_api v%d.%d\n",
- adapter->fw_key_api_major_ver,
- adapter->fw_key_api_minor_ver);
+ "key_api v%d.%d\n",
+ adapter->key_api_major_ver,
+ adapter->key_api_minor_ver);
+ break;
+ case FW_API_VER_ID:
+ adapter->fw_api_ver =
+ api_rev->major_ver;
+ dev_dbg(adapter->dev,
+ "Firmware api version %d\n",
+ adapter->fw_api_ver);
break;
default:
dev_warn(adapter->dev,
- "Unknown FW api_id: %d\n",
+ "Unknown api_id: %d\n",
api_id);
break;
}
@@ -1567,7 +1573,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
}
parsed_len += le16_to_cpu(tlv->len) +
sizeof(struct mwifiex_ie_types_header);
- left_len -= parsed_len;
+ left_len -= le16_to_cpu(tlv->len) +
+ sizeof(struct mwifiex_ie_types_header);
}
}
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 49da2d5..6a703ea 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -83,7 +83,7 @@ enum KEY_TYPE_ID {
#define WPA_PN_SIZE 8
#define KEY_PARAMS_FIXED_LEN 10
#define KEY_INDEX_MASK 0xf
-#define FW_KEY_API_VER_MAJOR_V2 2
+#define KEY_API_VER_MAJOR_V2 2
#define KEY_MCAST BIT(0)
#define KEY_UNICAST BIT(1)
@@ -170,7 +170,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154)
#define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156)
#define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194)
-#define TLV_TYPE_FW_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
+#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@@ -844,11 +844,12 @@ struct host_cmd_ds_802_11_ps_mode_enh {
} params;
} __packed;
-enum FW_API_VER_ID {
+enum API_VER_ID {
KEY_API_VER_ID = 1,
+ FW_API_VER_ID = 2,
};
-struct hw_spec_fw_api_rev {
+struct hw_spec_api_rev {
struct mwifiex_ie_types_header header;
__le16 api_id;
u8 major_ver;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 269a277..80bda80 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -282,8 +282,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
adapter->empty_tx_q_cnt = 0;
adapter->ext_scan = true;
- adapter->fw_key_api_major_ver = 0;
- adapter->fw_key_api_minor_ver = 0;
+ adapter->key_api_major_ver = 0;
+ adapter->key_api_minor_ver = 0;
}
/*
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index a2733b1..5439963 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -833,7 +833,7 @@ struct mwifiex_adapter {
struct semaphore *card_sem;
bool ext_scan;
u8 fw_api_ver;
- u8 fw_key_api_major_ver, fw_key_api_minor_ver;
+ u8 key_api_major_ver, key_api_minor_ver;
struct work_struct iface_work;
unsigned long iface_work_flags;
struct memory_type_mapping *mem_type_mapping_tbl;
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index dee717a..195ef0ca 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1719,7 +1719,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
bss = cfg80211_inform_bss(priv->wdev->wiphy,
- chan, bssid, timestamp,
+ chan, CFG80211_BSS_FTYPE_UNKNOWN,
+ bssid, timestamp,
cap_info_bitmap, beacon_period,
ie_buf, ie_len, rssi, GFP_KERNEL);
bss_priv = (struct mwifiex_bss_priv *)bss->priv;
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 733de92..225f749 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -965,7 +965,7 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
u16 cmd_action, u32 cmd_oid,
struct mwifiex_ds_encrypt_key *enc_key)
{
- if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
return mwifiex_cmd_802_11_key_material_v2(priv, cmd,
cmd_action, cmd_oid,
enc_key);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 08b78ba..62866b0 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -637,7 +637,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
- if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
return mwifiex_ret_802_11_key_material_v2(priv, resp);
else
return mwifiex_ret_802_11_key_material_v1(priv, resp);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index caae973..b95a29b 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -877,7 +877,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
return -1;
}
- if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) {
+ if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {
memcpy(encrypt_key->key_material,
wep_key->key_material, wep_key->key_length);
encrypt_key->key_len = wep_key->key_length;
@@ -903,7 +903,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
memset(&priv->wep_key[index], 0,
sizeof(struct mwifiex_wep_key));
- if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
enc_key = encrypt_key;
else
enc_key = NULL;
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index cee0283..ec79c49 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -172,7 +172,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq,
CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
- 0, GFP_ATOMIC);
+ 0);
return 0;
}
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index d3cf7c3..f4b784f 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1605,10 +1605,7 @@ static int ezusb_probe(struct usb_interface *interface,
for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
ep = &interface->altsetting[0].endpoint[i].desc;
- if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN) &&
- ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ if (usb_endpoint_is_bulk_in(ep)) {
/* we found a bulk in endpoint */
if (upriv->read_urb != NULL) {
pr_warning("Found a second bulk in ep, ignored");
@@ -1636,10 +1633,7 @@ static int ezusb_probe(struct usb_interface *interface,
}
}
- if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_OUT) &&
- ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ if (usb_endpoint_is_bulk_out(ep)) {
/* we found a bulk out endpoint */
if (upriv->bap_buf != NULL) {
pr_warning("Found a second bulk out ep, ignored");
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index e175b9b..2c66166 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -123,9 +123,10 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
beacon_interval = le16_to_cpu(bss->a.beacon_interv);
signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
- cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
- capability, beacon_interval, ie_buf, ie_len,
- signal, GFP_KERNEL);
+ cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
+ bss->a.bssid, timestamp, capability,
+ beacon_interval, ie_buf, ie_len, signal,
+ GFP_KERNEL);
cfg80211_put_bss(wiphy, cbss);
}
@@ -156,9 +157,10 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
ie = bss->data;
signal = SIGNAL_TO_MBM(bss->level);
- cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
- capability, beacon_interval, ie, ie_len,
- signal, GFP_KERNEL);
+ cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
+ bss->bssid, timestamp, capability,
+ beacon_interval, ie, ie_len, signal,
+ GFP_KERNEL);
cfg80211_put_bss(wiphy, cbss);
}
diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h
index e79848f..524c2f0 100644
--- a/drivers/net/wireless/ray_cs.h
+++ b/drivers/net/wireless/ray_cs.h
@@ -3,7 +3,8 @@
Written by Corey Thomas
*/
-#ifndef RAYLINK_H
+#ifndef _RAY_CS_H_
+#define _RAY_CS_H_
struct beacon_rx {
struct mac_header mac;
@@ -69,4 +70,4 @@ typedef struct ray_dev_t {
} ray_dev_t;
/*****************************************************************************/
-#endif /* RAYLINK_H */
+#endif /* _RAY_CS_H_ */
diff --git a/drivers/net/wireless/rayctl.h b/drivers/net/wireless/rayctl.h
index 3c3b98b1..b21ed64 100644
--- a/drivers/net/wireless/rayctl.h
+++ b/drivers/net/wireless/rayctl.h
@@ -1,4 +1,5 @@
-#ifndef RAYLINK_H
+#ifndef _RAYCTL_H_
+#define _RAYCTL_H_
typedef unsigned char UCHAR;
@@ -729,4 +730,4 @@ typedef struct snaphdr_t
#define RAY_IPX_TYPE 0x8137
#define APPLEARP_TYPE 0x80f3
/*****************************************************************************/
-#endif /* #ifndef RAYLINK_H */
+#endif /* _RAYCTL_H_ */
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index d2a9a08..1a4facd 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2022,9 +2022,10 @@ static bool rndis_bss_info_update(struct usbnet *usbdev,
capability = le16_to_cpu(fixed->capabilities);
beacon_interval = le16_to_cpu(fixed->beacon_interval);
- bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
- timestamp, capability, beacon_interval, ie, ie_len, signal,
- GFP_KERNEL);
+ bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
+ CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac,
+ timestamp, capability, beacon_interval,
+ ie, ie_len, signal, GFP_KERNEL);
cfg80211_put_bss(priv->wdev.wiphy, bss);
return (bss != NULL);
@@ -2711,9 +2712,10 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
bssid, (u32)timestamp, capability, beacon_period, ie_len,
ssid.essid, signal);
- bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
- timestamp, capability, beacon_period, ie_buf, ie_len,
- signal, GFP_KERNEL);
+ bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
+ CFG80211_BSS_FTYPE_UNKNOWN, bssid,
+ timestamp, capability, beacon_period,
+ ie_buf, ie_len, signal, GFP_KERNEL);
cfg80211_put_bss(priv->wdev.wiphy, bss);
}
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index a394a9a..b7434df 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -52,6 +52,7 @@
* RF5592 2.4G/5G 2T2R
* RF3070 2.4G 1T1R
* RF5360 2.4G 1T1R
+ * RF5362 2.4G 1T1R
* RF5370 2.4G 1T1R
* RF5390 2.4G 1T1R
*/
@@ -72,6 +73,7 @@
#define RF3070 0x3070
#define RF3290 0x3290
#define RF5360 0x5360
+#define RF5362 0x5362
#define RF5370 0x5370
#define RF5372 0x5372
#define RF5390 0x5390
@@ -2145,7 +2147,7 @@ struct mac_iveiv_entry {
/* Bits [7-4] for RF3320 (RT3370/RT3390), on other chipsets reserved */
#define RFCSR3_PA1_BIAS_CCK FIELD8(0x70)
#define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80)
-/* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */
+/* Bits for RF3290/RF5360/RF5362/RF5370/RF5372/RF5390/RF5392 */
#define RFCSR3_VCOCAL_EN FIELD8(0x80)
/* Bits for RF3050 */
#define RFCSR3_BIT1 FIELD8(0x02)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 893c9d5..9f57a2d 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -3186,6 +3186,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
break;
case RF3070:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
@@ -3203,6 +3204,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_rf(rt2x00dev, RF3290) ||
rt2x00_rf(rt2x00dev, RF3322) ||
rt2x00_rf(rt2x00dev, RF5360) ||
+ rt2x00_rf(rt2x00dev, RF5362) ||
rt2x00_rf(rt2x00dev, RF5370) ||
rt2x00_rf(rt2x00dev, RF5372) ||
rt2x00_rf(rt2x00dev, RF5390) ||
@@ -4317,6 +4319,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
case RF3070:
case RF3290:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
@@ -7095,6 +7098,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
case RF3320:
case RF3322:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
@@ -7551,6 +7555,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
case RF3320:
case RF3322:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
@@ -7680,6 +7685,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
case RF3070:
case RF3290:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
index d76684e..39b9a33 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
@@ -37,7 +37,13 @@
#include "halbtcoutsrc.h"
+#include "halbtc8192e2ant.h"
+#include "halbtc8723b1ant.h"
#include "halbtc8723b2ant.h"
+#include "halbtc8821a2ant.h"
+#include "halbtc8821a1ant.h"
+
+#define GetDefaultAdapter(padapter) padapter
#define BIT0 0x00000001
#define BIT1 0x00000002
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c
new file mode 100644
index 0000000..af3f604
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c
@@ -0,0 +1,3888 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/**************************************************************
+ * Description:
+ *
+ * This file is for RTL8192E Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ **************************************************************/
+
+/**************************************************************
+ * include files
+ **************************************************************/
+#include "halbt_precomp.h"
+/**************************************************************
+ * Global variables, these are static variables
+ **************************************************************/
+static struct coex_dm_8192e_2ant glcoex_dm_8192e_2ant;
+static struct coex_dm_8192e_2ant *coex_dm = &glcoex_dm_8192e_2ant;
+static struct coex_sta_8192e_2ant glcoex_sta_8192e_2ant;
+static struct coex_sta_8192e_2ant *coex_sta = &glcoex_sta_8192e_2ant;
+
+static const char *const GLBtInfoSrc8192e2Ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8192e_2ant = 20130902;
+static u32 glcoex_ver_8192e_2ant = 0x34;
+
+/**************************************************************
+ * local function proto type if needed
+ **************************************************************/
+/**************************************************************
+ * local function start with halbtc8192e2ant_
+ **************************************************************/
+static u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ int btrssi = 0;
+ u8 btrssi_state = coex_sta->pre_bt_rssi_state;
+
+ btrssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi pre state = LOW\n");
+ if (btrssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ btrssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to High\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at Low\n");
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi pre state = HIGH\n");
+ if (btrssi < rssi_thresh) {
+ btrssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to Low\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi pre state = LOW\n");
+ if (btrssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ btrssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to Medium\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi pre state = MEDIUM\n");
+ if (btrssi >= (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ btrssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to High\n");
+ } else if (btrssi < rssi_thresh) {
+ btrssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to Low\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at Medium\n");
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi pre state = HIGH\n");
+ if (btrssi < rssi_thresh1) {
+ btrssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to Medium\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_bt_rssi_state = btrssi_state;
+
+ return btrssi_state;
+}
+
+static u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ int wifirssi = 0;
+ u8 wifirssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifirssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ wifirssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to High\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at Low\n");
+ }
+ } else {
+ if (wifirssi < rssi_thresh) {
+ wifirssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to Low\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifirssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ wifirssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to Medium\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifirssi >= (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ wifirssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to High\n");
+ } else if (wifirssi < rssi_thresh) {
+ wifirssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to Low\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at Medium\n");
+ }
+ } else {
+ if (wifirssi < rssi_thresh1) {
+ wifirssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to Medium\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_wifi_rssi_state[index] = wifirssi_state;
+
+ return wifirssi_state;
+}
+
+static void btc8192e2ant_monitor_bt_enable_dis(struct btc_coexist *btcoexist)
+{
+ static bool pre_bt_disabled;
+ static u32 bt_disable_cnt;
+ bool bt_active = true, bt_disabled = false;
+
+ /* This function check if bt is disabled */
+
+ if (coex_sta->high_priority_tx == 0 &&
+ coex_sta->high_priority_rx == 0 &&
+ coex_sta->low_priority_tx == 0 &&
+ coex_sta->low_priority_rx == 0)
+ bt_active = false;
+
+ if (coex_sta->high_priority_tx == 0xffff &&
+ coex_sta->high_priority_rx == 0xffff &&
+ coex_sta->low_priority_tx == 0xffff &&
+ coex_sta->low_priority_rx == 0xffff)
+ bt_active = false;
+
+ if (bt_active) {
+ bt_disable_cnt = 0;
+ bt_disabled = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is enabled !!\n");
+ } else {
+ bt_disable_cnt++;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], bt all counters = 0, %d times!!\n",
+ bt_disable_cnt);
+ if (bt_disable_cnt >= 2) {
+ bt_disabled = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is disabled !!\n");
+ }
+ }
+ if (pre_bt_disabled != bt_disabled) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is from %s to %s!!\n",
+ (pre_bt_disabled ? "disabled" : "enabled"),
+ (bt_disabled ? "disabled" : "enabled"));
+ pre_bt_disabled = bt_disabled;
+ }
+}
+
+static u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist,
+ u8 sstype, u32 ra_masktype)
+{
+ u32 disra_mask = 0x0;
+
+ switch (ra_masktype) {
+ case 0: /* normal mode */
+ if (sstype == 2)
+ disra_mask = 0x0; /* enable 2ss */
+ else
+ disra_mask = 0xfff00000;/* disable 2ss */
+ break;
+ case 1: /* disable cck 1/2 */
+ if (sstype == 2)
+ disra_mask = 0x00000003;/* enable 2ss */
+ else
+ disra_mask = 0xfff00003;/* disable 2ss */
+ break;
+ case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */
+ if (sstype == 2)
+ disra_mask = 0x0001f1f7;/* enable 2ss */
+ else
+ disra_mask = 0xfff1f1f7;/* disable 2ss */
+ break;
+ default:
+ break;
+ }
+
+ return disra_mask;
+}
+
+static void halbtc8192e2ant_Updatera_mask(struct btc_coexist *btcoexist,
+ bool force_exec, u32 dis_ratemask)
+{
+ coex_dm->curra_mask = dis_ratemask;
+
+ if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask))
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+ &coex_dm->curra_mask);
+ coex_dm->prera_mask = coex_dm->curra_mask;
+}
+
+static void btc8192e2ant_autorate_fallback_retry(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ bool wifi_under_bmode = false;
+
+ coex_dm->cur_arfrtype = type;
+
+ if (force_exec || (coex_dm->pre_arfrtype != coex_dm->cur_arfrtype)) {
+ switch (coex_dm->cur_arfrtype) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ coex_dm->backup_arfr_cnt1);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ coex_dm->backup_arfr_cnt2);
+ break;
+ case 1:
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_B_MODE,
+ &wifi_under_bmode);
+ if (wifi_under_bmode) {
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ 0x0);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ 0x01010101);
+ } else {
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ 0x0);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ 0x04030201);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_arfrtype = coex_dm->cur_arfrtype;
+}
+
+static void halbtc8192e2ant_retrylimit(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_retrylimit_type = type;
+
+ if (force_exec || (coex_dm->pre_retrylimit_type !=
+ coex_dm->cur_retrylimit_type)) {
+ switch (coex_dm->cur_retrylimit_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_2byte(btcoexist, 0x42a,
+ coex_dm->backup_retrylimit);
+ break;
+ case 1: /* retry limit = 8 */
+ btcoexist->btc_write_2byte(btcoexist, 0x42a,
+ 0x0808);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_retrylimit_type = coex_dm->cur_retrylimit_type;
+}
+
+static void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_ampdutime_type = type;
+
+ if (force_exec || (coex_dm->pre_ampdutime_type !=
+ coex_dm->cur_ampdutime_type)) {
+ switch (coex_dm->cur_ampdutime_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_1byte(btcoexist, 0x456,
+ coex_dm->backup_ampdu_maxtime);
+ break;
+ case 1: /* AMPDU timw = 0x38 * 32us */
+ btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_ampdutime_type = coex_dm->cur_ampdutime_type;
+}
+
+static void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist,
+ bool force_exec, u8 ra_masktype,
+ u8 arfr_type, u8 retrylimit_type,
+ u8 ampdutime_type)
+{
+ u32 disra_mask = 0x0;
+
+ coex_dm->curra_masktype = ra_masktype;
+ disra_mask = halbtc8192e2ant_decidera_mask(btcoexist,
+ coex_dm->cur_sstype,
+ ra_masktype);
+ halbtc8192e2ant_Updatera_mask(btcoexist, force_exec, disra_mask);
+btc8192e2ant_autorate_fallback_retry(btcoexist, force_exec, arfr_type);
+ halbtc8192e2ant_retrylimit(btcoexist, force_exec, retrylimit_type);
+ halbtc8192e2ant_ampdu_maxtime(btcoexist, force_exec, ampdutime_type);
+}
+
+static void halbtc8192e2ant_limited_rx(struct btc_coexist *btcoexist,
+ bool force_exec, bool rej_ap_agg_pkt,
+ bool bt_ctrl_agg_buf_size,
+ u8 agg_buf_size)
+{
+ bool reject_rx_agg = rej_ap_agg_pkt;
+ bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+ u8 rx_agg_size = agg_buf_size;
+
+ /*********************************************
+ * Rx Aggregation related setting
+ *********************************************/
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT,
+ &reject_rx_agg);
+ /* decide BT control aggregation buf size or not */
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+ &bt_ctrl_rx_agg_size);
+ /* aggregation buf size, only work
+ * when BT control Rx aggregation size.
+ */
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size);
+ /* real update aggregation setting */
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_txrx, reg_lp_txrx, u32tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_txrx = 0x770;
+ reg_lp_txrx = 0x774;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+ reg_hp_tx = u32tmp & MASKLWORD;
+ reg_hp_rx = (u32tmp & MASKHWORD)>>16;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+ reg_lp_tx = u32tmp & MASKLWORD;
+ reg_lp_rx = (u32tmp & MASKHWORD)>>16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex] High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+ reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex] Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+ reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+
+ /* reset counter */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hson = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+
+ bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+ bt_link_info->sco_exist = coex_sta->sco_exist;
+ bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+ bt_link_info->pan_exist = coex_sta->pan_exist;
+ bt_link_info->hid_exist = coex_sta->hid_exist;
+
+ /* work around for HS mode. */
+ if (bt_hson) {
+ bt_link_info->pan_exist = true;
+ bt_link_info->bt_link_exist = true;
+ }
+
+ /* check if Sco only */
+ if (bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->sco_only = true;
+ else
+ bt_link_info->sco_only = false;
+
+ /* check if A2dp only */
+ if (!bt_link_info->sco_exist &&
+ bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->a2dp_only = true;
+ else
+ bt_link_info->a2dp_only = false;
+
+ /* check if Pan only */
+ if (!bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->pan_only = true;
+ else
+ bt_link_info->pan_only = false;
+
+ /* check if Hid only */
+ if (!bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ bt_link_info->hid_exist)
+ bt_link_info->hid_only = true;
+ else
+ bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ bool bt_hson = false;
+ u8 algorithm = BT_8192E_2ANT_COEX_ALGO_UNDEFINED;
+ u8 numdiffprofile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+
+ if (!bt_link_info->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "No BT link exists!!!\n");
+ return algorithm;
+ }
+
+ if (bt_link_info->sco_exist)
+ numdiffprofile++;
+ if (bt_link_info->hid_exist)
+ numdiffprofile++;
+ if (bt_link_info->pan_exist)
+ numdiffprofile++;
+ if (bt_link_info->a2dp_exist)
+ numdiffprofile++;
+
+ if (numdiffprofile == 1) {
+ if (bt_link_info->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO only\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID only\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "A2DP only\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "PAN(HS) only\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "PAN(EDR) only\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (numdiffprofile == 2) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + HID\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + A2DP ==> SCO\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + PAN(HS)\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_SCO_PAN;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ if (stack_info->num_of_hid >= 2) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID*2 + A2DP\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + A2DP\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP;
+ }
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + PAN(HS)\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (numdiffprofile == 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + HID + A2DP ==> HID\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + HID + PAN(HS)\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + HID + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_SCO_PAN;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + A2DP + PAN(HS)\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (numdiffprofile >= 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "ErrorSCO+HID+A2DP+PAN(HS)\n");
+
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO+HID+A2DP+PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+
+ return algorithm;
+}
+
+static void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist,
+ u8 dac_swinglvl)
+{
+ u8 h2c_parameter[1] = {0};
+
+ /* There are several type of dacswing
+ * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6
+ */
+ h2c_parameter[0] = dac_swinglvl;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swinglvl);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist,
+ u8 dec_btpwr_lvl)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = dec_btpwr_lvl;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex] decrease Bt Power level = %d, FW write 0x62 = 0x%x\n",
+ dec_btpwr_lvl, h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist,
+ bool force_exec, u8 dec_btpwr_lvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s Dec BT power level = %d\n",
+ (force_exec ? "force to" : ""), dec_btpwr_lvl);
+ coex_dm->cur_dec_bt_pwr = dec_btpwr_lvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], preBtDecPwrLvl=%d, curBtDecPwrLvl=%d\n",
+ coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr);
+ }
+ halbtc8192e2ant_set_fwdec_btpwr(btcoexist, coex_dm->cur_dec_bt_pwr);
+
+ coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr;
+}
+
+static void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist,
+ bool enable_autoreport)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (enable_autoreport)
+ h2c_parameter[0] |= BIT0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+ (enable_autoreport ? "Enabled!!" : "Disabled!!"),
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist,
+ bool force_exec,
+ bool enable_autoreport)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s BT Auto report = %s\n",
+ (force_exec ? "force to" : ""),
+ ((enable_autoreport) ? "Enabled" : "Disabled"));
+ coex_dm->cur_bt_auto_report = enable_autoreport;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex] bPreBtAutoReport=%d, bCurBtAutoReport=%d\n",
+ coex_dm->pre_bt_auto_report,
+ coex_dm->cur_bt_auto_report);
+
+ if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+ return;
+ }
+ halbtc8192e2ant_set_bt_autoreport(btcoexist,
+ coex_dm->cur_bt_auto_report);
+
+ coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist,
+ bool force_exec, u8 fw_dac_swinglvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set FW Dac Swing level = %d\n",
+ (force_exec ? "force to" : ""), fw_dac_swinglvl);
+ coex_dm->cur_fw_dac_swing_lvl = fw_dac_swinglvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex] preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n",
+ coex_dm->pre_fw_dac_swing_lvl,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ if (coex_dm->pre_fw_dac_swing_lvl ==
+ coex_dm->cur_fw_dac_swing_lvl)
+ return;
+ }
+
+ halbtc8192e2ant_setfw_dac_swinglevel(btcoexist,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl;
+}
+
+static void btc8192e2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist,
+ bool rx_rf_shrink_on)
+{
+ if (rx_rf_shrink_on) {
+ /* Shrink RF Rx LPF corner */
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Shrink RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+ 0xfffff, 0xffffc);
+ } else {
+ /* Resume RF Rx LPF corner
+ * After initialized, we can use coex_dm->btRf0x1eBackup
+ */
+ if (btcoexist->initilized) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Resume RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+ 0xfffff,
+ coex_dm->bt_rf0x1e_backup);
+ }
+ }
+}
+
+static void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist,
+ bool force_exec, bool rx_rf_shrink_on)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn Rx RF Shrink = %s\n",
+ (force_exec ? "force to" : ""),
+ ((rx_rf_shrink_on) ? "ON" : "OFF"));
+ coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex]bPreRfRxLpfShrink=%d,bCurRfRxLpfShrink=%d\n",
+ coex_dm->pre_rf_rx_lpf_shrink,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ if (coex_dm->pre_rf_rx_lpf_shrink ==
+ coex_dm->cur_rf_rx_lpf_shrink)
+ return;
+ }
+ btc8192e2ant_set_sw_rf_rx_lpf_corner(btcoexist,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink;
+}
+
+static void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist,
+ u32 level)
+{
+ u8 val = (u8)level;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Write SwDacSwing = 0x%x\n", level);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val);
+}
+
+static void btc8192e2ant_setsw_full_swing(struct btc_coexist *btcoexist,
+ bool sw_dac_swingon,
+ u32 sw_dac_swinglvl)
+{
+ if (sw_dac_swingon)
+ halbtc8192e2ant_set_dac_swingreg(btcoexist, sw_dac_swinglvl);
+ else
+ halbtc8192e2ant_set_dac_swingreg(btcoexist, 0x18);
+}
+
+static void halbtc8192e2ant_DacSwing(struct btc_coexist *btcoexist,
+ bool force_exec, bool dac_swingon,
+ u32 dac_swinglvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn DacSwing=%s, dac_swinglvl = 0x%x\n",
+ (force_exec ? "force to" : ""),
+ ((dac_swingon) ? "ON" : "OFF"), dac_swinglvl);
+ coex_dm->cur_dac_swing_on = dac_swingon;
+ coex_dm->cur_dac_swing_lvl = dac_swinglvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl = 0x%x, ",
+ coex_dm->pre_dac_swing_on,
+ coex_dm->pre_dac_swing_lvl);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "bCurDacSwingOn=%d, curDacSwingLvl = 0x%x\n",
+ coex_dm->cur_dac_swing_on,
+ coex_dm->cur_dac_swing_lvl);
+
+ if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) &&
+ (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl))
+ return;
+ }
+ mdelay(30);
+ btc8192e2ant_setsw_full_swing(btcoexist, dac_swingon, dac_swinglvl);
+
+ coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on;
+ coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl;
+}
+
+static void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist,
+ bool agc_table_en)
+{
+ /* BB AGC Gain Table */
+ if (agc_table_en) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB Agc Table On!\n");
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x0a1A0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x091B0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x081C0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x071D0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x061E0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x051F0001);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB Agc Table Off!\n");
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001);
+ }
+}
+
+static void halbtc8192e2ant_AgcTable(struct btc_coexist *btcoexist,
+ bool force_exec, bool agc_table_en)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s %s Agc Table\n",
+ (force_exec ? "force to" : ""),
+ ((agc_table_en) ? "Enable" : "Disable"));
+ coex_dm->cur_agc_table_en = agc_table_en;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n",
+ coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en);
+
+ if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en)
+ return;
+ }
+ halbtc8192e2ant_set_agc_table(btcoexist, agc_table_en);
+
+ coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en;
+}
+
+static void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, ",
+ (force_exec ? "force to" : ""), val0x6c0);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+ val0x6c4, val0x6c8, val0x6cc);
+ coex_dm->cur_val0x6c0 = val0x6c0;
+ coex_dm->cur_val0x6c4 = val0x6c4;
+ coex_dm->cur_val0x6c8 = val0x6c8;
+ coex_dm->cur_val0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c4 = 0x%x, ",
+ coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n",
+ coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c4 = 0x%x,\n",
+ coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n",
+ coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc);
+
+ if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+ (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+ (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+ (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+ return;
+ }
+ halbtc8192e2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+
+ coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+ coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+ coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+ coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void btc8192e2ant_coex_tbl_w_type(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ switch (type) {
+ case 0:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 1:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 2:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5ffb5ffb, 0xffffff, 0x3);
+ break;
+ case 3:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff,
+ 0x5fdb5fdb, 0xffffff, 0x3);
+ break;
+ case 4:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff,
+ 0x5ffb5ffb, 0xffffff, 0x3);
+ break;
+ default:
+ break;
+ }
+}
+
+static void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0; /* function enable */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex]set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_IgnoreWlanAct(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPreIgnoreWlanAct = %d ",
+ coex_dm->pre_ignore_wlan_act);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "bCurIgnoreWlanAct = %d!!\n",
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ halbtc8192e2ant_set_fw_ignore_wlanact(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8192e2ant_SetFwPstdma(struct btc_coexist *btcoexist, u8 byte1,
+ u8 byte2, u8 byte3, u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5] = {0};
+
+ h2c_parameter[0] = byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = byte5;
+
+ coex_dm->ps_tdma_para[0] = byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1] << 24 | h2c_parameter[2] << 16 |
+ h2c_parameter[3] << 8 | h2c_parameter[4]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void btc8192e2ant_sw_mec1(struct btc_coexist *btcoexist,
+ bool shrink_rx_lpf, bool low_penalty_ra,
+ bool limited_dig, bool btlan_constrain)
+{
+ halbtc8192e2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf);
+}
+
+static void btc8192e2ant_sw_mec2(struct btc_coexist *btcoexist,
+ bool agc_table_shift, bool adc_backoff,
+ bool sw_dac_swing, u32 dac_swinglvl)
+{
+ halbtc8192e2ant_AgcTable(btcoexist, NORMAL_EXEC, agc_table_shift);
+ halbtc8192e2ant_DacSwing(btcoexist, NORMAL_EXEC, sw_dac_swing,
+ dac_swinglvl);
+}
+
+static void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist,
+ bool force_exec, bool turn_on, u8 type)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn %s PS TDMA, type=%d\n",
+ (force_exec ? "force to" : ""),
+ (turn_on ? "ON" : "OFF"), type);
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n",
+ coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n",
+ coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma);
+
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ case 1:
+ default:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ case 2:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x90);
+ break;
+ case 3:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf1, 0x90);
+ break;
+ case 4:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10,
+ 0x3, 0xf1, 0x90);
+ break;
+ case 5:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0x60, 0x90);
+ break;
+ case 6:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0x60, 0x90);
+ break;
+ case 7:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0x70, 0x90);
+ break;
+ case 8:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xa3, 0x10,
+ 0x3, 0x70, 0x90);
+ break;
+ case 9:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x10);
+ break;
+ case 10:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x10);
+ break;
+ case 11:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf1, 0x10);
+ break;
+ case 12:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10,
+ 0x3, 0xf1, 0x10);
+ break;
+ case 13:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe0, 0x10);
+ break;
+ case 14:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe0, 0x10);
+ break;
+ case 15:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf0, 0x10);
+ break;
+ case 16:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x3, 0xf0, 0x10);
+ break;
+ case 17:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0x61, 0x20,
+ 0x03, 0x10, 0x10);
+ break;
+ case 18:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0xe1, 0x90);
+ break;
+ case 19:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0xe1, 0x90);
+ break;
+ case 20:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0x60, 0x90);
+ break;
+ case 21:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x15,
+ 0x03, 0x70, 0x90);
+ break;
+ case 71:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ }
+ } else {
+ /* disable PS tdma */
+ switch (type) {
+ default:
+ case 0:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0x8, 0x0, 0x0,
+ 0x0, 0x0);
+ btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4);
+ break;
+ case 1:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x8, 0x0);
+ mdelay(5);
+ btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20);
+ break;
+ }
+ }
+
+ /* update pre state */
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist,
+ u8 sstype)
+{
+ u8 mimops = BTC_MIMO_PS_DYNAMIC;
+ u32 disra_mask = 0x0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], REAL set SS Type = %d\n", sstype);
+
+ disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, sstype,
+ coex_dm->curra_masktype);
+ halbtc8192e2ant_Updatera_mask(btcoexist, FORCE_EXEC, disra_mask);
+
+ if (sstype == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+ /* switch ofdm path */
+ btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x11);
+ btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x1);
+ btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81111111);
+ /* switch cck patch */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x1);
+ btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x81);
+ mimops = BTC_MIMO_PS_STATIC;
+ } else if (sstype == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+ btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x33);
+ btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x3);
+ btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81121313);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x0);
+ btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x41);
+ mimops = BTC_MIMO_PS_DYNAMIC;
+ }
+ /* set rx 1ss or 2ss */
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimops);
+}
+
+static void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist,
+ bool force_exec, u8 new_sstype)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], %s Switch SS Type = %d\n",
+ (force_exec ? "force to" : ""), new_sstype);
+ coex_dm->cur_sstype = new_sstype;
+
+ if (!force_exec) {
+ if (coex_dm->pre_sstype == coex_dm->cur_sstype)
+ return;
+ }
+ halbtc8192e2ant_set_switch_sstype(btcoexist, coex_dm->cur_sstype);
+
+ coex_dm->pre_sstype = coex_dm->cur_sstype;
+}
+
+static void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist)
+{
+ /* fw all off */
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ /* sw all off */
+ btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+
+ /* hw all off */
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* force to reset coex mechanism */
+
+ halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, FORCE_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, FORCE_EXEC, 0);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, FORCE_EXEC, 0);
+ halbtc8192e2ant_switch_sstype(btcoexist, FORCE_EXEC, 2);
+
+ btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+}
+
+static void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+ bool low_pwr_disable = true;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+}
+
+static bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool common = false, wifi_connected = false, wifi_busy = false;
+ bool bt_hson = false, low_pwr_disable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (bt_link_info->sco_exist || bt_link_info->hid_exist)
+ halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 0, 0, 0);
+ else
+ halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+
+ if (!wifi_connected) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non-connected idle!!\n");
+
+ if ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) ||
+ (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 2);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 1);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ } else {
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 1);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ }
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+
+ common = true;
+ } else {
+ if (BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Wifi connected + BT non connected-idle!!\n");
+
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 2);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 1);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+ NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+
+ common = true;
+ } else if (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (bt_hson)
+ return false;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Wifi connected + BT connected-idle!!\n");
+
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 2);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 1);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+ NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+
+ common = true;
+ } else {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Wifi Connected-Busy + BT Busy!!\n");
+ common = false;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Wifi Connected-Idle + BT Busy!!\n");
+
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 1);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 21);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+ NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist,
+ NORMAL_EXEC, 0);
+ btc8192e2ant_sw_mec1(btcoexist, false,
+ false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false,
+ false, false, 0x18);
+ common = true;
+ }
+ }
+ }
+ return common;
+}
+
+static void btc8192e_int1(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+
+ if (coex_dm->cur_ps_tdma == 71) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 71) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ }
+ }
+ }
+}
+
+static void btc8192e_int2(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ }
+ }
+ }
+}
+
+static void btc8192e_int3(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ }
+}
+
+static void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
+ bool sco_hid, bool tx_pause,
+ u8 max_interval)
+{
+ static int up, dn, m, n, wait_cnt;
+ /* 0: no change, +1: increase WiFi duration,
+ * -1: decrease WiFi duration
+ */
+ int result;
+ u8 retry_cnt = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjust()\n");
+
+ if (!coex_dm->auto_tdma_adjust) {
+ coex_dm->auto_tdma_adjust = true;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+ if (sco_hid) {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (max_interval == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (max_interval == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ } else {
+ if (max_interval == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (max_interval == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (max_interval == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ } else {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (max_interval == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (max_interval == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ }
+ } else {
+ if (max_interval == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (max_interval == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (max_interval == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ }
+ }
+ }
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_cnt = 0;
+ } else {
+ /* accquire the BT TRx retry count from BT_Info byte2 */
+ retry_cnt = coex_sta->bt_retry_cnt;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], retry_cnt = %d\n", retry_cnt);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_cnt=%d\n",
+ up, dn, m, n, wait_cnt);
+ result = 0;
+ wait_cnt++;
+ /* no retry in the last 2-second duration */
+ if (retry_cnt == 0) {
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ wait_cnt = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex]Increase wifi duration!!\n");
+ }
+ } else if (retry_cnt <= 3) {
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ if (wait_cnt <= 2)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3 * m;
+ up = 0;
+ dn = 0;
+ wait_cnt = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "Reduce wifi duration for retry<3\n");
+ }
+ } else {
+ if (wait_cnt == 1)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_cnt = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "Decrease wifi duration for retryCounter>3!!\n");
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], max Interval = %d\n", max_interval);
+ if (max_interval == 1)
+ btc8192e_int1(btcoexist, tx_pause, result);
+ else if (max_interval == 2)
+ btc8192e_int2(btcoexist, tx_pause, result);
+ else if (max_interval == 3)
+ btc8192e_int3(btcoexist, tx_pause, result);
+ }
+
+ /* if current PsTdma not match with
+ * the recorded one (when scan, dhcp...),
+ * then we have to adjust it back to the previous record one.
+ */
+ if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) {
+ bool scan = false, link = false, roam = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], PsTdma type dismatch!!!, ");
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "curPsTdma=%d, recordPsTdma=%d\n",
+ coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (!scan && !link && !roam)
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true,
+ coex_dm->tdma_adj_type);
+ else
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n");
+ }
+}
+
+/* SCO only or SCO+PAN(HS) */
+static void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 4);
+
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x6);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x6);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 4);
+
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x6);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x6);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+ bool long_dist = false;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW ||
+ btrssi_state == BTC_RSSI_STATE_STAY_LOW) &&
+ (wifirssi_state == BTC_RSSI_STATE_LOW ||
+ wifirssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2dp, wifi/bt rssi both LOW!!\n");
+ long_dist = true;
+ }
+ if (long_dist) {
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true,
+ 0x4);
+ } else {
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false,
+ 0x8);
+ }
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (long_dist)
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 0);
+ else
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ if (long_dist) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17);
+ coex_dm->auto_tdma_adjust = false;
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ } else {
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ true, 1);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 1);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 1);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ }
+ }
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 2);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 2);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 2);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ }
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ true, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ true, 0x6);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ true, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ true, 0x6);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1);
+ }
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* PAN(HS) only */
+static void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ }
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* PAN(EDR)+A2DP */
+static void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 3);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 3);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 3);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8192e2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 3);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ u8 algorithm = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism()===>\n");
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], return for Manual CTRL <===\n");
+ return;
+ }
+
+ if (coex_sta->under_ips) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is under IPS !!!\n");
+ return;
+ }
+
+ algorithm = halbtc8192e2ant_action_algorithm(btcoexist);
+ if (coex_sta->c2h_bt_inquiry_page &&
+ (BT_8192E_2ANT_COEX_ALGO_PANHS != algorithm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT is under inquiry/page scan !!\n");
+ halbtc8192e2ant_action_bt_inquiry(btcoexist);
+ return;
+ }
+
+ coex_dm->cur_algorithm = algorithm;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm);
+
+ if (halbtc8192e2ant_is_common_action(btcoexist)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant common.\n");
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex] preAlgorithm=%d, curAlgorithm=%d\n",
+ coex_dm->pre_algorithm,
+ coex_dm->cur_algorithm);
+ coex_dm->auto_tdma_adjust = false;
+ }
+ switch (coex_dm->cur_algorithm) {
+ case BT_8192E_2ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = SCO.\n");
+ halbtc8192e2ant_action_sco(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_SCO_PAN:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = SCO+PAN(EDR).\n");
+ halbtc8192e2ant_action_sco_pan(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = HID.\n");
+ halbtc8192e2ant_action_hid(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = A2DP.\n");
+ halbtc8192e2ant_action_a2dp(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = A2DP+PAN(HS).\n");
+ halbtc8192e2ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = PAN(EDR).\n");
+ halbtc8192e2ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = HS mode.\n");
+ halbtc8192e2ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = PAN+A2DP.\n");
+ halbtc8192e2ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = PAN(EDR)+HID.\n");
+ halbtc8192e2ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = HID+A2DP+PAN.\n");
+ btc8192e2ant_action_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = HID+A2DP.\n");
+ halbtc8192e2ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = unknown!!\n");
+ /* halbtc8192e2ant_coex_alloff(btcoexist); */
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+static void halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist,
+ bool backup)
+{
+ u16 u16tmp = 0;
+ u8 u8tmp = 0;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 2Ant Init HW Config!!\n");
+
+ if (backup) {
+ /* backup rf 0x1e value */
+ coex_dm->bt_rf0x1e_backup =
+ btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A,
+ 0x1e, 0xfffff);
+
+ coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist,
+ 0x430);
+ coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist,
+ 0x434);
+ coex_dm->backup_retrylimit = btcoexist->btc_read_2byte(
+ btcoexist,
+ 0x42a);
+ coex_dm->backup_ampdu_maxtime = btcoexist->btc_read_1byte(
+ btcoexist,
+ 0x456);
+ }
+
+ /* antenna sw ctrl to bt */
+ btcoexist->btc_write_1byte(btcoexist, 0x4f, 0x6);
+ btcoexist->btc_write_1byte(btcoexist, 0x944, 0x24);
+ btcoexist->btc_write_4byte(btcoexist, 0x930, 0x700700);
+ btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20);
+ if (btcoexist->chip_interface == BTC_INTF_USB)
+ btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004);
+ else
+ btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, FORCE_EXEC, 0);
+
+ /* antenna switch control parameter */
+ btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);
+
+ /* coex parameters */
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+ /* 0x790[5:0] = 0x5 */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u8tmp &= 0xc0;
+ u8tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
+
+ /* enable counter statistics */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+
+ /* enable PTA */
+ btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20);
+ /* enable mailbox interface */
+ u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x40);
+ u16tmp |= BIT9;
+ btcoexist->btc_write_2byte(btcoexist, 0x40, u16tmp);
+
+ /* enable PTA I2C mailbox */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x101);
+ u8tmp |= BIT4;
+ btcoexist->btc_write_1byte(btcoexist, 0x101, u8tmp);
+
+ /* enable bt clock when wifi is disabled. */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x93);
+ u8tmp |= BIT0;
+ btcoexist->btc_write_1byte(btcoexist, 0x93, u8tmp);
+ /* enable bt clock when suspend. */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7);
+ u8tmp |= BIT0;
+ btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp);
+}
+
+/*************************************************************
+ * work around function start with wa_halbtc8192e2ant_
+ *************************************************************/
+
+/************************************************************
+ * extern function start with EXhalbtc8192e2ant_
+ ************************************************************/
+
+void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ halbtc8192e2ant_init_hwconfig(btcoexist, true);
+}
+
+void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+ halbtc8192e2ant_init_coex_dm(btcoexist);
+}
+
+void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ u8 *cli_buf = btcoexist->cli_buf;
+ u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+ u16 u16tmp[4];
+ u32 u32tmp[4];
+ bool roam = false, scan = false, link = false, wifi_under_5g = false;
+ bool bt_hson = false, wifi_busy = false;
+ int wifirssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir;
+ u8 wifi_dot11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[BT Coexist info]============");
+ CL_PRINTF(cli_buf);
+
+ if (btcoexist->manual_control) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ===========[Under Manual Control]===========");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ==========================================");
+ CL_PRINTF(cli_buf);
+ }
+
+ if (!board_info->bt_exist) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
+ CL_PRINTF(cli_buf);
+ return;
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:",
+ board_info->pg_ant_num, board_info->btdm_ant_num);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d",
+ "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+ &wifi_dot11_chnl);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsMode(HsChnl)",
+ wifi_dot11_chnl, bt_hson, wifi_hs_chnl);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0],
+ coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "Wifi rssi/ HS rssi", wifirssi, bt_hs_rssi);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+ "Wifi link/ roam/ scan", link, roam, scan);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+ &wifi_traffic_dir);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ",
+ "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ",
+ "BT [status/ rssi/ retryCnt]",
+ ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+ ((coex_sta->c2h_bt_inquiry_page) ?
+ ("inquiry/page scan") :
+ ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) ? "non-connected idle" :
+ ((BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) ? "connected-idle" : "busy")))),
+ coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d",
+ "SCO/HID/PAN/A2DP", stack_info->sco_exist,
+ stack_info->hid_exist, stack_info->pan_exist,
+ stack_info->a2dp_exist);
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
+ CL_PRINTF(cli_buf);
+
+ for (i = 0; i < BT_INFO_SRC_8192E_2ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x ",
+ GLBtInfoSrc8192e2Ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3]);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "%02x %02x %02x(%d)",
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ CL_PRINTF(cli_buf);
+ }
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s",
+ "PS state, IPS/LPS",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type",
+ coex_dm->cur_sstype);
+ CL_PRINTF(cli_buf);
+
+ /* Sw mechanism */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Sw mechanism]============");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+ "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink,
+ coex_dm->cur_low_penalty_ra, coex_dm->limited_dig);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+ "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
+ coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
+ coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask",
+ btcoexist->bt_info.ra_mask);
+ CL_PRINTF(cli_buf);
+
+ /* Fw mechanism */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Fw mechanism]============");
+ CL_PRINTF(cli_buf);
+
+ ps_tdma_case = coex_dm->cur_ps_tdma;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+ "PS TDMA", coex_dm->ps_tdma_para[0],
+ coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
+ coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
+ ps_tdma_case, coex_dm->auto_tdma_adjust);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+ "DecBtPwr/ IgnWlanAct",
+ coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act);
+ CL_PRINTF(cli_buf);
+
+ /* Hw setting */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Hw setting]============");
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x",
+ "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1,
+ coex_dm->backup_arfr_cnt2, coex_dm->backup_retrylimit,
+ coex_dm->backup_ampdu_maxtime);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+ u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "0x430/0x434/0x42a/0x456",
+ u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0xc04/ 0xd04/ 0x90c", u32tmp[0], u32tmp[1], u32tmp[2]);
+ CL_PRINTF(cli_buf);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778",
+ u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c);
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x92c/ 0x930", (u8tmp[0]), u32tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x40/ 0x4f", u8tmp[0], u8tmp[1]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)",
+ u32tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
+ u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "0x770(hp rx[31:16]/tx[15:0])",
+ coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "0x774(lp rx[31:16]/tx[15:0])",
+ coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+ CL_PRINTF(cli_buf);
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1)
+ halbtc8192e2ant_monitor_bt_ctr(btcoexist);
+#endif
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+ halbtc8192e2ant_coex_alloff(btcoexist);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+ }
+}
+
+void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_lps = false;
+ }
+}
+
+void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_SCAN_START == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ else if (BTC_SCAN_FINISH == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+}
+
+void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_ASSOCIATE_START == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ else if (BTC_ASSOCIATE_FINISH == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+}
+
+void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifi_center_chnl;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ if (BTC_MEDIA_CONNECT == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+
+ /* only 2.4G we need to inform bt the chnl mask */
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ &wifi_center_chnl);
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifi_center_chnl <= 14)) {
+ h2c_parameter[0] = 0x1;
+ h2c_parameter[1] = wifi_center_chnl;
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66 = 0x%x\n",
+ h2c_parameter[0] << 16 | h2c_parameter[1] << 8 |
+ h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ if (type == BTC_PACKET_DHCP)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], DHCP Packet notify\n");
+}
+
+void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ bool bt_busy = false, limited_dig = false;
+ bool wifi_connected = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ rsp_source = tmp_buf[0] & 0xf;
+ if (rsp_source >= BT_INFO_SRC_8192E_2ANT_MAX)
+ rsp_source = BT_INFO_SRC_8192E_2ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length=%d, hex data = [",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+ if (i == 1)
+ bt_info = tmp_buf[i];
+ if (i == length-1)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmp_buf[i]);
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmp_buf[i]);
+ }
+
+ if (BT_INFO_SRC_8192E_2ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0] */
+ coex_sta->bt_info_c2h[rsp_source][2] & 0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT
+ * because bt is reset and loss of the info.
+ */
+ if ((coex_sta->bt_info_ext & BIT1)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "bit1, send wifi BW&Chnl to BT!!\n");
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (wifi_connected)
+ ex_halbtc8192e2ant_media_status_notify(
+ btcoexist,
+ BTC_MEDIA_CONNECT);
+ else
+ ex_halbtc8192e2ant_media_status_notify(
+ btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+
+ if ((coex_sta->bt_info_ext & BIT3)) {
+ if (!btcoexist->manual_control &&
+ !btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "bit3, BT NOT ignore Wlan active!\n");
+ halbtc8192e2ant_IgnoreWlanAct(btcoexist,
+ FORCE_EXEC,
+ false);
+ }
+ } else {
+ /* BT already NOT ignore Wlan active,
+ * do nothing here.
+ */
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0)
+ if ((coex_sta->bt_info_ext & BIT4)) {
+ /* BT auto report already enabled, do nothing */
+ } else {
+ halbtc8192e2ant_bt_autoreport(btcoexist, FORCE_EXEC,
+ true);
+ }
+#endif
+ }
+
+ /* check BIT2 first ==> check if bt is under inquiry or page scan */
+ if (bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE)
+ coex_sta->c2h_bt_inquiry_page = true;
+ else
+ coex_sta->c2h_bt_inquiry_page = false;
+
+ /* set link exist status */
+ if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ } else {/* connection exists */
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8192E_2ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8192E_2ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8192E_2ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8192E_2ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ }
+
+ halbtc8192e2ant_update_btlink_info(btcoexist);
+
+ if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Non-Connected idle!!!\n");
+ } else if (bt_info == BT_INFO_8192E_2ANT_B_CONNECTION) {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], bt_infoNotify(), BT Connected-idle!!!\n");
+ } else if ((bt_info&BT_INFO_8192E_2ANT_B_SCO_ESCO) ||
+ (bt_info&BT_INFO_8192E_2ANT_B_SCO_BUSY)) {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_SCO_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], bt_infoNotify(), BT SCO busy!!!\n");
+ } else if (bt_info&BT_INFO_8192E_2ANT_B_ACL_BUSY) {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_ACL_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], bt_infoNotify(), BT ACL busy!!!\n");
+ } else {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_MAX;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex]bt_infoNotify(), BT Non-Defined state!!!\n");
+ }
+
+ if ((BT_8192E_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8192E_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) {
+ bt_busy = true;
+ limited_dig = true;
+ } else {
+ bt_busy = false;
+ limited_dig = false;
+ }
+
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ coex_dm->limited_dig = limited_dig;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig);
+
+ halbtc8192e2ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+}
+
+void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+
+ halbtc8192e2ant_IgnoreWlanAct(btcoexist, FORCE_EXEC, true);
+ ex_halbtc8192e2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist)
+{
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "=======================Periodical=======================\n");
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "************************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+ board_info->pg_ant_num, board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "************************************************\n");
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0)
+ halbtc8192e2ant_querybt_info(btcoexist);
+ halbtc8192e2ant_monitor_bt_ctr(btcoexist);
+ btc8192e2ant_monitor_bt_enable_dis(btcoexist);
+#else
+ if (halbtc8192e2ant_iswifi_status_changed(btcoexist) ||
+ coex_dm->auto_tdma_adjust)
+ halbtc8192e2ant_run_coexist_mechanism(btcoexist);
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h
new file mode 100644
index 0000000..75e1f7d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/*****************************************************************
+ * The following is for 8192E 2Ant BT Co-exist definition
+ *****************************************************************/
+#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0
+
+#define BT_INFO_8192E_2ANT_B_FTP BIT7
+#define BT_INFO_8192E_2ANT_B_A2DP BIT6
+#define BT_INFO_8192E_2ANT_B_HID BIT5
+#define BT_INFO_8192E_2ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8192E_2ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8192E_2ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8192E_2ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8192E_2ANT_B_CONNECTION BIT0
+
+#define BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT 2
+
+enum bt_info_src_8192e_2ant {
+ BT_INFO_SRC_8192E_2ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8192E_2ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8192E_2ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8192E_2ANT_MAX
+};
+
+enum bt_8192e_2ant_bt_status {
+ BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1,
+ BT_8192E_2ANT_BT_STATUS_INQ_PAGE = 0x2,
+ BT_8192E_2ANT_BT_STATUS_ACL_BUSY = 0x3,
+ BT_8192E_2ANT_BT_STATUS_SCO_BUSY = 0x4,
+ BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5,
+ BT_8192E_2ANT_BT_STATUS_MAX
+};
+
+enum bt_8192e_2ant_coex_algo {
+ BT_8192E_2ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8192E_2ANT_COEX_ALGO_SCO = 0x1,
+ BT_8192E_2ANT_COEX_ALGO_SCO_PAN = 0x2,
+ BT_8192E_2ANT_COEX_ALGO_HID = 0x3,
+ BT_8192E_2ANT_COEX_ALGO_A2DP = 0x4,
+ BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS = 0x5,
+ BT_8192E_2ANT_COEX_ALGO_PANEDR = 0x6,
+ BT_8192E_2ANT_COEX_ALGO_PANHS = 0x7,
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP = 0x8,
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_HID = 0x9,
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0xa,
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP = 0xb,
+ BT_8192E_2ANT_COEX_ALGO_MAX = 0xc
+};
+
+struct coex_dm_8192e_2ant {
+ /* fw mechanism */
+ u8 pre_dec_bt_pwr;
+ u8 cur_dec_bt_pwr;
+ u8 pre_fw_dac_swing_lvl;
+ u8 cur_fw_dac_swing_lvl;
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool reset_tdma_adjust;
+ bool auto_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+
+ /* sw mechanism */
+ bool pre_rf_rx_lpf_shrink;
+ bool cur_rf_rx_lpf_shrink;
+ u32 bt_rf0x1e_backup;
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ bool pre_dac_swing_on;
+ u32 pre_dac_swing_lvl;
+ bool cur_dac_swing_on;
+ u32 cur_dac_swing_lvl;
+ bool pre_adc_back_off;
+ bool cur_adc_back_off;
+ bool pre_agc_table_en;
+ bool cur_agc_table_en;
+ u32 pre_val0x6c0;
+ u32 cur_val0x6c0;
+ u32 pre_val0x6c4;
+ u32 cur_val0x6c4;
+ u32 pre_val0x6c8;
+ u32 cur_val0x6c8;
+ u8 pre_val0x6cc;
+ u8 cur_val0x6cc;
+ bool limited_dig;
+
+ u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */
+ u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */
+ u16 backup_retrylimit;
+ u8 backup_ampdu_maxtime;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+
+ u8 pre_sstype;
+ u8 cur_sstype;
+
+ u32 prera_mask;
+ u32 curra_mask;
+ u8 curra_masktype;
+ u8 pre_arfrtype;
+ u8 cur_arfrtype;
+ u8 pre_retrylimit_type;
+ u8 cur_retrylimit_type;
+ u8 pre_ampdutime_type;
+ u8 cur_ampdutime_type;
+};
+
+struct coex_sta_8192e_2ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+
+ bool under_lps;
+ bool under_ips;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8192E_2ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8192E_2ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/****************************************************************
+ * The following is interface which will notify coex module.
+ ****************************************************************/
+void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c
new file mode 100644
index 0000000..e4948c8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c
@@ -0,0 +1,3211 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/***************************************************************
+ * Description:
+ *
+ * This file is for RTL8723B Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ ***************************************************************/
+
+/***************************************************************
+ * include files
+ ***************************************************************/
+#include "halbt_precomp.h"
+/***************************************************************
+ * Global variables, these are static variables
+ ***************************************************************/
+static struct coex_dm_8723b_1ant glcoex_dm_8723b_1ant;
+static struct coex_dm_8723b_1ant *coex_dm = &glcoex_dm_8723b_1ant;
+static struct coex_sta_8723b_1ant glcoex_sta_8723b_1ant;
+static struct coex_sta_8723b_1ant *coex_sta = &glcoex_sta_8723b_1ant;
+
+static const char *const GLBtInfoSrc8723b1Ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8723b_1ant = 20130918;
+static u32 glcoex_ver_8723b_1ant = 0x47;
+
+/***************************************************************
+ * local function proto type if needed
+ ***************************************************************/
+/***************************************************************
+ * local function start with halbtc8723b1ant_
+ ***************************************************************/
+static u8 halbtc8723b1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ s32 bt_rssi = 0;
+ u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+ bt_rssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (bt_rssi >= rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Medium\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh1) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+ return bt_rssi_state;
+}
+
+static u8 halbtc8723b1ant_wifi_rssi_state(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num,
+ u8 rssi_thresh, u8 rssi_thresh1)
+{
+ s32 wifi_rssi = 0;
+ u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifi_rssi >= rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Medium\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh1) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+ return wifi_rssi_state;
+}
+
+static void halbtc8723b1ant_updatera_mask(struct btc_coexist *btcoexist,
+ bool force_exec, u32 dis_rate_mask)
+{
+ coex_dm->curra_mask = dis_rate_mask;
+
+ if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask))
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+ &coex_dm->curra_mask);
+
+ coex_dm->prera_mask = coex_dm->curra_mask;
+}
+
+static void btc8723b1ant_auto_rate_fb_retry(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ bool wifi_under_bmode = false;
+
+ coex_dm->cur_arfr_type = type;
+
+ if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) {
+ switch (coex_dm->cur_arfr_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ coex_dm->backup_arfr_cnt1);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ coex_dm->backup_arfr_cnt2);
+ break;
+ case 1:
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_B_MODE,
+ &wifi_under_bmode);
+ if (wifi_under_bmode) {
+ btcoexist->btc_write_4byte(btcoexist,
+ 0x430, 0x0);
+ btcoexist->btc_write_4byte(btcoexist,
+ 0x434, 0x01010101);
+ } else {
+ btcoexist->btc_write_4byte(btcoexist,
+ 0x430, 0x0);
+ btcoexist->btc_write_4byte(btcoexist,
+ 0x434, 0x04030201);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_arfr_type = coex_dm->cur_arfr_type;
+}
+
+static void halbtc8723b1ant_retry_limit(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_retry_limit_type = type;
+
+ if (force_exec || (coex_dm->pre_retry_limit_type !=
+ coex_dm->cur_retry_limit_type)) {
+ switch (coex_dm->cur_retry_limit_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_2byte(btcoexist, 0x42a,
+ coex_dm->backup_retry_limit);
+ break;
+ case 1: /* retry limit = 8 */
+ btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type;
+}
+
+static void halbtc8723b1ant_ampdu_maxtime(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_ampdu_time_type = type;
+
+ if (force_exec || (coex_dm->pre_ampdu_time_type !=
+ coex_dm->cur_ampdu_time_type)) {
+ switch (coex_dm->cur_ampdu_time_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_1byte(btcoexist, 0x456,
+ coex_dm->backup_ampdu_max_time);
+ break;
+ case 1: /* AMPDU timw = 0x38 * 32us */
+ btcoexist->btc_write_1byte(btcoexist,
+ 0x456, 0x38);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type;
+}
+
+static void halbtc8723b1ant_limited_tx(struct btc_coexist *btcoexist,
+ bool force_exec, u8 ra_masktype,
+ u8 arfr_type, u8 retry_limit_type,
+ u8 ampdu_time_type)
+{
+ switch (ra_masktype) {
+ case 0: /* normal mode */
+ halbtc8723b1ant_updatera_mask(btcoexist, force_exec, 0x0);
+ break;
+ case 1: /* disable cck 1/2 */
+ halbtc8723b1ant_updatera_mask(btcoexist, force_exec,
+ 0x00000003);
+ break;
+ /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/
+ case 2:
+ halbtc8723b1ant_updatera_mask(btcoexist, force_exec,
+ 0x0001f1f7);
+ break;
+ default:
+ break;
+ }
+
+ btc8723b1ant_auto_rate_fb_retry(btcoexist, force_exec, arfr_type);
+ halbtc8723b1ant_retry_limit(btcoexist, force_exec, retry_limit_type);
+ halbtc8723b1ant_ampdu_maxtime(btcoexist, force_exec, ampdu_time_type);
+}
+
+static void halbtc8723b1ant_limited_rx(struct btc_coexist *btcoexist,
+ bool force_exec, bool rej_ap_agg_pkt,
+ bool bt_ctrl_agg_buf_size,
+ u8 agg_buf_size)
+{
+ bool reject_rx_agg = rej_ap_agg_pkt;
+ bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+ u8 rxaggsize = agg_buf_size;
+
+ /**********************************************
+ * Rx Aggregation related setting
+ **********************************************/
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT,
+ &reject_rx_agg);
+ /* decide BT control aggregation buf size or not */
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+ &bt_ctrl_rx_agg_size);
+ /* aggregation buf size, only work
+ * when BT control Rx aggregation size.
+ */
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxaggsize);
+ /* real update aggregation setting */
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_txrx, reg_lp_txrx, u32tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0;
+ u32 reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_txrx = 0x770;
+ reg_lp_txrx = 0x774;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+ reg_hp_tx = u32tmp & MASKLWORD;
+ reg_hp_rx = (u32tmp & MASKHWORD) >> 16;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+ reg_lp_tx = u32tmp & MASKLWORD;
+ reg_lp_rx = (u32tmp & MASKHWORD) >> 16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ /* reset counter */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger*/
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static bool btc8723b1ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
+{
+ static bool pre_wifi_busy;
+ static bool pre_under_4way, pre_bt_hs_on;
+ bool wifi_busy = false, under_4way = false, bt_hs_on = false;
+ bool wifi_connected = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+ &under_4way);
+
+ if (wifi_connected) {
+ if (wifi_busy != pre_wifi_busy) {
+ pre_wifi_busy = wifi_busy;
+ return true;
+ }
+ if (under_4way != pre_under_4way) {
+ pre_under_4way = under_4way;
+ return true;
+ }
+ if (bt_hs_on != pre_bt_hs_on) {
+ pre_bt_hs_on = bt_hs_on;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+ bt_link_info->sco_exist = coex_sta->sco_exist;
+ bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+ bt_link_info->pan_exist = coex_sta->pan_exist;
+ bt_link_info->hid_exist = coex_sta->hid_exist;
+
+ /* work around for HS mode. */
+ if (bt_hs_on) {
+ bt_link_info->pan_exist = true;
+ bt_link_info->bt_link_exist = true;
+ }
+
+ /* check if Sco only */
+ if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->sco_only = true;
+ else
+ bt_link_info->sco_only = false;
+
+ /* check if A2dp only */
+ if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->a2dp_only = true;
+ else
+ bt_link_info->a2dp_only = false;
+
+ /* check if Pan only */
+ if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->pan_only = true;
+ else
+ bt_link_info->pan_only = false;
+
+ /* check if Hid only */
+ if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && bt_link_info->hid_exist)
+ bt_link_info->hid_only = true;
+ else
+ bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8723b1ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+ u8 algorithm = BT_8723B_1ANT_COEX_ALGO_UNDEFINED;
+ u8 numdiffprofile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ if (!bt_link_info->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], No BT link exists!!!\n");
+ return algorithm;
+ }
+
+ if (bt_link_info->sco_exist)
+ numdiffprofile++;
+ if (bt_link_info->hid_exist)
+ numdiffprofile++;
+ if (bt_link_info->pan_exist)
+ numdiffprofile++;
+ if (bt_link_info->a2dp_exist)
+ numdiffprofile++;
+
+ if (numdiffprofile == 1) {
+ if (bt_link_info->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO only\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+ } else {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID only\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP only\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = PAN(HS) only\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = PAN(EDR) only\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (numdiffprofile == 2) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + PAN(HS)\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + PAN(HS)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (numdiffprofile == 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (numdiffprofile >= 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n");
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+
+ return algorithm;
+}
+
+static void btc8723b1ant_set_sw_pen_tx_rate_adapt(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ u8 h2c_parameter[6] = {0};
+
+ h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty */
+
+ if (low_penalty_ra) {
+ h2c_parameter[1] |= BIT0;
+ /*normal rate except MCS7/6/5, OFDM54/48/36 */
+ h2c_parameter[2] = 0x00;
+ h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54 */
+ h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48 */
+ h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36 */
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set WiFi Low-Penalty Retry: %s",
+ (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8723b1ant_low_penalty_ra(struct btc_coexist *btcoexist,
+ bool force_exec, bool low_penalty_ra)
+{
+ coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+ if (!force_exec) {
+ if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+ return;
+ }
+ btc8723b1ant_set_sw_pen_tx_rate_adapt(btcoexist,
+ coex_dm->cur_low_penalty_ra);
+
+ coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8723b1ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8723b1ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec, u32 val0x6c0,
+ u32 val0x6c4, u32 val0x6c8,
+ u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6cc = 0x%x\n",
+ (force_exec ? "force to" : ""),
+ val0x6c0, val0x6c4, val0x6cc);
+ coex_dm->cur_val0x6c0 = val0x6c0;
+ coex_dm->cur_val0x6c4 = val0x6c4;
+ coex_dm->cur_val0x6c8 = val0x6c8;
+ coex_dm->cur_val0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+ (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+ (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+ (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+ return;
+ }
+ halbtc8723b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+
+ coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+ coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+ coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+ coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ switch (type) {
+ case 0:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x55555555, 0xffffff, 0x3);
+ break;
+ case 1:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 2:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 3:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0xaaaaaaaa, 0xffffff, 0x3);
+ break;
+ case 4:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5aaa5aaa, 0xffffff, 0x3);
+ break;
+ case 5:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0xaaaa5a5a, 0xffffff, 0x3);
+ break;
+ case 6:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0xaaaa5a5a, 0xffffff, 0x3);
+ break;
+ case 7:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa,
+ 0xaaaaaaaa, 0xffffff, 0x3);
+ break;
+ default:
+ break;
+ }
+}
+
+static void halbtc8723b1ant_SetFwIgnoreWlanAct(struct btc_coexist *btcoexist,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0; /* function enable */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8723b1ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n",
+ coex_dm->pre_ignore_wlan_act,
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ halbtc8723b1ant_SetFwIgnoreWlanAct(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8723b1ant_set_fw_ps_tdma(struct btc_coexist *btcoexist,
+ u8 byte1, u8 byte2, u8 byte3,
+ u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5] = {0};
+ u8 real_byte1 = byte1, real_byte5 = byte5;
+ bool ap_enable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ &ap_enable);
+
+ if (ap_enable) {
+ if ((byte1 & BIT4) && !(byte1 & BIT5)) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], FW for 1Ant AP mode\n");
+ real_byte1 &= ~BIT4;
+ real_byte1 |= BIT5;
+
+ real_byte5 |= BIT5;
+ real_byte5 &= ~BIT6;
+ }
+ }
+
+ h2c_parameter[0] = real_byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = real_byte5;
+
+ coex_dm->ps_tdma_para[0] = real_byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = real_byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1] << 24 |
+ h2c_parameter[2] << 16 |
+ h2c_parameter[3] << 8 |
+ h2c_parameter[4]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void halbtc8723b1ant_set_lps_rpwm(struct btc_coexist *btcoexist,
+ u8 lps_val, u8 rpwm_val)
+{
+ u8 lps = lps_val;
+ u8 rpwm = rpwm_val;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps);
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm);
+}
+
+static void halbtc8723b1ant_LpsRpwm(struct btc_coexist *btcoexist,
+ bool force_exec,
+ u8 lps_val, u8 rpwm_val)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n",
+ (force_exec ? "force to" : ""), lps_val, rpwm_val);
+ coex_dm->cur_lps = lps_val;
+ coex_dm->cur_rpwm = rpwm_val;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], LPS-RxBeaconMode = 0x%x , LPS-RPWM = 0x%x!!\n",
+ coex_dm->cur_lps, coex_dm->cur_rpwm);
+
+ if ((coex_dm->pre_lps == coex_dm->cur_lps) &&
+ (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], LPS-RPWM_Last = 0x%x , LPS-RPWM_Now = 0x%x!!\n",
+ coex_dm->pre_rpwm, coex_dm->cur_rpwm);
+
+ return;
+ }
+ }
+ halbtc8723b1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val);
+
+ coex_dm->pre_lps = coex_dm->cur_lps;
+ coex_dm->pre_rpwm = coex_dm->cur_rpwm;
+}
+
+static void halbtc8723b1ant_sw_mechanism(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra);
+
+ halbtc8723b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra);
+}
+
+static void halbtc8723b1ant_SetAntPath(struct btc_coexist *btcoexist,
+ u8 ant_pos_type, bool init_hw_cfg,
+ bool wifi_off)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 fw_ver = 0, u32tmp = 0;
+ bool pg_ext_switch = false;
+ bool use_ext_switch = false;
+ u8 h2c_parameter[2] = {0};
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch);
+ /* [31:16] = fw ver, [15:0] = fw sub ver */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+
+ if ((fw_ver < 0xc0000) || pg_ext_switch)
+ use_ext_switch = true;
+
+ if (init_hw_cfg) {
+ /*BT select s0/s1 is controlled by WiFi */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
+
+ /*Force GNT_BT to Normal */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
+ } else if (wifi_off) {
+ /*Force GNT_BT to High */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3);
+ /*BT select s0/s1 is controlled by BT */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0);
+
+ /* 0x4c[24:23] = 00, Set Antenna control by BT_RFE_CTRL
+ * BT Vendor 0xac = 0xf002
+ */
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp &= ~BIT23;
+ u32tmp &= ~BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+ }
+
+ if (use_ext_switch) {
+ if (init_hw_cfg) {
+ /* 0x4c[23] = 0, 0x4c[24] = 1
+ * Antenna control by WL/BT
+ */
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp &= ~BIT23;
+ u32tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT) {
+ /* Main Ant to BT for IPS case 0x4c[23] = 1 */
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x64, 0x1,
+ 0x1);
+
+ /*tell firmware "no antenna inverse"*/
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1; /*ext switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /*Aux Ant to BT for IPS case 0x4c[23] = 1 */
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x64, 0x1,
+ 0x0);
+
+ /*tell firmware "antenna inverse"*/
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1; /*ext switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* fixed internal switch first*/
+ /* fixed internal switch S1->WiFi, S0->BT*/
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+ else/* fixed internal switch S0->WiFi, S1->BT*/
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+
+ /* ext switch setting */
+ switch (ant_pos_type) {
+ case BTC_ANT_PATH_WIFI:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x1);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x2);
+ break;
+ case BTC_ANT_PATH_BT:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x2);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x1);
+ break;
+ default:
+ case BTC_ANT_PATH_PTA:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x1);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x2);
+ break;
+ }
+
+ } else {
+ if (init_hw_cfg) {
+ /* 0x4c[23] = 1, 0x4c[24] = 0 Antenna control by 0x64*/
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp |= BIT23;
+ u32tmp &= ~BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT) {
+ /*Main Ant to WiFi for IPS case 0x4c[23] = 1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x64, 0x1,
+ 0x0);
+
+ /*tell firmware "no antenna inverse"*/
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 0; /*internal switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /*Aux Ant to BT for IPS case 0x4c[23] = 1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x64, 0x1,
+ 0x1);
+
+ /*tell firmware "antenna inverse"*/
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 0; /*internal switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* fixed external switch first*/
+ /*Main->WiFi, Aux->BT*/
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+ 0x3, 0x1);
+ else/*Main->BT, Aux->WiFi */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+ 0x3, 0x2);
+
+ /* internal switch setting*/
+ switch (ant_pos_type) {
+ case BTC_ANT_PATH_WIFI:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x0);
+ else
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x280);
+ break;
+ case BTC_ANT_PATH_BT:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x280);
+ else
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x0);
+ break;
+ default:
+ case BTC_ANT_PATH_PTA:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x200);
+ else
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x80);
+ break;
+ }
+ }
+}
+
+static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist,
+ bool force_exec, bool turn_on, u8 type)
+{
+ bool wifi_busy = false;
+ u8 rssi_adjust_val = 0;
+
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (!force_exec) {
+ if (coex_dm->cur_ps_tdma_on)
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ******** TDMA(on, %d) *********\n",
+ coex_dm->cur_ps_tdma);
+ else
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ******** TDMA(off, %d) ********\n",
+ coex_dm->cur_ps_tdma);
+
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ default:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1a,
+ 0x1a, 0x0, 0x50);
+ break;
+ case 1:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x3a,
+ 0x03, 0x10, 0x50);
+
+ rssi_adjust_val = 11;
+ break;
+ case 2:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x2b,
+ 0x03, 0x10, 0x50);
+ rssi_adjust_val = 14;
+ break;
+ case 3:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1d,
+ 0x1d, 0x0, 0x52);
+ break;
+ case 4:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15,
+ 0x3, 0x14, 0x0);
+ rssi_adjust_val = 17;
+ break;
+ case 5:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15,
+ 0x3, 0x11, 0x10);
+ break;
+ case 6:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20,
+ 0x3, 0x11, 0x13);
+ break;
+ case 7:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc,
+ 0x5, 0x0, 0x0);
+ break;
+ case 8:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25,
+ 0x3, 0x10, 0x0);
+ break;
+ case 9:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21,
+ 0x3, 0x10, 0x50);
+ rssi_adjust_val = 18;
+ break;
+ case 10:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa,
+ 0xa, 0x0, 0x40);
+ break;
+ case 11:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15,
+ 0x03, 0x10, 0x50);
+ rssi_adjust_val = 20;
+ break;
+ case 12:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x0a,
+ 0x0a, 0x0, 0x50);
+ break;
+ case 13:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15,
+ 0x15, 0x0, 0x50);
+ break;
+ case 14:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21,
+ 0x3, 0x10, 0x52);
+ break;
+ case 15:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa,
+ 0x3, 0x8, 0x0);
+ break;
+ case 16:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15,
+ 0x3, 0x10, 0x0);
+ rssi_adjust_val = 18;
+ break;
+ case 18:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25,
+ 0x3, 0x10, 0x0);
+ rssi_adjust_val = 14;
+ break;
+ case 20:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35,
+ 0x03, 0x11, 0x10);
+ break;
+ case 21:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25,
+ 0x03, 0x11, 0x11);
+ break;
+ case 22:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25,
+ 0x03, 0x11, 0x10);
+ break;
+ case 23:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 24:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 25:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 26:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 27:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+ 0x3, 0x31, 0x98);
+ rssi_adjust_val = 22;
+ break;
+ case 28:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x69, 0x25,
+ 0x3, 0x31, 0x0);
+ break;
+ case 29:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xab, 0x1a,
+ 0x1a, 0x1, 0x10);
+ break;
+ case 30:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14,
+ 0x3, 0x10, 0x50);
+ break;
+ case 31:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a,
+ 0x1a, 0, 0x58);
+ break;
+ case 32:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa,
+ 0x3, 0x10, 0x0);
+ break;
+ case 33:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25,
+ 0x3, 0x30, 0x90);
+ break;
+ case 34:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x53, 0x1a,
+ 0x1a, 0x0, 0x10);
+ break;
+ case 35:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x63, 0x1a,
+ 0x1a, 0x0, 0x10);
+ break;
+ case 36:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12,
+ 0x3, 0x14, 0x50);
+ break;
+ /* SoftAP only with no sta associated,BT disable ,
+ * TDMA mode for power saving
+ * here softap mode screen off will cost 70-80mA for phone
+ */
+ case 40:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18,
+ 0x00, 0x10, 0x24);
+ break;
+ }
+ } else {
+ switch (type) {
+ case 8: /*PTA Control */
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x8, 0x0,
+ 0x0, 0x0, 0x0);
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA,
+ false, false);
+ break;
+ case 0:
+ default: /*Software control, Antenna at BT side */
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0,
+ 0x0, 0x0, 0x0);
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT,
+ false, false);
+ break;
+ case 9: /*Software control, Antenna at WiFi side */
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0,
+ 0x0, 0x0, 0x0);
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_WIFI,
+ false, false);
+ break;
+ }
+ }
+ rssi_adjust_val = 0;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
+ &rssi_adjust_val);
+
+ /* update pre state */
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static bool halbtc8723b1ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ bool commom = false, wifi_connected = false;
+ bool wifi_busy = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (!wifi_connected &&
+ BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n");
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else if (wifi_connected &&
+ (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + BT non connected-idle!!\n");
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else if (!wifi_connected &&
+ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n");
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else if (wifi_connected &&
+ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + BT connected-idle!!\n");
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else if (!wifi_connected &&
+ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE !=
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ ("[BTCoex], Wifi non connected-idle + BT Busy!!\n"));
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else {
+ if (wifi_busy)
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Busy + BT Busy!!\n");
+ else
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Idle + BT Busy!!\n");
+
+ commom = false;
+ }
+
+ return commom;
+}
+
+static void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ static s32 up, dn, m, n, wait_count;
+ /* 0: no change, +1: increase WiFi duration,
+ * -1: decrease WiFi duration
+ */
+ s32 result;
+ u8 retry_count = 0, bt_info_ext;
+ bool wifi_busy = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjustForAcl()\n");
+
+ if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status)
+ wifi_busy = true;
+ else
+ wifi_busy = false;
+
+ if ((BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+ wifi_status) ||
+ (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) ||
+ (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifi_status)) {
+ if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 &&
+ coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ }
+ return;
+ }
+
+ if (!coex_dm->auto_tdma_adjust) {
+ coex_dm->auto_tdma_adjust = true;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+ coex_dm->tdma_adj_type = 2;
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ } else {
+ /*accquire the BT TRx retry count from BT_Info byte2 */
+ retry_count = coex_sta->bt_retry_cnt;
+ bt_info_ext = coex_sta->bt_info_ext;
+ result = 0;
+ wait_count++;
+ /* no retry in the last 2-second duration */
+ if (retry_count == 0) {
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ wait_count = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Increase wifi duration!!\n");
+ }
+ } else if (retry_count <= 3) {
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ if (wait_count <= 2)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3 * m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+ }
+ } else {
+ if (wait_count == 1)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3 * m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+ }
+
+ if (result == -1) {
+ if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+ ((coex_dm->cur_ps_tdma == 1) ||
+ (coex_dm->cur_ps_tdma == 2))) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ } else if (result == 1) {
+ if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+ ((coex_dm->cur_ps_tdma == 1) ||
+ (coex_dm->cur_ps_tdma == 2))) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ }
+ } else { /*no change */
+ /*if busy / idle change */
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex],********* TDMA(on, %d) ********\n",
+ coex_dm->cur_ps_tdma);
+ }
+
+ if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 &&
+ coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) {
+ /* recover to previous adjust type */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
+ coex_dm->tdma_adj_type);
+ }
+ }
+}
+
+static void btc8723b1ant_pstdmachkpwrsave(struct btc_coexist *btcoexist,
+ bool new_ps_state)
+{
+ u8 lps_mode = 0x0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode);
+
+ if (lps_mode) { /* already under LPS state */
+ if (new_ps_state) {
+ /* keep state under LPS, do nothing. */
+ } else {
+ /* will leave LPS state, turn off psTdma first */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ }
+ } else { /* NO PS state */
+ if (new_ps_state) {
+ /* will enter LPS state, turn off psTdma first */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ } else {
+ /* keep state under NO PS state, do nothing. */
+ }
+ }
+}
+
+static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist,
+ u8 ps_type, u8 lps_val,
+ u8 rpwm_val)
+{
+ bool low_pwr_disable = false;
+
+ switch (ps_type) {
+ case BTC_PS_WIFI_NATIVE:
+ /* recover to original 32k low power setting */
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL);
+ break;
+ case BTC_PS_LPS_ON:
+ btc8723b1ant_pstdmachkpwrsave(btcoexist, true);
+ halbtc8723b1ant_LpsRpwm(btcoexist, NORMAL_EXEC, lps_val,
+ rpwm_val);
+ /* when coex force to enter LPS, do not enter 32k low power. */
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ /* power save must executed before psTdma. */
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL);
+ break;
+ case BTC_PS_LPS_OFF:
+ btc8723b1ant_pstdmachkpwrsave(btcoexist, false);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+/***************************************************
+ *
+ * Software Coex Mechanism start
+ *
+ ***************************************************/
+/* SCO only or SCO+PAN(HS) */
+static void halbtc8723b1ant_action_sco(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8723b1ant_action_hid(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8723b1ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+/* PAN(HS) only */
+static void halbtc8723b1ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(EDR)+A2DP */
+static void halbtc8723b1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8723b1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8723b1ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/*****************************************************
+ *
+ * Non-Software Coex Mechanism start
+ *
+ *****************************************************/
+static void halbtc8723b1ant_action_wifi_multiport(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+}
+
+static void halbtc8723b1ant_action_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+}
+
+static void halbtc8723b1ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false, ap_enable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ &ap_enable);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ if (!wifi_connected) {
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+ } else if (bt_link_info->sco_exist || bt_link_info->hid_only) {
+ /* SCO/HID-only busy */
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else {
+ if (ap_enable)
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ else
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_LPS_ON,
+ 0x50, 0x4);
+
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void btc8723b1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ /* tdma and coex table */
+
+ if (bt_link_info->sco_exist) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+ } else { /* HID */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5);
+ }
+}
+
+static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy(
+ struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ u8 bt_rssi_state;
+
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 28, 0);
+
+ if (bt_link_info->hid_only) { /*HID */
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, wifi_status);
+ coex_dm->auto_tdma_adjust = false;
+ return;
+ } else if (bt_link_info->a2dp_only) { /*A2DP */
+ if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ coex_dm->auto_tdma_adjust = false;
+ } else if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b1ant_tdma_dur_adj_for_acl(btcoexist,
+ wifi_status);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ } else { /*for low BT RSSI */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ }
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) { /*HID+A2DP */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->auto_tdma_adjust = false;
+ } else { /*for low BT RSSI*/
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->auto_tdma_adjust = false;
+ }
+
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6);
+ /*PAN(OPP,FTP), HID+PAN(OPP,FTP) */
+ } else if (bt_link_info->pan_only ||
+ (bt_link_info->hid_exist && bt_link_info->pan_exist)) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6);
+ coex_dm->auto_tdma_adjust = false;
+ /*A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP)*/
+ } else if ((bt_link_info->a2dp_exist && bt_link_info->pan_exist) ||
+ (bt_link_info->hid_exist && bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist)) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ }
+}
+
+static void btc8723b1ant_action_wifi_not_conn(struct btc_coexist *btcoexist)
+{
+ /* power save state */
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoex)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoex->bt_link_info;
+
+ halbtc8723b1ant_power_save_state(btcoex, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table */
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+ true, 22);
+ halbtc8723b1ant_coex_table_with_type(btcoex,
+ NORMAL_EXEC, 1);
+ } else if (bt_link_info->pan_only) {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+ true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoex,
+ NORMAL_EXEC, 2);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+ true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoex,
+ NORMAL_EXEC, 1);
+ }
+ } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)){
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoex,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 2);
+ }
+}
+
+static void btc8723b1ant_act_wifi_not_conn_asso_auth(struct btc_coexist *btcoex)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoex->bt_link_info;
+
+ halbtc8723b1ant_power_save_state(btcoex, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ||
+ (bt_link_info->sco_exist) || (bt_link_info->hid_only) ||
+ (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 7);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 1);
+ }
+}
+
+static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table */
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 22);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ } else if (bt_link_info->pan_only) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ }
+ } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+ }
+}
+
+static void halbtc8723b1ant_action_wifi_connected_special_packet(
+ struct btc_coexist *btcoexist)
+{
+ bool hs_connecting = false;
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting);
+
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table */
+ if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ||
+ (bt_link_info->sco_exist) || (bt_link_info->hid_only) ||
+ (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist)
+{
+ bool wifi_busy = false;
+ bool scan = false, link = false, roam = false;
+ bool under_4way = false, ap_enable = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect()===>\n");
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+ &under_4way);
+ if (under_4way) {
+ halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (scan || link || roam) {
+ if (scan)
+ btc8723b1ant_action_wifi_conn_scan(btcoexist);
+ else
+ halbtc8723b1ant_action_wifi_connected_special_packet(
+ btcoexist);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ &ap_enable);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ /* power save state */
+ if (!ap_enable &&
+ BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status &&
+ !btcoexist->bt_link_info.hid_only) {
+ if (!wifi_busy && btcoexist->bt_link_info.a2dp_only)
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ else
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_LPS_ON,
+ 0x50, 0x4);
+ } else {
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ }
+ /* tdma and coex table */
+ if (!wifi_busy) {
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+ } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ }
+ } else {
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+ } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ }
+ }
+}
+
+static void btc8723b1ant_run_sw_coex_mech(struct btc_coexist *btcoexist)
+{
+ u8 algorithm = 0;
+
+ algorithm = halbtc8723b1ant_action_algorithm(btcoexist);
+ coex_dm->cur_algorithm = algorithm;
+
+ if (!halbtc8723b1ant_is_common_action(btcoexist)) {
+ switch (coex_dm->cur_algorithm) {
+ case BT_8723B_1ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = SCO.\n");
+ halbtc8723b1ant_action_sco(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID.\n");
+ halbtc8723b1ant_action_hid(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = A2DP.\n");
+ halbtc8723b1ant_action_a2dp(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = A2DP+PAN(HS).\n");
+ halbtc8723b1ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN(EDR).\n");
+ halbtc8723b1ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HS mode.\n");
+ halbtc8723b1ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN+A2DP.\n");
+ halbtc8723b1ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN(EDR)+HID.\n");
+ halbtc8723b1ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID+A2DP+PAN.\n");
+ btc8723b1ant_action_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID+A2DP.\n");
+ halbtc8723b1ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = coexist All Off!!\n");
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false, bt_hs_on = false;
+ bool increase_scan_dev_num = false;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+ u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_link_status = 0;
+ u32 num_of_wifi_link = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism()===>\n");
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n");
+ return;
+ }
+
+ if (btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n");
+ return;
+ }
+
+ if (coex_sta->under_ips) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is under IPS !!!\n");
+ return;
+ }
+
+ if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) {
+ increase_scan_dev_num = true;
+ }
+
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM,
+ &increase_scan_dev_num);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ num_of_wifi_link = wifi_link_status >> 16;
+ if (num_of_wifi_link >= 2) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size,
+ agg_buf_size);
+ halbtc8723b1ant_action_wifi_multiport(btcoexist);
+ return;
+ }
+
+ if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ } else {
+ if (wifi_connected) {
+ wifi_rssi_state =
+ halbtc8723b1ant_wifi_rssi_state(btcoexist,
+ 1, 2, 30, 0);
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8723b1ant_limited_tx(btcoexist,
+ NORMAL_EXEC,
+ 1, 1, 1, 1);
+ } else {
+ halbtc8723b1ant_limited_tx(btcoexist,
+ NORMAL_EXEC,
+ 1, 1, 1, 1);
+ }
+ } else {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC,
+ 0, 0, 0, 0);
+ }
+ }
+
+ if (bt_link_info->sco_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x3;
+ } else if (bt_link_info->hid_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x5;
+ } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x8;
+ }
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+
+ btc8723b1ant_run_sw_coex_mech(btcoexist);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8723b1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8723b1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (!wifi_connected) {
+ bool scan = false, link = false, roam = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is non connected-idle !!!\n");
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (scan || link || roam) {
+ if (scan)
+ btc8723b1ant_action_wifi_not_conn_scan(
+ btcoexist);
+ else
+ btc8723b1ant_act_wifi_not_conn_asso_auth(
+ btcoexist);
+ } else {
+ btc8723b1ant_action_wifi_not_conn(btcoexist);
+ }
+ } else { /* wifi LPS/Busy */
+ halbtc8723b1ant_action_wifi_connected(btcoexist);
+ }
+}
+
+static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* sw all off */
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+
+ halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist,
+ bool backup)
+{
+ u32 u32tmp = 0;
+ u8 u8tmp = 0;
+ u32 cnt_bt_cal_chk = 0;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 1Ant Init HW Config!!\n");
+
+ if (backup) {/* backup rf 0x1e value */
+ coex_dm->backup_arfr_cnt1 =
+ btcoexist->btc_read_4byte(btcoexist, 0x430);
+ coex_dm->backup_arfr_cnt2 =
+ btcoexist->btc_read_4byte(btcoexist, 0x434);
+ coex_dm->backup_retry_limit =
+ btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ coex_dm->backup_ampdu_max_time =
+ btcoexist->btc_read_1byte(btcoexist, 0x456);
+ }
+
+ /* WiFi goto standby while GNT_BT 0-->1 */
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780);
+ /* BT goto standby while GNT_BT 1-->0 */
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x500);
+
+ btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
+ btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
+
+ /* BT calibration check */
+ while (cnt_bt_cal_chk <= 20) {
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x49d);
+ cnt_bt_cal_chk++;
+ if (u32tmp & BIT0) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ########### BT calibration(cnt=%d) ###########\n",
+ cnt_bt_cal_chk);
+ mdelay(50);
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ********** BT NOT calibration (cnt=%d)**********\n",
+ cnt_bt_cal_chk);
+ break;
+ }
+ }
+
+ /* 0x790[5:0] = 0x5 */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u8tmp &= 0xc0;
+ u8tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
+
+ /* Enable counter statistics */
+ /*0x76e[3] =1, WLAN_Act control by PTA */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+
+ /*Antenna config */
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA, true, false);
+ /* PTA parameter */
+ halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8723b1ant_wifi_off_hw_cfg(struct btc_coexist *btcoexist)
+{
+ /* set wlan_act to low */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+}
+
+/**************************************************************
+ * work around function start with wa_halbtc8723b1ant_
+ **************************************************************/
+/**************************************************************
+ * extern function start with EXhalbtc8723b1ant_
+ **************************************************************/
+
+void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_init_hw_config(btcoexist, true);
+}
+
+void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+
+ btcoexist->stop_coex_dm = false;
+
+ halbtc8723b1ant_init_coex_dm(btcoexist);
+
+ halbtc8723b1ant_query_bt_info(btcoexist);
+}
+
+void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ u8 *cli_buf = btcoexist->cli_buf;
+ u8 u8tmp[4], i, bt_info_ext, pstdmacase = 0;
+ u16 u16tmp[4];
+ u32 u32tmp[4];
+ bool roam = false, scan = false;
+ bool link = false, wifi_under_5g = false;
+ bool bt_hs_on = false, wifi_busy = false;
+ s32 wifi_rssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck, wifi_link_status;
+ u8 wifi_dot11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[BT Coexist info]============");
+ CL_PRINTF(cli_buf);
+
+ if (btcoexist->manual_control) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[Under Manual Control]==========");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ==========================================");
+ CL_PRINTF(cli_buf);
+ }
+ if (btcoexist->stop_coex_dm) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[Coex is STOPPED]============");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ==========================================");
+ CL_PRINTF(cli_buf);
+ }
+
+ if (!board_info->bt_exist) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
+ CL_PRINTF(cli_buf);
+ return;
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d",
+ "Ant PG Num/ Ant Mech/ Ant Pos:",
+ board_info->pg_ant_num, board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d",
+ "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8723b_1ant, glcoex_ver_8723b_1ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+ &wifi_dot11_chnl);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsChnl(HsMode)",
+ wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info",
+ coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+ coex_dm->wifi_chnl_info[2]);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+ "Wifi link/ roam/ scan", link, roam, scan);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist , BTC_GET_BL_WIFI_UNDER_5G,
+ &wifi_under_5g);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+ &wifi_traffic_dir);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ",
+ "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d",
+ "sta/vwifi/hs/p2pGo/p2pGc",
+ ((wifi_link_status & WIFI_STA_CONNECTED) ? 1 : 0),
+ ((wifi_link_status & WIFI_AP_CONNECTED) ? 1 : 0),
+ ((wifi_link_status & WIFI_HS_CONNECTED) ? 1 : 0),
+ ((wifi_link_status & WIFI_P2P_GO_CONNECTED) ? 1 : 0),
+ ((wifi_link_status & WIFI_P2P_GC_CONNECTED) ? 1 : 0));
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ",
+ "BT [status/ rssi/ retryCnt]",
+ ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+ ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+ ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) ?
+ "non-connected idle" :
+ ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) ?
+ "connected-idle" : "busy")))),
+ coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d / %d / %d / %d",
+ "SCO/HID/PAN/A2DP", bt_link_info->sco_exist,
+ bt_link_info->hid_exist, bt_link_info->pan_exist,
+ bt_link_info->a2dp_exist);
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext & BIT0) ? "Basic rate" : "EDR rate");
+ CL_PRINTF(cli_buf);
+
+ for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+ GLBtInfoSrc8723b1Ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3],
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ CL_PRINTF(cli_buf);
+ }
+ }
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %s/%s, (0x%x/0x%x)",
+ "PS state, IPS/LPS, (lps/rpwm)",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")),
+ btcoexist->bt_info.lps_val,
+ btcoexist->bt_info.rpwm_val);
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ if (!btcoexist->manual_control) {
+ /* Sw mechanism */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Sw mechanism]============");
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/",
+ "SM[LowPenaltyRA]", coex_dm->cur_low_penalty_ra);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ",
+ "DelBA/ BtCtrlAgg/ AggSize",
+ (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"),
+ (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"),
+ btcoexist->bt_info.agg_buf_size);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ",
+ "Rate Mask", btcoexist->bt_info.ra_mask);
+ CL_PRINTF(cli_buf);
+
+ /* Fw mechanism */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Fw mechanism]============");
+ CL_PRINTF(cli_buf);
+
+ pstdmacase = coex_dm->cur_ps_tdma;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+ "PS TDMA", coex_dm->ps_tdma_para[0],
+ coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
+ coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
+ pstdmacase, coex_dm->auto_tdma_adjust);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ",
+ "IgnWlanAct", coex_dm->cur_ignore_wlan_act);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ",
+ "Latest error condition(should be 0)",
+ coex_dm->error_condition);
+ CL_PRINTF(cli_buf);
+ }
+
+ /* Hw setting */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Hw setting]============");
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1,
+ coex_dm->backup_arfr_cnt2, coex_dm->backup_retry_limit,
+ coex_dm->backup_ampdu_max_time);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+ u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "0x430/0x434/0x42a/0x456",
+ u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x778/0x6cc/0x880[29:25]", u8tmp[0], u32tmp[0],
+ (u32tmp[1] & 0x3e000000) >> 25);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x948/ 0x67[5] / 0x765",
+ u32tmp[0], ((u8tmp[0] & 0x20) >> 5), u8tmp[1]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]",
+ u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3);
+ CL_PRINTF(cli_buf);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+ "0x38[11]/0x40/0x4c[24:23]/0x64[0]",
+ ((u8tmp[0] & 0x8)>>3), u8tmp[1],
+ ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0xc50(dig)/0x49c(null-drop)", u32tmp[0] & 0xff, u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8);
+ u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+
+ fa_ofdm = ((u32tmp[0] & 0xffff0000) >> 16) +
+ ((u32tmp[1] & 0xffff0000) >> 16) +
+ (u32tmp[1] & 0xffff) +
+ (u32tmp[2] & 0xffff) +
+ ((u32tmp[3] & 0xffff0000) >> 16) +
+ (u32tmp[3] & 0xffff);
+ fa_cck = (u8tmp[0] << 8) + u8tmp[1];
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "OFDM-CCA/OFDM-FA/CCK-FA",
+ u32tmp[0] & 0xffff, fa_ofdm, fa_cck);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8(coexTable)",
+ u32tmp[0], u32tmp[1], u32tmp[2]);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "0x770(high-pri rx/tx)", coex_sta->high_priority_rx,
+ coex_sta->high_priority_tx);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "0x774(low-pri rx/tx)", coex_sta->low_priority_rx,
+ coex_sta->low_priority_tx);
+ CL_PRINTF(cli_buf);
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1)
+ halbtc8723b1ant_monitor_bt_ctr(btcoexist);
+#endif
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+ return;
+
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT,
+ false, true);
+ /* set PTA control */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 0);
+ halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+
+ halbtc8723b1ant_init_hw_config(btcoexist, false);
+ halbtc8723b1ant_init_coex_dm(btcoexist);
+ halbtc8723b1ant_query_bt_info(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+ return;
+
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_lps = false;
+ }
+}
+
+void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ bool wifi_connected = false, bt_hs_on = false;
+ u32 wifi_link_status = 0;
+ u32 num_of_wifi_link = 0;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ halbtc8723b1ant_query_bt_info(btcoexist);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ num_of_wifi_link = wifi_link_status >> 16;
+ if (num_of_wifi_link >= 2) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+ halbtc8723b1ant_action_wifi_multiport(btcoexist);
+ return;
+ }
+
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8723b1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8723b1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_SCAN_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ if (!wifi_connected) /* non-connected scan */
+ btc8723b1ant_action_wifi_not_conn_scan(btcoexist);
+ else /* wifi is connected */
+ btc8723b1ant_action_wifi_conn_scan(btcoexist);
+ } else if (BTC_SCAN_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+ if (!wifi_connected) /* non-connected scan */
+ btc8723b1ant_action_wifi_not_conn(btcoexist);
+ else
+ halbtc8723b1ant_action_wifi_connected(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ bool wifi_connected = false, bt_hs_on = false;
+ u32 wifi_link_status = 0;
+ u32 num_of_wifi_link = 0;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ num_of_wifi_link = wifi_link_status>>16;
+ if (num_of_wifi_link >= 2) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+ halbtc8723b1ant_action_wifi_multiport(btcoexist);
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8723b1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8723b1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_ASSOCIATE_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ btc8723b1ant_act_wifi_not_conn_asso_auth(btcoexist);
+ } else if (BTC_ASSOCIATE_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (!wifi_connected) /* non-connected scan */
+ btc8723b1ant_action_wifi_not_conn(btcoexist);
+ else
+ halbtc8723b1ant_action_wifi_connected(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifiCentralChnl;
+
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ if (BTC_MEDIA_CONNECT == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+
+ /* only 2.4G we need to inform bt the chnl mask */
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ &wifiCentralChnl);
+
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifiCentralChnl <= 14)) {
+ h2c_parameter[0] = 0x0;
+ h2c_parameter[1] = wifiCentralChnl;
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66 = 0x%x\n",
+ h2c_parameter[0] << 16 | h2c_parameter[1] << 8 |
+ h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ bool bt_hs_on = false;
+ u32 wifi_link_status = 0;
+ u32 num_of_wifi_link = 0;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ num_of_wifi_link = wifi_link_status >> 16;
+ if (num_of_wifi_link >= 2) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+ halbtc8723b1ant_action_wifi_multiport(btcoexist);
+ return;
+ }
+
+ coex_sta->special_pkt_period_cnt = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8723b1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8723b1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_PACKET_DHCP == type ||
+ BTC_PACKET_EAPOL == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], special Packet(%d) notify\n", type);
+ halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ bool wifi_connected = false;
+ bool bt_busy = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ rsp_source = tmp_buf[0] & 0xf;
+ if (rsp_source >= BT_INFO_SRC_8723B_1ANT_MAX)
+ rsp_source = BT_INFO_SRC_8723B_1ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length=%d, hex data = [",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+ if (i == 1)
+ bt_info = tmp_buf[i];
+ if (i == length - 1)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmp_buf[i]);
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmp_buf[i]);
+ }
+
+ if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0] */
+ coex_sta->bt_info_c2h[rsp_source][2] & 0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT
+ * because bt is reset and loss of the info.
+ */
+ if (coex_sta->bt_info_ext & BIT1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n");
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (wifi_connected)
+ ex_halbtc8723b1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_CONNECT);
+ else
+ ex_halbtc8723b1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+
+ if (coex_sta->bt_info_ext & BIT3) {
+ if (!btcoexist->manual_control &&
+ !btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit3 check, set BT NOT ignore Wlan active!!\n");
+ halbtc8723b1ant_ignore_wlan_act(btcoexist,
+ FORCE_EXEC,
+ false);
+ }
+ } else {
+ /* BT already NOT ignore Wlan active, do nothing here.*/
+ }
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0)
+ if (coex_sta->bt_info_ext & BIT4) {
+ /* BT auto report already enabled, do nothing */
+ } else {
+ halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC,
+ true);
+ }
+#endif
+ }
+
+ /* check BIT2 first ==> check if bt is under inquiry or page scan */
+ if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE)
+ coex_sta->c2h_bt_inquiry_page = true;
+ else
+ coex_sta->c2h_bt_inquiry_page = false;
+
+ /* set link exist status */
+ if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ } else { /* connection exists */
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8723B_1ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8723B_1ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8723B_1ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ }
+
+ halbtc8723b1ant_update_bt_link_info(btcoexist);
+
+ if (!(bt_info&BT_INFO_8723B_1ANT_B_CONNECTION)) {
+ coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Non-Connected idle!\n");
+ /* connection exists but no busy */
+ } else if (bt_info == BT_INFO_8723B_1ANT_B_CONNECTION) {
+ coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n");
+ } else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) ||
+ (bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) {
+ coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_SCO_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
+ } else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) {
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status)
+ coex_dm->auto_tdma_adjust = false;
+
+ coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_ACL_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
+ } else {
+ coex_dm->bt_status =
+ BT_8723B_1ANT_BT_STATUS_MAX;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Non-Defined state!!\n");
+ }
+
+ if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+ bt_busy = true;
+ else
+ bt_busy = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ halbtc8723b1ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+
+ btcoexist->stop_coex_dm = true;
+
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false, true);
+
+ halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+ halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+
+ ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Pnp notify\n");
+
+ if (BTC_WIFI_PNP_SLEEP == pnp_state) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify to SLEEP\n");
+ btcoexist->stop_coex_dm = true;
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false,
+ true);
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+ halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+ } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify to WAKE UP\n");
+ btcoexist->stop_coex_dm = false;
+ halbtc8723b1ant_init_hw_config(btcoexist, false);
+ halbtc8723b1ant_init_coex_dm(btcoexist);
+ halbtc8723b1ant_query_bt_info(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], *****************Coex DM Reset****************\n");
+
+ halbtc8723b1ant_init_hw_config(btcoexist, false);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0);
+ halbtc8723b1ant_init_coex_dm(btcoexist);
+}
+
+void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], ==========================Periodical===========================\n");
+
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+ board_info->pg_ant_num, board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8723b_1ant,
+ glcoex_ver_8723b_1ant, fw_ver,
+ bt_patch_ver, bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0)
+ halbtc8723b1ant_query_bt_info(btcoexist);
+ halbtc8723b1ant_monitor_bt_ctr(btcoexist);
+ halbtc8723b1ant_monitor_bt_enable_disable(btcoexist);
+#else
+ if (btc8723b1ant_is_wifi_status_changed(btcoexist) ||
+ coex_dm->auto_tdma_adjust) {
+ halbtc8723b1ant_run_coexist_mechanism(btcoexist);
+ }
+
+ coex_sta->special_pkt_period_cnt++;
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h
new file mode 100644
index 0000000..75f8094
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h
@@ -0,0 +1,184 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/**********************************************************************
+ * The following is for 8723B 1ANT BT Co-exist definition
+ **********************************************************************/
+#define BT_AUTO_REPORT_ONLY_8723B_1ANT 1
+
+#define BT_INFO_8723B_1ANT_B_FTP BIT7
+#define BT_INFO_8723B_1ANT_B_A2DP BIT6
+#define BT_INFO_8723B_1ANT_B_HID BIT5
+#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8723B_1ANT_B_CONNECTION BIT0
+
+#define BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \
+ (((_BT_INFO_EXT_&BIT0)) ? true : false)
+
+#define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2
+
+enum _BT_INFO_SRC_8723B_1ANT {
+ BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8723B_1ANT_MAX
+};
+
+enum _BT_8723B_1ANT_BT_STATUS {
+ BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1,
+ BT_8723B_1ANT_BT_STATUS_INQ_PAGE = 0x2,
+ BT_8723B_1ANT_BT_STATUS_ACL_BUSY = 0x3,
+ BT_8723B_1ANT_BT_STATUS_SCO_BUSY = 0x4,
+ BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5,
+ BT_8723B_1ANT_BT_STATUS_MAX
+};
+
+enum _BT_8723B_1ANT_WIFI_STATUS {
+ BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5,
+ BT_8723B_1ANT_WIFI_STATUS_MAX
+};
+
+enum _BT_8723B_1ANT_COEX_ALGO {
+ BT_8723B_1ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8723B_1ANT_COEX_ALGO_SCO = 0x1,
+ BT_8723B_1ANT_COEX_ALGO_HID = 0x2,
+ BT_8723B_1ANT_COEX_ALGO_A2DP = 0x3,
+ BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4,
+ BT_8723B_1ANT_COEX_ALGO_PANEDR = 0x5,
+ BT_8723B_1ANT_COEX_ALGO_PANHS = 0x6,
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7,
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID = 0x8,
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9,
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP = 0xa,
+ BT_8723B_1ANT_COEX_ALGO_MAX = 0xb,
+};
+
+struct coex_dm_8723b_1ant {
+ /* fw mechanism */
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool auto_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+ u8 pre_lps;
+ u8 cur_lps;
+ u8 pre_rpwm;
+ u8 cur_rpwm;
+
+ /* sw mechanism */
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ u32 pre_val0x6c0;
+ u32 cur_val0x6c0;
+ u32 pre_val0x6c4;
+ u32 cur_val0x6c4;
+ u32 pre_val0x6c8;
+ u32 cur_val0x6c8;
+ u8 pre_val0x6cc;
+ u8 cur_val0x6cc;
+ bool limited_dig;
+
+ u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */
+ u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */
+ u16 backup_retry_limit;
+ u8 backup_ampdu_max_time;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+
+ u32 prera_mask;
+ u32 curra_mask;
+ u8 pre_arfr_type;
+ u8 cur_arfr_type;
+ u8 pre_retry_limit_type;
+ u8 cur_retry_limit_type;
+ u8 pre_ampdu_time_type;
+ u8 cur_ampdu_time_type;
+
+ u8 error_condition;
+};
+
+struct coex_sta_8723b_1ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+
+ bool under_lps;
+ bool under_ips;
+ u32 special_pkt_period_cnt;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/*************************************************************************
+ * The following is interface which will notify coex module.
+ *************************************************************************/
+void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate);
+void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
index d916ab9..bd37d65 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
@@ -49,8 +49,8 @@ static const char *const glbt_info_src_8723b_2ant[] = {
"BT Info[bt auto report]",
};
-static u32 glcoex_ver_date_8723b_2ant = 20130731;
-static u32 glcoex_ver_8723b_2ant = 0x3b;
+static u32 glcoex_ver_date_8723b_2ant = 20131113;
+static u32 glcoex_ver_8723b_2ant = 0x3f;
/**************************************************************
* local function proto type if needed
@@ -303,6 +303,21 @@ static void btc8723b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
}
+static void btc8723b2ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
{
static bool pre_wifi_busy;
@@ -604,7 +619,7 @@ static bool btc8723b_need_dec_pwr(struct btc_coexist *btcoexist)
if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi))
return false;
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
if (wifi_connected) {
if (bt_hs_on) {
@@ -824,7 +839,6 @@ static void btc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoex,
btc8723b2ant_set_dac_swing_reg(btcoex, 0x18);
}
-
static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist,
bool force_exec, bool dac_swing_on,
u32 dac_swing_lvl)
@@ -884,7 +898,6 @@ static void btc8723b2ant_set_agc_table(struct btc_coexist *btcoexist,
btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001);
}
-
/* RF Gain */
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000);
if (agc_table_en) {
@@ -1160,8 +1173,87 @@ static void btc8723b2ant_sw_mechanism2(struct btc_coexist *btcoexist,
dac_swing_lvl);
}
+static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist,
+ u8 antpos_type, bool init_hwcfg,
+ bool wifi_off)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 fw_ver = 0, u32tmp = 0;
+ bool pg_ext_switch = false;
+ bool use_ext_switch = false;
+ u8 h2c_parameter[2] = {0};
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+
+ if ((fw_ver < 0xc0000) || pg_ext_switch)
+ use_ext_switch = true;
+
+ if (init_hwcfg) {
+ /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT */
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp &= ~BIT23;
+ u32tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+ btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
+ btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
+
+ /* Force GNT_BT to low */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+ /* tell firmware "no antenna inverse" */
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1; /* ext switch type */
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /* tell firmware "antenna inverse" */
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1; /* ext switch type */
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* ext switch setting */
+ if (use_ext_switch) {
+ /* fixed internal switch S1->WiFi, S0->BT */
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+ switch (antpos_type) {
+ case BTC_ANT_WIFI_AT_MAIN:
+ /* ext switch main at wifi */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+ 0x3, 0x1);
+ break;
+ case BTC_ANT_WIFI_AT_AUX:
+ /* ext switch aux at wifi */
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3, 0x2);
+ break;
+ }
+ } else { /* internal switch */
+ /* fixed ext switch */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1);
+ switch (antpos_type) {
+ case BTC_ANT_WIFI_AT_MAIN:
+ /* fixed internal switch S1->WiFi, S0->BT */
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+ break;
+ case BTC_ANT_WIFI_AT_AUX:
+ /* fixed internal switch S0->WiFi, S1->BT */
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+ break;
+ }
+ }
+}
+
static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec,
- bool turn_on, u8 type)
+ bool turn_on, u8 type)
{
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
"[BTCoex], %s turn %s PS TDMA, type=%d\n",
@@ -1351,7 +1443,8 @@ static void btc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
coex_dm->need_recover_0x948 = true;
coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948);
- btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+ btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_AUX,
+ false, false);
}
static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist)
@@ -1520,7 +1613,9 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause,
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 8);
coex_dm->tdma_adj_type = 8;
- } else if (coex_dm->cur_ps_tdma == 9) {
+ }
+
+ if (coex_dm->cur_ps_tdma == 9) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 13);
coex_dm->tdma_adj_type = 13;
@@ -1607,7 +1702,9 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause,
} else if (coex_dm->cur_ps_tdma == 8) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
coex_dm->tdma_adj_type = 4;
- } else if (coex_dm->cur_ps_tdma == 13) {
+ }
+
+ if (coex_dm->cur_ps_tdma == 13) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
coex_dm->tdma_adj_type = 9;
} else if (coex_dm->cur_ps_tdma == 14) {
@@ -1652,23 +1749,34 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause,
coex_dm->tdma_adj_type = 12;
}
} else if (result == 1) {
- int tmp = coex_dm->cur_ps_tdma;
- switch (tmp) {
- case 4:
- case 3:
- case 2:
- case 12:
- case 11:
- case 10:
- btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
- true, tmp - 1);
- coex_dm->tdma_adj_type = tmp - 1;
- break;
- case 1:
+ if (coex_dm->cur_ps_tdma == 4) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 71);
coex_dm->tdma_adj_type = 71;
- break;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
}
}
}
@@ -1694,7 +1802,8 @@ static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause,
} else if (coex_dm->cur_ps_tdma == 4) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
coex_dm->tdma_adj_type = 8;
- } else if (coex_dm->cur_ps_tdma == 9) {
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
coex_dm->tdma_adj_type = 14;
} else if (coex_dm->cur_ps_tdma == 10) {
@@ -1776,7 +1885,8 @@ static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause,
} else if (coex_dm->cur_ps_tdma == 8) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
coex_dm->tdma_adj_type = 4;
- } else if (coex_dm->cur_ps_tdma == 13) {
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
coex_dm->tdma_adj_type = 10;
} else if (coex_dm->cur_ps_tdma == 14) {
@@ -1865,7 +1975,8 @@ static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause,
} else if (coex_dm->cur_ps_tdma == 4) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
coex_dm->tdma_adj_type = 8;
- } else if (coex_dm->cur_ps_tdma == 9) {
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
coex_dm->tdma_adj_type = 15;
} else if (coex_dm->cur_ps_tdma == 10) {
@@ -1935,101 +2046,80 @@ static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause,
BTC_PRINT(BTC_MSG_ALGORITHM,
ALGO_TRACE_FW_DETAIL,
"[BTCoex], TxPause = 0\n");
- switch (coex_dm->cur_ps_tdma) {
- case 5:
+ if (coex_dm->cur_ps_tdma == 5) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 6:
+ } else if (coex_dm->cur_ps_tdma == 6) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 7:
+ } else if (coex_dm->cur_ps_tdma == 7) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 8:
+ } else if (coex_dm->cur_ps_tdma == 8) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
coex_dm->tdma_adj_type = 4;
- break;
- case 13:
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 14:
+ } else if (coex_dm->cur_ps_tdma == 14) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 15:
+ } else if (coex_dm->cur_ps_tdma == 15) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 16:
+ } else if (coex_dm->cur_ps_tdma == 16) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
coex_dm->tdma_adj_type = 12;
- break;
}
if (result == -1) {
- switch (coex_dm->cur_ps_tdma) {
- case 1:
+ if (coex_dm->cur_ps_tdma == 1) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 2:
+ } else if (coex_dm->cur_ps_tdma == 2) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 3:
+ } else if (coex_dm->cur_ps_tdma == 3) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 4);
coex_dm->tdma_adj_type = 4;
- break;
- case 9:
+ } else if (coex_dm->cur_ps_tdma == 9) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 10:
+ } else if (coex_dm->cur_ps_tdma == 10) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 11:
+ } else if (coex_dm->cur_ps_tdma == 11) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 12);
coex_dm->tdma_adj_type = 12;
- break;
}
} else if (result == 1) {
- switch (coex_dm->cur_ps_tdma) {
- case 4:
+ if (coex_dm->cur_ps_tdma == 4) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 3:
+ } else if (coex_dm->cur_ps_tdma == 3) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 2:
+ } else if (coex_dm->cur_ps_tdma == 2) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 12:
+ } else if (coex_dm->cur_ps_tdma == 12) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 11:
+ } else if (coex_dm->cur_ps_tdma == 11) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 10:
+ } else if (coex_dm->cur_ps_tdma == 10) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
@@ -2328,7 +2418,7 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2385,12 +2475,43 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist)
/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/
static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist)
{
- u8 wifi_rssi_state, bt_rssi_state;
+ u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
u32 wifi_bw;
+ u8 ap_num = 0;
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 1, 2, 40, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num);
+
+ /* define the office environment */
+ /* driver don't know AP num in Linux, so we will never enter this if */
+ if (ap_num >= 10 && BTC_RSSI_HIGH(wifi_rssi_state1)) {
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff,
+ 0x0);
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ true, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ true, 0x18);
+ }
+ return;
+ }
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2501,7 +2622,7 @@ static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2612,7 +2733,7 @@ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2676,7 +2797,7 @@ static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
if (btc8723b_need_dec_pwr(btcoexist))
@@ -2746,7 +2867,7 @@ static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2809,8 +2930,8 @@ static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
u32 wifi_bw;
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
- 0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2982,7 +3103,15 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
}
}
-
+static void btc8723b2ant_wifioff_hwcfg(struct btc_coexist *btcoexist)
+{
+ /* set wlan_act to low */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+ /* Force GNT_BT to High */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3);
+ /* BT select s0/s1 is controlled by BT */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0);
+}
/*********************************************************************
* work around function start with wa_btc8723b2ant_
@@ -2990,98 +3119,24 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
/*********************************************************************
* extern function start with EXbtc8723b2ant_
*********************************************************************/
-void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
{
- struct btc_board_info *board_info = &btcoexist->board_info;
- u32 u32tmp = 0, fw_ver;
u8 u8tmp = 0;
- u8 h2c_parameter[2] = {0};
-
BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
"[BTCoex], 2Ant Init HW Config!!\n");
+ coex_dm->bt_rf0x1e_backup =
+ btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff);
- /* backup rf 0x1e value */
- coex_dm->bt_rf0x1e_backup = btcoexist->btc_get_rf_reg(btcoexist,
- BTC_RF_A, 0x1e,
- 0xfffff);
-
- /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */
- u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
- u32tmp &= ~BIT23;
- u32tmp |= BIT24;
- btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
-
- btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
- btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
-
- /* Antenna switch control parameter */
- /* btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);*/
-
- /*Force GNT_BT to low*/
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
- btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
-
- /* 0x790[5:0]=0x5 */
+ /* 0x790[5:0] = 0x5 */
u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
u8tmp &= 0xc0;
u8tmp |= 0x5;
btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
-
- /*Antenna config */
- btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
-
- /*ext switch for fw ver < 0xc */
- if (fw_ver < 0xc00) {
- if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
- 0x3, 0x1);
- /*Main Ant to BT for IPS case 0x4c[23]=1*/
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
- 0x1);
-
- /*tell firmware "no antenna inverse"*/
- h2c_parameter[0] = 0;
- h2c_parameter[1] = 1; /* ext switch type */
- btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
- h2c_parameter);
- } else {
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
- 0x3, 0x2);
- /*Aux Ant to BT for IPS case 0x4c[23]=1*/
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
- 0x0);
-
- /*tell firmware "antenna inverse"*/
- h2c_parameter[0] = 1;
- h2c_parameter[1] = 1; /*ext switch type*/
- btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
- h2c_parameter);
- }
- } else {
- /*ext switch always at s1 (if exist) */
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1);
- /*Main Ant to BT for IPS case 0x4c[23]=1*/
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1);
-
- if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
- /*tell firmware "no antenna inverse"*/
- h2c_parameter[0] = 0;
- h2c_parameter[1] = 0; /*ext switch type*/
- btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
- h2c_parameter);
- } else {
- /*tell firmware "antenna inverse"*/
- h2c_parameter[0] = 1;
- h2c_parameter[1] = 0; /*ext switch type*/
- btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
- h2c_parameter);
- }
- }
-
+ /*Antenna config */
+ btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN,
+ true, false);
/* PTA parameter */
btc8723b_coex_tbl_type(btcoexist, FORCE_EXEC, 0);
@@ -3092,14 +3147,14 @@ void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
}
-void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
{
BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
"[BTCoex], Coex Mechanism Init!!\n");
btc8723b2ant_init_coex_dm(btcoexist);
}
-void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
{
struct btc_board_info *board_info = &btcoexist->board_info;
struct btc_stack_info *stack_info = &btcoexist->stack_info;
@@ -3114,6 +3169,7 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck;
u8 wifi_dot11_chnl, wifi_hs_chnl;
u32 fw_ver = 0, bt_patch_ver = 0;
+ u8 ap_num = 0;
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ============[BT Coexist info]============");
@@ -3171,8 +3227,9 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
- "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d",
+ "Wifi rssi/ HS rssi/ AP#", wifi_rssi, bt_hs_rssi, ap_num);
CL_PRINTF(cli_buf);
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
@@ -3301,7 +3358,6 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3);
CL_PRINTF(cli_buf);
-
u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39);
u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
@@ -3371,22 +3427,26 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
BTC_DBG_DISP_COEX_STATISTICS);
}
-
-void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
{
if (BTC_IPS_ENTER == type) {
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
"[BTCoex], IPS ENTER notify\n");
coex_sta->under_ips = true;
+ btc8723b2ant_wifioff_hwcfg(btcoexist);
+ btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
btc8723b2ant_coex_alloff(btcoexist);
} else if (BTC_IPS_LEAVE == type) {
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
"[BTCoex], IPS LEAVE notify\n");
coex_sta->under_ips = false;
+ ex_btc8723b2ant_init_hwconfig(btcoexist);
+ btc8723b2ant_init_coex_dm(btcoexist);
+ btc8723b2ant_query_bt_info(btcoexist);
}
}
-void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
{
if (BTC_LPS_ENABLE == type) {
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3399,7 +3459,7 @@ void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
}
}
-void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
{
if (BTC_SCAN_START == type)
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3409,7 +3469,7 @@ void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
"[BTCoex], SCAN FINISH notify\n");
}
-void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
{
if (BTC_ASSOCIATE_START == type)
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3419,8 +3479,8 @@ void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
"[BTCoex], CONNECT FINISH notify\n");
}
-void btc8723b_med_stat_notify(struct btc_coexist *btcoexist,
- u8 type)
+void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
{
u8 h2c_parameter[3] = {0};
u32 wifi_bw;
@@ -3460,16 +3520,16 @@ void btc8723b_med_stat_notify(struct btc_coexist *btcoexist,
btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
}
-void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
- u8 type)
+void ex_btc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
{
if (type == BTC_PACKET_DHCP)
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
"[BTCoex], DHCP Packet notify\n");
}
-void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
- u8 *tmpbuf, u8 length)
+void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length)
{
u8 bt_info = 0;
u8 i, rsp_source = 0;
@@ -3516,7 +3576,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
coex_sta->bt_info_c2h[rsp_source][4];
/* Here we need to resend some wifi info to BT
- * because bt is reset and loss of the info.
+ because bt is reset and loss of the info.
*/
if ((coex_sta->bt_info_ext & BIT1)) {
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
@@ -3525,11 +3585,13 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
&wifi_connected);
if (wifi_connected)
- btc8723b_med_stat_notify(btcoexist,
- BTC_MEDIA_CONNECT);
+ ex_btc8723b2ant_media_status_notify(
+ btcoexist,
+ BTC_MEDIA_CONNECT);
else
- btc8723b_med_stat_notify(btcoexist,
- BTC_MEDIA_DISCONNECT);
+ ex_btc8723b2ant_media_status_notify(
+ btcoexist,
+ BTC_MEDIA_DISCONNECT);
}
if ((coex_sta->bt_info_ext & BIT3)) {
@@ -3564,7 +3626,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
coex_sta->a2dp_exist = false;
coex_sta->hid_exist = false;
coex_sta->sco_exist = false;
- } else { /* connection exists */
+ } else { /* connection exists */
coex_sta->bt_link_exist = true;
if (bt_info & BT_INFO_8723B_2ANT_B_FTP)
coex_sta->pan_exist = true;
@@ -3601,7 +3663,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_SCO_BUSY;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
"[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
- } else if (bt_info & BT_INFO_8723B_2ANT_B_ACL_BUSY) {
+ } else if (bt_info&BT_INFO_8723B_2ANT_B_ACL_BUSY) {
coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_ACL_BUSY;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
"[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
@@ -3630,26 +3692,16 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
btc8723b2ant_run_coexist_mechanism(btcoexist);
}
-void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
- u8 type)
-{
- if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type)
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
- "[BTCoex],StackOP Inquiry/page/pair start notify\n");
- else if (BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type)
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
- "[BTCoex],StackOP Inquiry/page/pair finish notify\n");
-}
-
-void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist)
{
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+ btc8723b2ant_wifioff_hwcfg(btcoexist);
btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
- btc8723b_med_stat_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+ ex_btc8723b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
}
-void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist)
{
struct btc_board_info *board_info = &btcoexist->board_info;
struct btc_stack_info *stack_info = &btcoexist->stack_info;
@@ -3677,8 +3729,7 @@ void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist)
&bt_patch_ver);
btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
- "[BTCoex], CoexVer/ FwVer/ PatchVer = "
- "%d_%x/ 0x%x/ 0x%x(%d)\n",
+ "[BTCoex], CoexVer/ fw_ver/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
fw_ver, bt_patch_ver, bt_patch_ver);
BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
index e0ad8e5..567f354 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
@@ -153,21 +153,20 @@ struct coex_sta_8723b_2ant {
/*********************************************************************
* The following is interface which will notify coex module.
*********************************************************************/
-void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
-void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
- u8 type);
-void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
- u8 *tmpbuf, u8 length);
-void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
- u8 type);
-void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_btc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist);
#endif
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c
new file mode 100644
index 0000000..0b75e8c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c
@@ -0,0 +1,3010 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*============================================================
+ * Description:
+ *
+ * This file is for RTL8821A Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ *============================================================
+*/
+/*============================================================
+ * include files
+ *============================================================
+ */
+#include "halbt_precomp.h"
+/*============================================================
+ * Global variables, these are static variables
+ *============================================================
+ */
+static struct coex_dm_8821a_1ant glcoex_dm_8821a_1ant;
+static struct coex_dm_8821a_1ant *coex_dm = &glcoex_dm_8821a_1ant;
+static struct coex_sta_8821a_1ant glcoex_sta_8821a_1ant;
+static struct coex_sta_8821a_1ant *coex_sta = &glcoex_sta_8821a_1ant;
+
+static const char *const glbt_info_src_8821a_1ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8821a_1ant = 20130816;
+static u32 glcoex_ver_8821a_1ant = 0x41;
+
+/*============================================================
+ * local function proto type if needed
+ *
+ * local function start with halbtc8821a1ant_
+ *============================================================
+ */
+static u8 halbtc8821a1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ long bt_rssi = 0;
+ u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+ bt_rssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (bt_rssi >= (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Medium\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh1) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ }
+ coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+ return bt_rssi_state;
+}
+
+static u8 halbtc8821a1ant_WifiRssiState(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ long wifi_rssi = 0;
+ u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifi_rssi >=
+ (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Medium\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh1) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ }
+ coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+ return wifi_rssi_state;
+}
+
+static void halbtc8821a1ant_update_ra_mask(struct btc_coexist *btcoexist,
+ bool force_exec, u32 dis_rate_mask)
+{
+ coex_dm->cur_ra_mask = dis_rate_mask;
+
+ if (force_exec ||
+ (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) {
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+ &coex_dm->cur_ra_mask);
+ }
+ coex_dm->pre_ra_mask = coex_dm->cur_ra_mask;
+}
+
+static void btc8821a1ant_auto_rate_fb_retry(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ bool wifi_under_b_mode = false;
+
+ coex_dm->cur_arfr_type = type;
+
+ if (force_exec ||
+ (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) {
+ switch (coex_dm->cur_arfr_type) {
+ case 0: /* normal mode*/
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ coex_dm->backup_arfr_cnt1);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ coex_dm->backup_arfr_cnt2);
+ break;
+ case 1:
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_B_MODE,
+ &wifi_under_b_mode);
+ if (wifi_under_b_mode) {
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ 0x0);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ 0x01010101);
+ } else {
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ 0x0);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ 0x04030201);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_arfr_type = coex_dm->cur_arfr_type;
+}
+
+static void halbtc8821a1ant_retry_limit(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_retry_limit_type = type;
+
+ if (force_exec ||
+ (coex_dm->pre_retry_limit_type != coex_dm->cur_retry_limit_type)) {
+ switch (coex_dm->cur_retry_limit_type) {
+ case 0: /* normal mode*/
+ btcoexist->btc_write_2byte(btcoexist, 0x42a,
+ coex_dm->backup_retry_limit);
+ break;
+ case 1: /* retry limit = 8*/
+ btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808);
+ break;
+ default:
+ break;
+ }
+ }
+ coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type;
+}
+
+static void halbtc8821a1ant_ampdu_max_time(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_ampdu_time_type = type;
+
+ if (force_exec ||
+ (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) {
+ switch (coex_dm->cur_ampdu_time_type) {
+ case 0: /* normal mode*/
+ btcoexist->btc_write_1byte(btcoexist, 0x456,
+ coex_dm->backup_ampdu_max_time);
+ break;
+ case 1: /* AMPDU timw = 0x38 * 32us*/
+ btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type;
+}
+
+static void halbtc8821a1ant_limited_tx(struct btc_coexist *btcoexist,
+ bool force_exec, u8 ra_mask_type,
+ u8 arfr_type, u8 retry_limit_type,
+ u8 ampdu_time_type)
+{
+ switch (ra_mask_type) {
+ case 0: /* normal mode*/
+ halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, 0x0);
+ break;
+ case 1: /* disable cck 1/2*/
+ halbtc8821a1ant_update_ra_mask(btcoexist, force_exec,
+ 0x00000003);
+ break;
+ case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/
+ halbtc8821a1ant_update_ra_mask(btcoexist, force_exec,
+ 0x0001f1f7);
+ break;
+ default:
+ break;
+ }
+
+ btc8821a1ant_auto_rate_fb_retry(btcoexist, force_exec, arfr_type);
+ halbtc8821a1ant_retry_limit(btcoexist, force_exec, retry_limit_type);
+ halbtc8821a1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type);
+}
+
+static void halbtc8821a1ant_limited_rx(struct btc_coexist *btcoexist,
+ bool force_exec, bool rej_ap_agg_pkt,
+ bool bt_ctrl_agg_buf_size,
+ u8 agg_buf_size)
+{
+ bool reject_rx_agg = rej_ap_agg_pkt;
+ bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+ u8 rx_agg_size = agg_buf_size;
+
+ /*============================================*/
+ /* Rx Aggregation related setting*/
+ /*============================================*/
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_BL_TO_REJ_AP_AGG_PKT, &reject_rx_agg);
+ /* decide BT control aggregation buf size or not*/
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+ &bt_ctrl_rx_agg_size);
+ /* aggregation buf size, only work when BT control Rx agg size.*/
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size);
+ /* real update aggregation setting*/
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8821a1ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_tx_rx, reg_lp_tx_rx, u4_tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_tx_rx = 0x770;
+ reg_lp_tx_rx = 0x774;
+
+ u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_tx_rx);
+ reg_hp_tx = u4_tmp & MASKLWORD;
+ reg_hp_rx = (u4_tmp & MASKHWORD)>>16;
+
+ u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_tx_rx);
+ reg_lp_tx = u4_tmp & MASKLWORD;
+ reg_lp_rx = (u4_tmp & MASKHWORD)>>16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ /* reset counter*/
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8821a1ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger*/
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_update_bt_link_info(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+ bt_link_info->sco_exist = coex_sta->sco_exist;
+ bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+ bt_link_info->pan_exist = coex_sta->pan_exist;
+ bt_link_info->hid_exist = coex_sta->hid_exist;
+
+ /* work around for HS mode.*/
+ if (bt_hs_on) {
+ bt_link_info->pan_exist = true;
+ bt_link_info->bt_link_exist = true;
+ }
+
+ /* check if Sco only*/
+ if (bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->sco_only = true;
+ else
+ bt_link_info->sco_only = false;
+
+ /* check if A2dp only*/
+ if (!bt_link_info->sco_exist &&
+ bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->a2dp_only = true;
+ else
+ bt_link_info->a2dp_only = false;
+
+ /* check if Pan only*/
+ if (!bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->pan_only = true;
+ else
+ bt_link_info->pan_only = false;
+
+ /* check if Hid only*/
+ if (!bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ bt_link_info->hid_exist)
+ bt_link_info->hid_only = true;
+ else
+ bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8821a1ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+ u8 algorithm = BT_8821A_1ANT_COEX_ALGO_UNDEFINED;
+ u8 num_of_diff_profile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ if (!bt_link_info->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], No BT link exists!!!\n");
+ return algorithm;
+ }
+
+ if (bt_link_info->sco_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->hid_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->pan_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->a2dp_exist)
+ num_of_diff_profile++;
+
+ if (num_of_diff_profile == 1) {
+ if (bt_link_info->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+ } else {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = PAN(HS) only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = PAN(EDR) only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 2) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile >= 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n");
+
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+ return algorithm;
+}
+
+static void halbtc8821a1ant_set_bt_auto_report(struct btc_coexist *btcoexist,
+ bool enable_auto_report)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (enable_auto_report)
+ h2c_parameter[0] |= BIT0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+ (enable_auto_report ? "Enabled!!" : "Disabled!!"),
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_bt_auto_report(struct btc_coexist *btcoexist,
+ bool force_exec,
+ bool enable_auto_report)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW, "[BTCoex], %s BT Auto report = %s\n",
+ (force_exec ? "force to" : ""), ((enable_auto_report) ?
+ "Enabled" : "Disabled"));
+ coex_dm->cur_bt_auto_report = enable_auto_report;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_bt_auto_report = %d, cur_bt_auto_report = %d\n",
+ coex_dm->pre_bt_auto_report,
+ coex_dm->cur_bt_auto_report);
+
+ if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+ return;
+ }
+ halbtc8821a1ant_set_bt_auto_report(btcoexist, coex_dm->cur_bt_auto_report);
+
+ coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void btc8821a1ant_set_sw_pen_tx_rate(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ u8 h2c_parameter[6] = {0};
+
+ h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty*/
+
+ if (low_penalty_ra) {
+ h2c_parameter[1] |= BIT0;
+ /*normal rate except MCS7/6/5, OFDM54/48/36*/
+ h2c_parameter[2] = 0x00;
+ h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54*/
+ h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48*/
+ h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36*/
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set WiFi Low-Penalty Retry: %s",
+ (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8821a1ant_low_penalty_ra(struct btc_coexist *btcoexist,
+ bool force_exec, bool low_penalty_ra)
+{
+ coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+ if (!force_exec) {
+ if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+ return;
+ }
+ btc8821a1ant_set_sw_pen_tx_rate(btcoexist, coex_dm->cur_low_penalty_ra);
+
+ coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8821a1ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8821a1ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec, u32 val0x6c0,
+ u32 val0x6c4, u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+ (force_exec ? "force to" : ""), val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+ coex_dm->cur_val_0x6c0 = val0x6c0;
+ coex_dm->cur_val_0x6c4 = val0x6c4;
+ coex_dm->cur_val_0x6c8 = val0x6c8;
+ coex_dm->cur_val_0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ if ((coex_dm->pre_val_0x6c0 == coex_dm->cur_val_0x6c0) &&
+ (coex_dm->pre_val_0x6c4 == coex_dm->cur_val_0x6c4) &&
+ (coex_dm->pre_val_0x6c8 == coex_dm->cur_val_0x6c8) &&
+ (coex_dm->pre_val_0x6cc == coex_dm->cur_val_0x6cc))
+ return;
+ }
+ halbtc8821a1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+
+ coex_dm->pre_val_0x6c0 = coex_dm->cur_val_0x6c0;
+ coex_dm->pre_val_0x6c4 = coex_dm->cur_val_0x6c4;
+ coex_dm->pre_val_0x6c8 = coex_dm->cur_val_0x6c8;
+ coex_dm->pre_val_0x6cc = coex_dm->cur_val_0x6cc;
+}
+
+static void halbtc8821a1ant_coex_table_with_type(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ switch (type) {
+ case 0:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x55555555, 0xffffff, 0x3);
+ break;
+ case 1:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec,
+ 0x55555555, 0x5a5a5a5a,
+ 0xffffff, 0x3);
+ break;
+ case 2:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 3:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0xaaaaaaaa, 0xffffff, 0x3);
+ break;
+ case 4:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0xffffffff,
+ 0xffffffff, 0xffffff, 0x3);
+ break;
+ case 5:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5fff5fff,
+ 0x5fff5fff, 0xffffff, 0x3);
+ break;
+ case 6:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 7:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5afa5afa,
+ 0x5afa5afa, 0xffffff, 0x3);
+ break;
+ default:
+ break;
+ }
+}
+
+static void btc8821a1ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0; /* function enable*/
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n",
+ coex_dm->pre_ignore_wlan_act,
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ btc8821a1ant_set_fw_ignore_wlan_act(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8821a1ant_set_fw_pstdma(struct btc_coexist *btcoexist,
+ u8 byte1, u8 byte2, u8 byte3,
+ u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5] = {0};
+
+ h2c_parameter[0] = byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = byte5;
+
+ coex_dm->ps_tdma_para[0] = byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1]<<24 |
+ h2c_parameter[2]<<16 |
+ h2c_parameter[3]<<8 |
+ h2c_parameter[4]);
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void halbtc8821a1ant_set_lps_rpwm(struct btc_coexist *btcoexist,
+ u8 lps_val, u8 rpwm_val)
+{
+ u8 lps = lps_val;
+ u8 rpwm = rpwm_val;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps);
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm);
+}
+
+static void halbtc8821a1ant_lps_rpwm(struct btc_coexist *btcoexist,
+ bool force_exec, u8 lps_val, u8 rpwm_val)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n",
+ (force_exec ? "force to" : ""), lps_val, rpwm_val);
+ coex_dm->cur_lps = lps_val;
+ coex_dm->cur_rpwm = rpwm_val;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], LPS-RxBeaconMode = 0x%x, LPS-RPWM = 0x%x!!\n",
+ coex_dm->cur_lps, coex_dm->cur_rpwm);
+
+ if ((coex_dm->pre_lps == coex_dm->cur_lps) &&
+ (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], LPS-RPWM_Last = 0x%x, LPS-RPWM_Now = 0x%x!!\n",
+ coex_dm->pre_rpwm, coex_dm->cur_rpwm);
+
+ return;
+ }
+ }
+ halbtc8821a1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val);
+
+ coex_dm->pre_lps = coex_dm->cur_lps;
+ coex_dm->pre_rpwm = coex_dm->cur_rpwm;
+}
+
+static void halbtc8821a1ant_sw_mechanism(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra);
+
+ halbtc8821a1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra);
+}
+
+static void halbtc8821a1ant_set_ant_path(struct btc_coexist *btcoexist,
+ u8 ant_pos_type, bool init_hw_cfg,
+ bool wifi_off)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 u4_tmp = 0;
+ u8 h2c_parameter[2] = {0};
+
+ if (init_hw_cfg) {
+ /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT*/
+ u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u4_tmp &= ~BIT23;
+ u4_tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp);
+
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x975, 0x3, 0x3);
+ btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77);
+
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+ /*tell firmware "antenna inverse" ==>
+ * WRONG firmware antenna control code.==>need fw to fix
+ */
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1;
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ /*Main Ant to BT for IPS case 0x4c[23] = 1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64,
+ 0x1, 0x1);
+ } else {
+ /*tell firmware "no antenna inverse" ==>
+ * WRONG firmware antenna control code.==>need fw to fix
+ */
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1;
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ /*Aux Ant to BT for IPS case 0x4c[23] = 1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64,
+ 0x1, 0x0);
+ }
+ } else if (wifi_off) {
+ /* 0x4c[24:23] = 00, Set Antenna control
+ * by BT_RFE_CTRL BT Vendor 0xac = 0xf002
+ */
+ u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u4_tmp &= ~BIT23;
+ u4_tmp &= ~BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp);
+ }
+
+ /* ext switch setting*/
+ switch (ant_pos_type) {
+ case BTC_ANT_PATH_WIFI:
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x1);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x2);
+ break;
+ case BTC_ANT_PATH_BT:
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x2);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x1);
+ break;
+ default:
+ case BTC_ANT_PATH_PTA:
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x1);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x2);
+ break;
+ }
+}
+
+static void halbtc8821a1ant_ps_tdma(struct btc_coexist *btcoexist,
+ bool force_exec, bool turn_on, u8 type)
+{
+ u8 rssi_adjust_val = 0;
+
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ if (!force_exec) {
+ if (coex_dm->cur_ps_tdma_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ********** TDMA(on, %d) **********\n",
+ coex_dm->cur_ps_tdma);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ********** TDMA(off, %d) **********\n",
+ coex_dm->cur_ps_tdma);
+ }
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ default:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1a,
+ 0x1a, 0x0, 0x50);
+ break;
+ case 1:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x3a,
+ 0x03, 0x10, 0x50);
+ rssi_adjust_val = 11;
+ break;
+ case 2:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x2b,
+ 0x03, 0x10, 0x50);
+ rssi_adjust_val = 14;
+ break;
+ case 3:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1d,
+ 0x1d, 0x0, 0x10);
+ break;
+ case 4:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15,
+ 0x3, 0x14, 0x0);
+ rssi_adjust_val = 17;
+ break;
+ case 5:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15,
+ 0x3, 0x11, 0x10);
+ break;
+ case 6:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+ 0x3, 0x0, 0x0);
+ break;
+ case 7:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xc,
+ 0x5, 0x0, 0x0);
+ break;
+ case 8:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25,
+ 0x3, 0x10, 0x0);
+ break;
+ case 9:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21,
+ 0x3, 0x10, 0x50);
+ rssi_adjust_val = 18;
+ break;
+ case 10:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+ 0xa, 0x0, 0x40);
+ break;
+ case 11:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14,
+ 0x03, 0x10, 0x10);
+ rssi_adjust_val = 20;
+ break;
+ case 12:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x0a,
+ 0x0a, 0x0, 0x50);
+ break;
+ case 13:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x18,
+ 0x18, 0x0, 0x10);
+ break;
+ case 14:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21,
+ 0x3, 0x10, 0x10);
+ break;
+ case 15:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+ 0x3, 0x8, 0x0);
+ break;
+ case 16:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15,
+ 0x3, 0x10, 0x0);
+ rssi_adjust_val = 18;
+ break;
+ case 18:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25,
+ 0x3, 0x10, 0x0);
+ rssi_adjust_val = 14;
+ break;
+ case 20:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x35,
+ 0x03, 0x11, 0x10);
+ break;
+ case 21:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15,
+ 0x03, 0x11, 0x10);
+ break;
+ case 22:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x25,
+ 0x03, 0x11, 0x10);
+ break;
+ case 23:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 24:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x15,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 25:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 26:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 27:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+ 0x3, 0x31, 0x98);
+ rssi_adjust_val = 22;
+ break;
+ case 28:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x69, 0x25,
+ 0x3, 0x31, 0x0);
+ break;
+ case 29:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xab, 0x1a,
+ 0x1a, 0x1, 0x10);
+ break;
+ case 30:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14,
+ 0x3, 0x10, 0x50);
+ break;
+ case 31:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x1a,
+ 0x1a, 0, 0x58);
+ break;
+ case 32:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0xa,
+ 0x3, 0x10, 0x0);
+ break;
+ case 33:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xa3, 0x25,
+ 0x3, 0x30, 0x90);
+ break;
+ case 34:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x53, 0x1a,
+ 0x1a, 0x0, 0x10);
+ break;
+ case 35:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x63, 0x1a,
+ 0x1a, 0x0, 0x10);
+ break;
+ case 36:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x12,
+ 0x3, 0x14, 0x50);
+ break;
+ }
+ } else {
+ /* disable PS tdma*/
+ switch (type) {
+ case 8: /*PTA Control*/
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x8, 0x0, 0x0,
+ 0x0, 0x0);
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA,
+ false, false);
+ break;
+ case 0:
+ default: /*Software control, Antenna at BT side*/
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x0, 0x0);
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+ false, false);
+ break;
+ case 9: /*Software control, Antenna at WiFi side*/
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x0, 0x0);
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI,
+ false, false);
+ break;
+ case 10: /* under 5G*/
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x8, 0x0);
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+ false, false);
+ break;
+ }
+ }
+ rssi_adjust_val = 0;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val);
+
+ /* update pre state*/
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static bool halbtc8821a1ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ bool common = false, wifi_connected = false, wifi_busy = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (!wifi_connected &&
+ BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else if (wifi_connected &&
+ (BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + BT non connected-idle!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else if (!wifi_connected &&
+ (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else if (wifi_connected &&
+ (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + BT connected-idle!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else if (!wifi_connected &&
+ (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE !=
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT Busy!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else {
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Busy + BT Busy!!\n");
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Idle + BT Busy!!\n");
+ }
+
+ common = false;
+ }
+
+ return common;
+}
+
+static void btc8821a1ant_tdma_dur_adj(struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ static long up, dn, m, n, wait_count;
+ /*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/
+ long result;
+ u8 retry_count = 0, bt_info_ext;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjustForAcl()\n");
+
+ if ((BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+ wifi_status) ||
+ (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN ==
+ wifi_status) ||
+ (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT ==
+ wifi_status)) {
+ if (coex_dm->cur_ps_tdma != 1 &&
+ coex_dm->cur_ps_tdma != 2 &&
+ coex_dm->cur_ps_tdma != 3 &&
+ coex_dm->cur_ps_tdma != 9) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ }
+ return;
+ }
+
+ if (!coex_dm->auto_tdma_adjust) {
+ coex_dm->auto_tdma_adjust = true;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+ coex_dm->tdma_adj_type = 2;
+ /*============*/
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ } else {
+ /*accquire the BT TRx retry count from BT_Info byte2*/
+ retry_count = coex_sta->bt_retry_cnt;
+ bt_info_ext = coex_sta->bt_info_ext;
+ result = 0;
+ wait_count++;
+
+ if (retry_count == 0) {
+ /* no retry in the last 2-second duration*/
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ /* if (retry count == 0) for 2*n seconds ,
+ * make WiFi duration wider
+ */
+ wait_count = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Increase wifi duration!!\n");
+ }
+ } else if (retry_count <= 3) {
+ /* <=3 retry in the last 2-second duration*/
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ /* if retry count< 3 for 2*2 seconds,
+ * shrink wifi duration
+ */
+ if (wait_count <= 2)
+ m++; /* avoid bounce in two levels */
+ else
+ m = 1;
+
+ if (m >= 20) {
+ /* m max value is 20, max time is 120 s,
+ * recheck if adjust WiFi duration.
+ */
+ m = 20;
+ }
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+ }
+ } else {
+ /* retry count > 3, if retry count > 3 happens once,
+ * shrink WiFi duration
+ */
+ if (wait_count == 1)
+ m++; /* avoid bounce in two levels */
+ else
+ m = 1;
+ /* m max value is 20, max time is 120 second,
+ * recheck if adjust WiFi duration.
+ */
+ if (m >= 20)
+ m = 20;
+
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+ }
+
+ if (result == -1) {
+ if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+ ((coex_dm->cur_ps_tdma == 1) ||
+ (coex_dm->cur_ps_tdma == 2))) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ } else if (result == 1) {
+ if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+ ((coex_dm->cur_ps_tdma == 1) ||
+ (coex_dm->cur_ps_tdma == 2))) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ }
+ } else {
+ /*no change*/
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ********** TDMA(on, %d) **********\n",
+ coex_dm->cur_ps_tdma);
+ }
+
+ if (coex_dm->cur_ps_tdma != 1 &&
+ coex_dm->cur_ps_tdma != 2 &&
+ coex_dm->cur_ps_tdma != 9 &&
+ coex_dm->cur_ps_tdma != 11) {
+ /* recover to previous adjust type*/
+ halbtc8821a1ant_ps_tdma(btcoexist,
+ NORMAL_EXEC, true,
+ coex_dm->tdma_adj_type);
+ }
+ }
+}
+
+static void btc8821a1ant_ps_tdma_check_for_pwr_save(struct btc_coexist *btcoex,
+ bool new_ps_state)
+{
+ u8 lps_mode = 0x0;
+
+ btcoex->btc_get(btcoex, BTC_GET_U1_LPS_MODE, &lps_mode);
+
+ if (lps_mode) {
+ /* already under LPS state*/
+ if (new_ps_state) {
+ /* keep state under LPS, do nothing.*/
+ } else {
+ /* will leave LPS state, turn off psTdma first*/
+ halbtc8821a1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 0);
+ }
+ } else {
+ /* NO PS state*/
+ if (new_ps_state) {
+ /* will enter LPS state, turn off psTdma first*/
+ halbtc8821a1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 0);
+ } else {
+ /* keep state under NO PS state, do nothing.*/
+ }
+ }
+}
+
+static void halbtc8821a1ant_power_save_state(struct btc_coexist *btcoexist,
+ u8 ps_type, u8 lps_val,
+ u8 rpwm_val)
+{
+ bool low_pwr_disable = false;
+
+ switch (ps_type) {
+ case BTC_PS_WIFI_NATIVE:
+ /* recover to original 32k low power setting*/
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL);
+ break;
+ case BTC_PS_LPS_ON:
+ btc8821a1ant_ps_tdma_check_for_pwr_save(btcoexist,
+ true);
+ halbtc8821a1ant_lps_rpwm(btcoexist,
+ NORMAL_EXEC, lps_val, rpwm_val);
+ /* when coex force to enter LPS, do not enter 32k low power.*/
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ /* power save must executed before psTdma.*/
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL);
+ break;
+ case BTC_PS_LPS_OFF:
+ btc8821a1ant_ps_tdma_check_for_pwr_save(btcoexist, false);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+static void halbtc8821a1ant_coex_under_5g(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8821a1ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true);
+
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 10);
+
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+
+ halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+
+ halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 5);
+}
+
+static void halbtc8821a1ant_action_wifi_only(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9);
+}
+
+static void btc8821a1ant_mon_bt_en_dis(struct btc_coexist *btcoexist)
+{
+ static bool pre_bt_disabled;
+ static u32 bt_disable_cnt;
+ bool bt_active = true, bt_disabled = false;
+
+ /* This function check if bt is disabled*/
+
+ if (coex_sta->high_priority_tx == 0 &&
+ coex_sta->high_priority_rx == 0 &&
+ coex_sta->low_priority_tx == 0 &&
+ coex_sta->low_priority_rx == 0) {
+ bt_active = false;
+ }
+ if (coex_sta->high_priority_tx == 0xffff &&
+ coex_sta->high_priority_rx == 0xffff &&
+ coex_sta->low_priority_tx == 0xffff &&
+ coex_sta->low_priority_rx == 0xffff) {
+ bt_active = false;
+ }
+ if (bt_active) {
+ bt_disable_cnt = 0;
+ bt_disabled = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is enabled !!\n");
+ } else {
+ bt_disable_cnt++;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], bt all counters = 0, %d times!!\n",
+ bt_disable_cnt);
+ if (bt_disable_cnt >= 2) {
+ bt_disabled = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is disabled !!\n");
+ halbtc8821a1ant_action_wifi_only(btcoexist);
+ }
+ }
+ if (pre_bt_disabled != bt_disabled) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is from %s to %s!!\n",
+ (pre_bt_disabled ? "disabled" : "enabled"),
+ (bt_disabled ? "disabled" : "enabled"));
+ pre_bt_disabled = bt_disabled;
+ if (bt_disabled) {
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS,
+ NULL);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS,
+ NULL);
+ }
+ }
+}
+
+/*=============================================*/
+/**/
+/* Software Coex Mechanism start*/
+/**/
+/*=============================================*/
+
+/* SCO only or SCO+PAN(HS)*/
+static void halbtc8821a1ant_action_sco(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8821a1ant_action_hid(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/
+static void halbtc8821a1ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(HS) only*/
+static void halbtc8821a1ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(EDR)+A2DP*/
+static void halbtc8821a1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/* HID+A2DP+PAN(EDR)*/
+static void btc8821a1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8821a1ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/*=============================================*/
+/**/
+/* Non-Software Coex Mechanism start*/
+/**/
+/*=============================================*/
+
+static void halbtc8821a1ant_action_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2);
+}
+
+static void halbtc8821a1ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false;
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+ if (!wifi_connected) {
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else if ((bt_link_info->sco_exist) ||
+ (bt_link_info->hid_only)) {
+ /* SCO/HID-only busy*/
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else {
+ halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON,
+ 0x50, 0x4);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void btc8821a1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist,
+ u8 wifi_status) {
+ /* tdma and coex table*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+
+ if (BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+ wifi_status)
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ else
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+}
+
+static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ u8 bt_rssi_state;
+
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ bt_rssi_state = halbtc8821a1ant_bt_rssi_state(2, 28, 0);
+
+ if (bt_link_info->hid_only) {
+ /*HID*/
+ btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+ wifi_status);
+ coex_dm->auto_tdma_adjust = false;
+ return;
+ } else if (bt_link_info->a2dp_only) {
+ /*A2DP*/
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a1ant_tdma_dur_adj(btcoexist, wifi_status);
+ } else {
+ /*for low BT RSSI*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->auto_tdma_adjust = false;
+ }
+
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) {
+ /*HID+A2DP*/
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ /*for low BT RSSI*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->auto_tdma_adjust = false;
+ }
+
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else if ((bt_link_info->pan_only) ||
+ (bt_link_info->hid_exist && bt_link_info->pan_exist)) {
+ /*PAN(OPP, FTP), HID+PAN(OPP, FTP)*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) ||
+ (bt_link_info->hid_exist && bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist)) {
+ /*A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP)*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ }
+}
+
+static void halbtc8821a1ant_action_wifi_not_connected(
+ struct btc_coexist *btcoexist)
+{
+ /* power save state*/
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+ /* tdma and coex table*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void btc8821a1ant_act_wifi_not_conn_scan(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+}
+
+static void halbtc8821a1ant_action_wifi_connected_scan(
+ struct btc_coexist *btcoexist) {
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ /* power save state*/
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+ /* tdma and coex table*/
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 22);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+ } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void btc8821a1ant_act_wifi_conn_sp_pkt(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool hs_connecting = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting);
+
+ halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table*/
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 22);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 20);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ }
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void halbtc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist)
+{
+ bool wifi_busy = false;
+ bool scan = false, link = false, roam = false;
+ bool under_4way = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect()===>\n");
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_4_WAY_PROGRESS, &under_4way);
+ if (under_4way) {
+ btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ if (scan || link || roam) {
+ halbtc8821a1ant_action_wifi_connected_scan(btcoexist);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n");
+ return;
+ }
+
+ /* power save state*/
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY ==
+ coex_dm->bt_status && !btcoexist->bt_link_info.hid_only)
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_LPS_ON, 0x50, 0x4);
+ else
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table*/
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ if (!wifi_busy) {
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+ } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ }
+ } else {
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+ } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ }
+ }
+}
+
+static void btc8821a1ant_run_sw_coex_mech(struct btc_coexist *btcoexist)
+{
+ u8 algorithm = 0;
+
+ algorithm = halbtc8821a1ant_action_algorithm(btcoexist);
+ coex_dm->cur_algorithm = algorithm;
+
+ if (!halbtc8821a1ant_is_common_action(btcoexist)) {
+ switch (coex_dm->cur_algorithm) {
+ case BT_8821A_1ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = SCO.\n");
+ halbtc8821a1ant_action_sco(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID.\n");
+ halbtc8821a1ant_action_hid(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = A2DP.\n");
+ halbtc8821a1ant_action_a2dp(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = A2DP+PAN(HS).\n");
+ halbtc8821a1ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN(EDR).\n");
+ halbtc8821a1ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HS mode.\n");
+ halbtc8821a1ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN+A2DP.\n");
+ halbtc8821a1ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN(EDR)+HID.\n");
+ halbtc8821a1ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID+A2DP+PAN.\n");
+ btc8821a1ant_action_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID+A2DP.\n");
+ halbtc8821a1ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = coexist All Off!!\n");
+ /*halbtc8821a1ant_coex_all_off(btcoexist);*/
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+static void halbtc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false, bt_hs_on = false;
+ bool increase_scan_dev_num = false;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+ u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ bool wifi_under_5g = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism()===>\n");
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n");
+ return;
+ }
+
+ if (btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n");
+ return;
+ }
+
+ if (coex_sta->under_ips) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is under IPS !!!\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+ if (wifi_under_5g) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for 5G <===\n");
+ halbtc8821a1ant_coex_under_5g(btcoexist);
+ return;
+ }
+
+ if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+ increase_scan_dev_num = true;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM,
+ &increase_scan_dev_num);
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+ if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) {
+ halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ } else {
+ if (wifi_connected) {
+ wifi_rssi_state =
+ halbtc8821a1ant_WifiRssiState(btcoexist, 1, 2,
+ 30, 0);
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a1ant_limited_tx(btcoexist,
+ NORMAL_EXEC, 1, 1,
+ 1, 1);
+ } else {
+ halbtc8821a1ant_limited_tx(btcoexist,
+ NORMAL_EXEC, 1, 1,
+ 1, 1);
+ }
+ } else {
+ halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC,
+ 0, 0, 0, 0);
+ }
+ }
+
+ if (bt_link_info->sco_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x3;
+ } else if (bt_link_info->hid_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x5;
+ } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x8;
+ }
+ halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+
+ btc8821a1ant_run_sw_coex_mech(btcoexist);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8821a1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8821a1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (!wifi_connected) {
+ bool scan = false, link = false, roam = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is non connected-idle !!!\n");
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (scan || link || roam)
+ btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+ else
+ halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+ } else {
+ /* wifi LPS/Busy*/
+ halbtc8821a1ant_action_wifi_connected(btcoexist);
+ }
+}
+
+static void halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* force to reset coex mechanism*/
+ /* sw all off*/
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8821a1ant_init_hw_config(struct btc_coexist *btcoexist,
+ bool back_up)
+{
+ u8 u1_tmp = 0;
+ bool wifi_under_5g = false;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 1Ant Init HW Config!!\n");
+
+ if (back_up) {
+ coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist,
+ 0x430);
+ coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist,
+ 0x434);
+ coex_dm->backup_retry_limit =
+ btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ coex_dm->backup_ampdu_max_time =
+ btcoexist->btc_read_1byte(btcoexist, 0x456);
+ }
+
+ /* 0x790[5:0] = 0x5*/
+ u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u1_tmp &= 0xc0;
+ u1_tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u1_tmp);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+ /*Antenna config*/
+ if (wifi_under_5g)
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+ true, false);
+ else
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA,
+ true, false);
+ /* PTA parameter*/
+ halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+
+ /* Enable counter statistics*/
+ /*0x76e[3] =1, WLAN_Act control by PTA*/
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+}
+
+/*============================================================*/
+/* work around function start with wa_halbtc8821a1ant_*/
+/*============================================================*/
+/*============================================================*/
+/* extern function start with EXhalbtc8821a1ant_*/
+/*============================================================*/
+void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_init_hw_config(btcoexist, true);
+}
+
+void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+
+ btcoexist->stop_coex_dm = false;
+
+ halbtc8821a1ant_init_coex_dm(btcoexist);
+
+ halbtc8821a1ant_query_bt_info(btcoexist);
+}
+
+void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ u8 *cli_buf = btcoexist->cli_buf;
+ u8 u1_tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+ u16 u2_tmp[4];
+ u32 u4_tmp[4];
+ bool roam = false, scan = false, link = false, wifi_under_5g = false;
+ bool bt_hs_on = false, wifi_busy = false;
+ long wifi_rssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir;
+ u8 wifi_dot11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[BT Coexist info]============");
+ CL_PRINTF(cli_buf);
+
+ if (btcoexist->manual_control) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[Under Manual Control]============");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ==========================================");
+ CL_PRINTF(cli_buf);
+ }
+ if (btcoexist->stop_coex_dm) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[Coex is STOPPED]============");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ==========================================");
+ CL_PRINTF(cli_buf);
+ }
+
+ if (!board_info->bt_exist) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
+ CL_PRINTF(cli_buf);
+ return;
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d/ %d",
+ "Ant PG Num/ Ant Mech/ Ant Pos:",
+ board_info->pg_ant_num,
+ board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %s / %d", "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8821a_1ant,
+ glcoex_ver_8821a_1ant,
+ fw_ver, bt_patch_ver,
+ bt_patch_ver);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION,
+ &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+ &wifi_dot11_chnl);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL,
+ &wifi_hs_chnl);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsChnl(HsMode)",
+ wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info",
+ coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+ coex_dm->wifi_chnl_info[2]);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi",
+ (int)wifi_rssi, (int)bt_hs_rssi);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan",
+ link, roam, scan);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G,
+ &wifi_under_5g);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW,
+ &wifi_bw);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY,
+ &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+ &wifi_traffic_dir);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %s / %s/ %s ", "Wifi status",
+ (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]",
+ ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+ ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+ ((BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) ?
+ "non-connected idle" :
+ ((BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) ?
+ "connected-idle" : "busy")))),
+ coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP",
+ bt_link_info->sco_exist,
+ bt_link_info->hid_exist,
+ bt_link_info->pan_exist,
+ bt_link_info->a2dp_exist);
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext&BIT0) ?
+ "Basic rate" : "EDR rate");
+ CL_PRINTF(cli_buf);
+
+ for (i = 0; i < BT_INFO_SRC_8821A_1ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+ glbt_info_src_8821a_1ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3],
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ CL_PRINTF(cli_buf);
+ }
+ }
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %s/%s, (0x%x/0x%x)",
+ "PS state, IPS/LPS, (lps/rpwm)",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_Lps ? "LPS ON" : "LPS OFF")),
+ btcoexist->bt_info.lps_val,
+ btcoexist->bt_info.rpwm_val);
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ if (!btcoexist->manual_control) {
+ /* Sw mechanism*/
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s", "============[Sw mechanism]============");
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d", "SM[LowPenaltyRA]",
+ coex_dm->cur_low_penalty_ra);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %s/ %s/ %d ",
+ "DelBA/ BtCtrlAgg/ AggSize",
+ (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"),
+ (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"),
+ btcoexist->bt_info.agg_buf_size);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x ", "Rate Mask",
+ btcoexist->bt_info.ra_mask);
+ CL_PRINTF(cli_buf);
+
+ /* Fw mechanism*/
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Fw mechanism]============");
+ CL_PRINTF(cli_buf);
+
+ ps_tdma_case = coex_dm->cur_ps_tdma;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+ "PS TDMA",
+ coex_dm->ps_tdma_para[0],
+ coex_dm->ps_tdma_para[1],
+ coex_dm->ps_tdma_para[2],
+ coex_dm->ps_tdma_para[3],
+ coex_dm->ps_tdma_para[4],
+ ps_tdma_case,
+ coex_dm->auto_tdma_adjust);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x ",
+ "Latest error condition(should be 0)",
+ coex_dm->error_condition);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d ", "IgnWlanAct",
+ coex_dm->cur_ignore_wlan_act);
+ CL_PRINTF(cli_buf);
+ }
+
+ /* Hw setting*/
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s", "============[Hw setting]============");
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "backup ARFR1/ARFR2/RL/AMaxTime",
+ coex_dm->backup_arfr_cnt1,
+ coex_dm->backup_arfr_cnt2,
+ coex_dm->backup_retry_limit,
+ coex_dm->backup_ampdu_max_time);
+ CL_PRINTF(cli_buf);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+ u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+ u2_tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "0x430/0x434/0x42a/0x456",
+ u4_tmp[0], u4_tmp[1], u2_tmp[0], u1_tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc58);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x", "0x778/ 0xc58[29:25]",
+ u1_tmp[0], (u4_tmp[0]&0x3e000000) >> 25);
+ CL_PRINTF(cli_buf);
+
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x", "0x8db[6:5]",
+ ((u1_tmp[0]&0x60)>>5));
+ CL_PRINTF(cli_buf);
+
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x975);
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0xcb4[29:28]/0xcb4[7:0]/0x974[9:8]",
+ (u4_tmp[0] & 0x30000000)>>28,
+ u4_tmp[0] & 0xff,
+ u1_tmp[0] & 0x3);
+ CL_PRINTF(cli_buf);
+
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x64);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x40/0x4c[24:23]/0x64[0]",
+ u1_tmp[0], ((u4_tmp[0]&0x01800000)>>23), u1_tmp[1]&0x1);
+ CL_PRINTF(cli_buf);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522",
+ u4_tmp[0], u1_tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x", "0xc50(dig)",
+ u4_tmp[0]&0xff);
+ CL_PRINTF(cli_buf);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48);
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5d);
+ u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA",
+ u4_tmp[0], (u1_tmp[0]<<8) + u1_tmp[1]);
+ CL_PRINTF(cli_buf);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u4_tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
+ u4_tmp[0], u4_tmp[1], u4_tmp[2], u1_tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)",
+ coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)",
+ coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+ CL_PRINTF(cli_buf);
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1)
+ halbtc8821a1ant_monitor_bt_ctr(btcoexist);
+#endif
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+ return;
+
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+ halbtc8821a1ant_set_ant_path(btcoexist,
+ BTC_ANT_PATH_BT, false, true);
+ /*set PTA control*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 0);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+
+ halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+ }
+}
+
+void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+ return;
+
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_Lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_Lps = false;
+ }
+}
+
+void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ bool wifi_connected = false, bt_hs_on = false;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+ halbtc8821a1ant_query_bt_info(btcoexist);
+
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8821a1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8821a1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_SCAN_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ if (!wifi_connected) {
+ /* non-connected scan*/
+ btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+ } else {
+ /* wifi is connected*/
+ halbtc8821a1ant_action_wifi_connected_scan(btcoexist);
+ }
+ } else if (BTC_SCAN_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+ if (!wifi_connected) {
+ /* non-connected scan*/
+ halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+ } else {
+ halbtc8821a1ant_action_wifi_connected(btcoexist);
+ }
+ }
+}
+
+void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ bool wifi_connected = false, bt_hs_on = false;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8821a1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8821a1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_ASSOCIATE_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+ } else if (BTC_ASSOCIATE_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+ if (!wifi_connected) {
+ /* non-connected scan*/
+ halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+ } else {
+ halbtc8821a1ant_action_wifi_connected(btcoexist);
+ }
+ }
+}
+
+void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifi_central_chnl;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ if (BTC_MEDIA_CONNECT == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+ }
+
+ /* only 2.4G we need to inform bt the chnl mask*/
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ &wifi_central_chnl);
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifi_central_chnl <= 14)) {
+ /*h2c_parameter[0] = 0x1;*/
+ h2c_parameter[0] = 0x0;
+ h2c_parameter[1] = wifi_central_chnl;
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66 = 0x%x\n",
+ h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ bool bt_hs_on = false;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ coex_sta->special_pkt_period_cnt = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8821a1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8821a1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_PACKET_DHCP == type ||
+ BTC_PACKET_EAPOL == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], special Packet(%d) notify\n", type);
+ btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist);
+ }
+}
+
+void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ bool wifi_connected = false;
+ bool bt_busy = false;
+ bool wifi_under_5g = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+ rsp_source = tmp_buf[0]&0xf;
+ if (rsp_source >= BT_INFO_SRC_8821A_1ANT_MAX)
+ rsp_source = BT_INFO_SRC_8821A_1ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length = %d, hex data = [",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+ if (i == 1)
+ bt_info = tmp_buf[i];
+ if (i == length-1) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmp_buf[i]);
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmp_buf[i]);
+ }
+ }
+
+ if (BT_INFO_SRC_8821A_1ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0]*/
+ coex_sta->bt_info_c2h[rsp_source][2]&0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3]*2+10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT*/
+ /* because bt is reset and loss of the info.*/
+ if (coex_sta->bt_info_ext & BIT1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n");
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (wifi_connected) {
+ ex_halbtc8821a1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_CONNECT);
+ } else {
+ ex_halbtc8821a1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+ }
+
+ if ((coex_sta->bt_info_ext & BIT3) && !wifi_under_5g) {
+ if (!btcoexist->manual_control &&
+ !btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n");
+ halbtc8821a1ant_ignore_wlan_act(btcoexist,
+ FORCE_EXEC,
+ false);
+ }
+ }
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0)
+ if (!(coex_sta->bt_info_ext & BIT4)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n");
+ halbtc8821a1ant_bt_auto_report(btcoexist,
+ FORCE_EXEC, true);
+ }
+#endif
+ }
+
+ /* check BIT2 first ==> check if bt is under inquiry or page scan*/
+ if (bt_info & BT_INFO_8821A_1ANT_B_INQ_PAGE)
+ coex_sta->c2h_bt_inquiry_page = true;
+ else
+ coex_sta->c2h_bt_inquiry_page = false;
+
+ /* set link exist status*/
+ if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ } else {
+ /* connection exists*/
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8821A_1ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8821A_1ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8821A_1ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8821A_1ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ }
+
+ halbtc8821a1ant_update_bt_link_info(btcoexist);
+
+ if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) {
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n");
+ } else if (bt_info == BT_INFO_8821A_1ANT_B_CONNECTION) {
+ /* connection exists but no busy*/
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n");
+ } else if ((bt_info&BT_INFO_8821A_1ANT_B_SCO_ESCO) ||
+ (bt_info&BT_INFO_8821A_1ANT_B_SCO_BUSY)) {
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_SCO_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
+ } else if (bt_info&BT_INFO_8821A_1ANT_B_ACL_BUSY) {
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status)
+ coex_dm->auto_tdma_adjust = false;
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_ACL_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
+ } else {
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_MAX;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n");
+ }
+
+ if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+ bt_busy = true;
+ else
+ bt_busy = false;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Halt notify\n");
+
+ btcoexist->stop_coex_dm = true;
+
+ halbtc8821a1ant_set_ant_path(btcoexist,
+ BTC_ANT_PATH_BT, false, true);
+ halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+ halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+
+ ex_halbtc8821a1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify\n");
+
+ if (BTC_WIFI_PNP_SLEEP == pnp_state) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify to SLEEP\n");
+ btcoexist->stop_coex_dm = true;
+ halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+ halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9);
+ } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify to WAKE UP\n");
+ btcoexist->stop_coex_dm = false;
+ halbtc8821a1ant_init_hw_config(btcoexist, false);
+ halbtc8821a1ant_init_coex_dm(btcoexist);
+ halbtc8821a1ant_query_bt_info(btcoexist);
+ }
+}
+
+void
+ex_halbtc8821a1ant_periodical(
+ struct btc_coexist *btcoexist) {
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], ==========================Periodical===========================\n");
+
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+ board_info->pg_ant_num,
+ board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8821a_1ant,
+ glcoex_ver_8821a_1ant,
+ fw_ver, bt_patch_ver,
+ bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0)
+ halbtc8821a1ant_query_bt_info(btcoexist);
+ halbtc8821a1ant_monitor_bt_ctr(btcoexist);
+ btc8821a1ant_mon_bt_en_dis(btcoexist);
+#else
+ if (halbtc8821a1ant_Is_wifi_status_changed(btcoexist) ||
+ coex_dm->auto_tdma_adjust) {
+ if (coex_sta->special_pkt_period_cnt > 2)
+ halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+ }
+
+ coex_sta->special_pkt_period_cnt++;
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h
new file mode 100644
index 0000000..20e9048
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*===========================================
+ * The following is for 8821A 1ANT BT Co-exist definition
+ *===========================================
+ */
+#define BT_AUTO_REPORT_ONLY_8821A_1ANT 0
+
+#define BT_INFO_8821A_1ANT_B_FTP BIT7
+#define BT_INFO_8821A_1ANT_B_A2DP BIT6
+#define BT_INFO_8821A_1ANT_B_HID BIT5
+#define BT_INFO_8821A_1ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8821A_1ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8821A_1ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8821A_1ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8821A_1ANT_B_CONNECTION BIT0
+
+#define BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \
+ (((_BT_INFO_EXT_&BIT0)) ? true : false)
+
+#define BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT 2
+
+enum _BT_INFO_SRC_8821A_1ANT {
+ BT_INFO_SRC_8821A_1ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8821A_1ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8821A_1ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8821A_1ANT_MAX
+};
+
+enum _BT_8821A_1ANT_BT_STATUS {
+ BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1,
+ BT_8821A_1ANT_BT_STATUS_INQ_PAGE = 0x2,
+ BT_8821A_1ANT_BT_STATUS_ACL_BUSY = 0x3,
+ BT_8821A_1ANT_BT_STATUS_SCO_BUSY = 0x4,
+ BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5,
+ BT_8821A_1ANT_BT_STATUS_MAX
+};
+
+enum _BT_8821A_1ANT_WIFI_STATUS {
+ BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5,
+ BT_8821A_1ANT_WIFI_STATUS_MAX
+};
+
+enum BT_8821A_1ANT_COEX_ALGO {
+ BT_8821A_1ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8821A_1ANT_COEX_ALGO_SCO = 0x1,
+ BT_8821A_1ANT_COEX_ALGO_HID = 0x2,
+ BT_8821A_1ANT_COEX_ALGO_A2DP = 0x3,
+ BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS = 0x4,
+ BT_8821A_1ANT_COEX_ALGO_PANEDR = 0x5,
+ BT_8821A_1ANT_COEX_ALGO_PANHS = 0x6,
+ BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7,
+ BT_8821A_1ANT_COEX_ALGO_PANEDR_HID = 0x8,
+ BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9,
+ BT_8821A_1ANT_COEX_ALGO_HID_A2DP = 0xa,
+ BT_8821A_1ANT_COEX_ALGO_MAX = 0xb,
+};
+
+struct coex_dm_8821a_1ant {
+ /* fw mechanism */
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool auto_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+ u8 pre_lps;
+ u8 cur_lps;
+ u8 pre_rpwm;
+ u8 cur_rpwm;
+
+ /* sw mechanism */
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ u32 pre_val_0x6c0;
+ u32 cur_val_0x6c0;
+ u32 pre_val_0x6c4;
+ u32 cur_val_0x6c4;
+ u32 pre_val_0x6c8;
+ u32 cur_val_0x6c8;
+ u8 pre_val_0x6cc;
+ u8 cur_val_0x6cc;
+ /* Auto Rate Fallback Retry cnt */
+ u32 backup_arfr_cnt1;
+ /* Auto Rate Fallback Retry cnt */
+ u32 backup_arfr_cnt2;
+ u16 backup_retry_limit;
+ u8 backup_ampdu_max_time;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+
+ u32 pre_ra_mask;
+ u32 cur_ra_mask;
+ u8 pre_arfr_type;
+ u8 cur_arfr_type;
+ u8 pre_retry_limit_type;
+ u8 cur_retry_limit_type;
+ u8 pre_ampdu_time_type;
+ u8 cur_ampdu_time_type;
+
+ u8 error_condition;
+};
+
+struct coex_sta_8821a_1ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+
+ bool under_Lps;
+ bool under_ips;
+ u32 special_pkt_period_cnt;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8821A_1ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8821A_1ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/*===========================================
+ * The following is interface which will notify coex module.
+ *===========================================
+ */
+void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate);
+void ex_halbtc8821a1ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code,
+ u8 op_len, u8 *data);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c
new file mode 100644
index 0000000..2322b7d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c
@@ -0,0 +1,3914 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*============================================================
+ * Description:
+ *
+ * This file is for RTL8821A Co-exist mechanism
+ *
+ * History
+ * 2012/08/22 Cosa first check in.
+ * 2012/11/14 Cosa Revise for 8821A 2Ant out sourcing.
+ *
+ *============================================================
+ */
+
+/*============================================================
+ * include files
+ *============================================================
+*/
+#include "halbt_precomp.h"
+/*============================================================
+ * Global variables, these are static variables
+ *============================================================
+ */
+static struct coex_dm_8821a_2ant glcoex_dm_8821a_2ant;
+static struct coex_dm_8821a_2ant *coex_dm = &glcoex_dm_8821a_2ant;
+static struct coex_sta_8821a_2ant glcoex_sta_8821a_2ant;
+static struct coex_sta_8821a_2ant *coex_sta = &glcoex_sta_8821a_2ant;
+
+static const char *const glbt_info_src_8821a_2ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8821a_2ant = 20130618;
+static u32 glcoex_ver_8821a_2ant = 0x5050;
+
+/*============================================================
+ * local function proto type if needed
+ *============================================================
+ *============================================================
+ * local function start with halbtc8821a2ant_
+ *============================================================
+ */
+static u8 halbtc8821a2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ long bt_rssi = 0;
+ u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+ bt_rssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ long tmp = rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT;
+ if (bt_rssi >= tmp) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (bt_rssi >=
+ (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Medium\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh1) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+ return bt_rssi_state;
+}
+
+static u8 halbtc8821a2ant_wifi_rssi_state(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num,
+ u8 rssi_thresh, u8 rssi_thresh1)
+{
+ long wifi_rssi = 0;
+ u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifi_rssi >= (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Medium\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh1) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ }
+ coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+ return wifi_rssi_state;
+}
+
+static void btc8821a2ant_mon_bt_en_dis(struct btc_coexist *btcoexist)
+{
+ static bool pre_bt_disabled;
+ static u32 bt_disable_cnt;
+ bool bt_active = true, bt_disabled = false;
+
+ /* This function check if bt is disabled*/
+
+ if (coex_sta->high_priority_tx == 0 &&
+ coex_sta->high_priority_rx == 0 &&
+ coex_sta->low_priority_tx == 0 &&
+ coex_sta->low_priority_rx == 0)
+ bt_active = false;
+ if (coex_sta->high_priority_tx == 0xffff &&
+ coex_sta->high_priority_rx == 0xffff &&
+ coex_sta->low_priority_tx == 0xffff &&
+ coex_sta->low_priority_rx == 0xffff)
+ bt_active = false;
+ if (bt_active) {
+ bt_disable_cnt = 0;
+ bt_disabled = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is enabled !!\n");
+ } else {
+ bt_disable_cnt++;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], bt all counters = 0, %d times!!\n",
+ bt_disable_cnt);
+ if (bt_disable_cnt >= 2) {
+ bt_disabled = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is disabled !!\n");
+ }
+ }
+ if (pre_bt_disabled != bt_disabled) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is from %s to %s!!\n",
+ (pre_bt_disabled ? "disabled" : "enabled"),
+ (bt_disabled ? "disabled" : "enabled"));
+ pre_bt_disabled = bt_disabled;
+ }
+}
+
+static void halbtc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_txrx, reg_lp_txrx, u4tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_txrx = 0x770;
+ reg_lp_txrx = 0x774;
+
+ u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+ reg_hp_tx = u4tmp & MASKLWORD;
+ reg_hp_rx = (u4tmp & MASKHWORD)>>16;
+
+ u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+ reg_lp_tx = u4tmp & MASKLWORD;
+ reg_lp_rx = (u4tmp & MASKHWORD)>>16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+ reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+ reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+
+ /* reset counter */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8821a2ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static u8 halbtc8821a2ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ bool bt_hs_on = false;
+ u8 algorithm = BT_8821A_2ANT_COEX_ALGO_UNDEFINED;
+ u8 num_of_diff_profile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ /*for win-8 stack HID report error*/
+ /* sync BTInfo with BT firmware and stack */
+ if (!stack_info->hid_exist)
+ stack_info->hid_exist = coex_sta->hid_exist;
+ /* when stack HID report error, here we use the info from bt fw. */
+ if (!stack_info->bt_link_exist)
+ stack_info->bt_link_exist = coex_sta->bt_link_exist;
+
+ if (!coex_sta->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], No profile exists!!!\n");
+ return algorithm;
+ }
+
+ if (coex_sta->sco_exist)
+ num_of_diff_profile++;
+ if (coex_sta->hid_exist)
+ num_of_diff_profile++;
+ if (coex_sta->pan_exist)
+ num_of_diff_profile++;
+ if (coex_sta->a2dp_exist)
+ num_of_diff_profile++;
+
+ if (num_of_diff_profile == 1) {
+ if (coex_sta->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_SCO;
+ } else {
+ if (coex_sta->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID;
+ } else if (coex_sta->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2DP only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP;
+ } else if (coex_sta->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], PAN(HS) only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], PAN(EDR) only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 2) {
+ if (coex_sta->sco_exist) {
+ if (coex_sta->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (coex_sta->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP ==> SCO\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (coex_sta->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (coex_sta->hid_exist &&
+ coex_sta->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP;
+ } else if (coex_sta->hid_exist &&
+ coex_sta->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (coex_sta->pan_exist &&
+ coex_sta->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2DP + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 3) {
+ if (coex_sta->sco_exist) {
+ if (coex_sta->hid_exist &&
+ coex_sta->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + A2DP ==> HID\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (coex_sta->hid_exist &&
+ coex_sta->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (coex_sta->pan_exist &&
+ coex_sta->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (coex_sta->hid_exist &&
+ coex_sta->pan_exist &&
+ coex_sta->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile >= 3) {
+ if (coex_sta->sco_exist) {
+ if (coex_sta->hid_exist &&
+ coex_sta->pan_exist &&
+ coex_sta->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n");
+
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+ return algorithm;
+}
+
+static bool halbtc8821a2ant_need_to_dec_bt_pwr(struct btc_coexist *btcoexist)
+{
+ bool ret = false;
+ bool bt_hs_on = false, wifi_connected = false;
+ long bt_hs_rssi = 0;
+ u8 bt_rssi_state;
+
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on))
+ return false;
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected))
+ return false;
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi))
+ return false;
+
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ if (wifi_connected) {
+ if (bt_hs_on) {
+ if (bt_hs_rssi > 37) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], Need to decrease bt power for HS mode!!\n");
+ ret = true;
+ }
+ } else {
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], Need to decrease bt power for Wifi is connected!!\n");
+ ret = true;
+ }
+ }
+ }
+ return ret;
+}
+
+static void btc8821a2ant_set_fw_dac_swing_lev(struct btc_coexist *btcoexist,
+ u8 dac_swing_lvl)
+{
+ u8 h2c_parameter[1] = {0};
+
+ /* There are several type of dacswing
+ * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6
+ */
+ h2c_parameter[0] = dac_swing_lvl;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist,
+ bool dec_bt_pwr)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (dec_bt_pwr)
+ h2c_parameter[0] |= BIT1;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], decrease Bt Power : %s, FW write 0x62 = 0x%x\n",
+ (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_dec_bt_pwr(struct btc_coexist *btcoexist,
+ bool force_exec, bool dec_bt_pwr)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s Dec BT power = %s\n",
+ (force_exec ? "force to" : ""),
+ ((dec_bt_pwr) ? "ON" : "OFF"));
+ coex_dm->cur_dec_bt_pwr = dec_bt_pwr;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_dec_bt_pwr = %d, cur_dec_bt_pwr = %d\n",
+ coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr);
+
+ if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr)
+ return;
+ }
+ halbtc8821a2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr);
+
+ coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr;
+}
+
+static void btc8821a2ant_set_fw_bt_lna_constr(struct btc_coexist *btcoexist,
+ bool bt_lna_cons_on)
+{
+ u8 h2c_parameter[2] = {0};
+
+ h2c_parameter[0] = 0x3; /* opCode, 0x3 = BT_SET_LNA_CONSTRAIN */
+
+ if (bt_lna_cons_on)
+ h2c_parameter[1] |= BIT0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set BT LNA Constrain: %s, FW write 0x69 = 0x%x\n",
+ (bt_lna_cons_on ? "ON!!" : "OFF!!"),
+ h2c_parameter[0]<<8|h2c_parameter[1]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter);
+}
+
+static void btc8821a2_set_bt_lna_const(struct btc_coexist *btcoexist,
+ bool force_exec, bool bt_lna_cons_on)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s BT Constrain = %s\n",
+ (force_exec ? "force" : ""),
+ ((bt_lna_cons_on) ? "ON" : "OFF"));
+ coex_dm->cur_bt_lna_constrain = bt_lna_cons_on;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_bt_lna_constrain = %d,cur_bt_lna_constrain = %d\n",
+ coex_dm->pre_bt_lna_constrain,
+ coex_dm->cur_bt_lna_constrain);
+
+ if (coex_dm->pre_bt_lna_constrain ==
+ coex_dm->cur_bt_lna_constrain)
+ return;
+ }
+ btc8821a2ant_set_fw_bt_lna_constr(btcoexist,
+ coex_dm->cur_bt_lna_constrain);
+
+ coex_dm->pre_bt_lna_constrain = coex_dm->cur_bt_lna_constrain;
+}
+
+static void halbtc8821a2ant_set_fw_bt_psd_mode(struct btc_coexist *btcoexist,
+ u8 bt_psd_mode)
+{
+ u8 h2c_parameter[2] = {0};
+
+ h2c_parameter[0] = 0x2; /* opCode, 0x2 = BT_SET_PSD_MODE */
+
+ h2c_parameter[1] = bt_psd_mode;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set BT PSD mode = 0x%x, FW write 0x69 = 0x%x\n",
+ h2c_parameter[1],
+ h2c_parameter[0]<<8|h2c_parameter[1]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter);
+}
+
+static void halbtc8821a2ant_set_bt_psd_mode(struct btc_coexist *btcoexist,
+ bool force_exec, u8 bt_psd_mode)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s BT PSD mode = 0x%x\n",
+ (force_exec ? "force" : ""), bt_psd_mode);
+ coex_dm->cur_bt_psd_mode = bt_psd_mode;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_bt_psd_mode = 0x%x, cur_bt_psd_mode = 0x%x\n",
+ coex_dm->pre_bt_psd_mode, coex_dm->cur_bt_psd_mode);
+
+ if (coex_dm->pre_bt_psd_mode == coex_dm->cur_bt_psd_mode)
+ return;
+ }
+ halbtc8821a2ant_set_fw_bt_psd_mode(btcoexist,
+ coex_dm->cur_bt_psd_mode);
+
+ coex_dm->pre_bt_psd_mode = coex_dm->cur_bt_psd_mode;
+}
+
+static void halbtc8821a2ant_set_bt_auto_report(struct btc_coexist *btcoexist,
+ bool enable_auto_report)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (enable_auto_report)
+ h2c_parameter[0] |= BIT0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+ (enable_auto_report ? "Enabled!!" : "Disabled!!"),
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_bt_auto_report(struct btc_coexist *btcoexist,
+ bool force_exec,
+ bool enable_auto_report)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s BT Auto report = %s\n",
+ (force_exec ? "force to" : ""),
+ ((enable_auto_report) ? "Enabled" : "Disabled"));
+ coex_dm->cur_bt_auto_report = enable_auto_report;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_bt_auto_report = %d, cur_bt_auto_report = %d\n",
+ coex_dm->pre_bt_auto_report,
+ coex_dm->cur_bt_auto_report);
+
+ if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+ return;
+ }
+ halbtc8821a2ant_set_bt_auto_report(btcoexist,
+ coex_dm->cur_bt_auto_report);
+
+ coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void halbtc8821a2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist,
+ bool force_exec,
+ u8 fw_dac_swing_lvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set FW Dac Swing level = %d\n",
+ (force_exec ? "force to" : ""), fw_dac_swing_lvl);
+ coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_fw_dac_swing_lvl = %d, cur_fw_dac_swing_lvl = %d\n",
+ coex_dm->pre_fw_dac_swing_lvl,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ if (coex_dm->pre_fw_dac_swing_lvl ==
+ coex_dm->cur_fw_dac_swing_lvl)
+ return;
+ }
+
+ btc8821a2ant_set_fw_dac_swing_lev(btcoexist,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl;
+}
+
+static void btc8821a2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist,
+ bool rx_rf_shrink_on)
+{
+ if (rx_rf_shrink_on) {
+ /* Shrink RF Rx LPF corner */
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Shrink RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+ 0xfffff, 0xffffc);
+ } else {
+ /* Resume RF Rx LPF corner
+ * After initialized, we can use coex_dm->bt_rf0x1e_backup
+ */
+ if (btcoexist->initilized) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Resume RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A,
+ 0x1e, 0xfffff,
+ coex_dm->bt_rf0x1e_backup);
+ }
+ }
+}
+
+static void halbtc8821a2ant_RfShrink(struct btc_coexist *btcoexist,
+ bool force_exec, bool rx_rf_shrink_on)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn Rx RF Shrink = %s\n",
+ (force_exec ? "force to" : ""),
+ ((rx_rf_shrink_on) ? "ON" : "OFF"));
+ coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_rf_rx_lpf_shrink = %d, cur_rf_rx_lpf_shrink = %d\n",
+ coex_dm->pre_rf_rx_lpf_shrink,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ if (coex_dm->pre_rf_rx_lpf_shrink ==
+ coex_dm->cur_rf_rx_lpf_shrink)
+ return;
+ }
+ btc8821a2ant_set_sw_rf_rx_lpf_corner(btcoexist,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink;
+}
+
+static void btc8821a2ant_SetSwPenTxRateAdapt(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ u8 h2c_parameter[6] = {0};
+
+ h2c_parameter[0] = 0x6; /* opCode, 0x6 = Retry_Penalty */
+
+ if (low_penalty_ra) {
+ h2c_parameter[1] |= BIT0;
+ /*normal rate except MCS7/6/5, OFDM54/48/36 */
+ h2c_parameter[2] = 0x00;
+ /*MCS7 or OFDM54 */
+ h2c_parameter[3] = 0xf7;
+ /*MCS6 or OFDM48 */
+ h2c_parameter[4] = 0xf8;
+ /*MCS5 or OFDM36 */
+ h2c_parameter[5] = 0xf9;
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set WiFi Low-Penalty Retry: %s",
+ (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8821a2ant_low_penalty_ra(struct btc_coexist *btcoexist,
+ bool force_exec, bool low_penalty_ra)
+{
+ /*return;*/
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn LowPenaltyRA = %s\n",
+ (force_exec ? "force to" : ""),
+ ((low_penalty_ra) ? "ON" : "OFF"));
+ coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_low_penalty_ra = %d, cur_low_penalty_ra = %d\n",
+ coex_dm->pre_low_penalty_ra,
+ coex_dm->cur_low_penalty_ra);
+
+ if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+ return;
+ }
+ btc8821a2ant_SetSwPenTxRateAdapt(btcoexist,
+ coex_dm->cur_low_penalty_ra);
+
+ coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8821a2ant_set_dac_swing_reg(struct btc_coexist *btcoexist,
+ u32 level)
+{
+ u8 val = (u8)level;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Write SwDacSwing = 0x%x\n", level);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc5b, 0x3e, val);
+}
+
+static void btc8821a2ant_set_sw_full_dac_swing(struct btc_coexist *btcoexist,
+ bool sw_dac_swing_on,
+ u32 sw_dac_swing_lvl)
+{
+ if (sw_dac_swing_on)
+ halbtc8821a2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl);
+ else
+ halbtc8821a2ant_set_dac_swing_reg(btcoexist, 0x18);
+}
+
+static void halbtc8821a2ant_dac_swing(struct btc_coexist *btcoexist,
+ bool force_exec, bool dac_swing_on,
+ u32 dac_swing_lvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn DacSwing = %s, dac_swing_lvl = 0x%x\n",
+ (force_exec ? "force to" : ""),
+ ((dac_swing_on) ? "ON" : "OFF"),
+ dac_swing_lvl);
+ coex_dm->cur_dac_swing_on = dac_swing_on;
+ coex_dm->cur_dac_swing_lvl = dac_swing_lvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_dac_swing_on = %d, pre_dac_swing_lvl = 0x%x, cur_dac_swing_on = %d, cur_dac_swing_lvl = 0x%x\n",
+ coex_dm->pre_dac_swing_on,
+ coex_dm->pre_dac_swing_lvl,
+ coex_dm->cur_dac_swing_on,
+ coex_dm->cur_dac_swing_lvl);
+
+ if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) &&
+ (coex_dm->pre_dac_swing_lvl ==
+ coex_dm->cur_dac_swing_lvl))
+ return;
+ }
+ mdelay(30);
+ btc8821a2ant_set_sw_full_dac_swing(btcoexist, dac_swing_on,
+ dac_swing_lvl);
+
+ coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on;
+ coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl;
+}
+
+static void halbtc8821a2ant_set_adc_back_off(struct btc_coexist *btcoexist,
+ bool adc_back_off)
+{
+ if (adc_back_off) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB BackOff Level On!\n");
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB BackOff Level Off!\n");
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1);
+ }
+}
+
+static void halbtc8821a2ant_adc_back_off(struct btc_coexist *btcoexist,
+ bool force_exec, bool adc_back_off)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn AdcBackOff = %s\n",
+ (force_exec ? "force to" : ""),
+ ((adc_back_off) ? "ON" : "OFF"));
+ coex_dm->cur_adc_back_off = adc_back_off;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_adc_back_off = %d, cur_adc_back_off = %d\n",
+ coex_dm->pre_adc_back_off, coex_dm->cur_adc_back_off);
+
+ if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off)
+ return;
+ }
+ halbtc8821a2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off);
+
+ coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off;
+}
+
+static void halbtc8821a2ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8821a2ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec, u32 val0x6c0,
+ u32 val0x6c4, u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+ (force_exec ? "force to" : ""),
+ val0x6c0, val0x6c4, val0x6c8, val0x6cc);
+ coex_dm->cur_val0x6c0 = val0x6c0;
+ coex_dm->cur_val0x6c4 = val0x6c4;
+ coex_dm->cur_val0x6c8 = val0x6c8;
+ coex_dm->cur_val0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_val0x6c0 = 0x%x, pre_val0x6c4 = 0x%x, pre_val0x6c8 = 0x%x, pre_val0x6cc = 0x%x !!\n",
+ coex_dm->pre_val0x6c0,
+ coex_dm->pre_val0x6c4,
+ coex_dm->pre_val0x6c8,
+ coex_dm->pre_val0x6cc);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], cur_val0x6c0 = 0x%x, cur_val0x6c4 = 0x%x, cur_val0x6c8 = 0x%x, cur_val0x6cc = 0x%x !!\n",
+ coex_dm->cur_val0x6c0,
+ coex_dm->cur_val0x6c4,
+ coex_dm->cur_val0x6c8,
+ coex_dm->cur_val0x6cc);
+
+ if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+ (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+ (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+ (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+ return;
+ }
+ halbtc8821a2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8,
+ val0x6cc);
+
+ coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+ coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+ coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+ coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void halbtc8821a2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoex,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0;/* function enable */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoex->btc_fill_h2c(btcoex, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n",
+ coex_dm->pre_ignore_wlan_act,
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ halbtc8821a2ant_set_fw_ignore_wlan_act(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8821a2ant_set_fw_pstdma(struct btc_coexist *btcoexist,
+ u8 byte1, u8 byte2, u8 byte3,
+ u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5];
+
+ h2c_parameter[0] = byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = byte5;
+
+ coex_dm->ps_tdma_para[0] = byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1]<<24|
+ h2c_parameter[2]<<16|
+ h2c_parameter[3]<<8|
+ h2c_parameter[4]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void btc8821a2ant_sw_mech1(struct btc_coexist *btcoexist,
+ bool shrink_rx_lpf,
+ bool low_penalty_ra, bool limited_dig,
+ bool bt_lna_constrain)
+{
+ u32 wifi_bw;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_HT40 != wifi_bw) {
+ /*only shrink RF Rx LPF for HT40*/
+ if (shrink_rx_lpf)
+ shrink_rx_lpf = false;
+ }
+
+ halbtc8821a2ant_RfShrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf);
+ halbtc8821a2ant_low_penalty_ra(btcoexist,
+ NORMAL_EXEC, low_penalty_ra);
+
+ /* no limited DIG
+ * btc8821a2_set_bt_lna_const(btcoexist,
+ NORMAL_EXEC, bBTLNAConstrain);
+ */
+}
+
+static void btc8821a2ant_sw_mech2(struct btc_coexist *btcoexist,
+ bool agc_table_shift,
+ bool adc_back_off, bool sw_dac_swing,
+ u32 dac_swing_lvl)
+{
+ /* halbtc8821a2ant_AgcTable(btcoexist, NORMAL_EXEC, bAGCTableShift); */
+ halbtc8821a2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off);
+ halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing,
+ sw_dac_swing);
+}
+
+static void halbtc8821a2ant_set_ant_path(struct btc_coexist *btcoexist,
+ u8 ant_pos_type, bool init_hw_cfg,
+ bool wifi_off)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 u4tmp = 0;
+ u8 h2c_parameter[2] = {0};
+
+ if (init_hw_cfg) {
+ /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT */
+ u4tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u4tmp &= ~BIT23;
+ u4tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u4tmp);
+
+ btcoexist->btc_write_4byte(btcoexist, 0x974, 0x3ff);
+ btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77);
+
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+ /* tell firmware "antenna inverse" ==>
+ * WRONG firmware antenna control code.
+ * ==>need fw to fix
+ */
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1;
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /* tell firmware "no antenna inverse"
+ * ==> WRONG firmware antenna control code.
+ * ==>need fw to fix
+ */
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1;
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* ext switch setting */
+ switch (ant_pos_type) {
+ case BTC_ANT_WIFI_AT_MAIN:
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1);
+ break;
+ case BTC_ANT_WIFI_AT_AUX:
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2);
+ break;
+ }
+}
+
+static void halbtc8821a2ant_ps_tdma(struct btc_coexist *btcoexist,
+ bool force_exec, bool turn_on, u8 type)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn %s PS TDMA, type = %d\n",
+ (force_exec ? "force to" : ""), (turn_on ? "ON" : "OFF"),
+ type);
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_ps_tdma_on = %d, cur_ps_tdma_on = %d!!\n",
+ coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_ps_tdma = %d, cur_ps_tdma = %d!!\n",
+ coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma);
+
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ case 1:
+ default:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ case 2:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x90);
+ break;
+ case 3:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf1, 0x90);
+ break;
+ case 4:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x10,
+ 0x03, 0xf1, 0x90);
+ break;
+ case 5:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0x60, 0x90);
+ break;
+ case 6:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0x60, 0x90);
+ break;
+ case 7:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0x70, 0x90);
+ break;
+ case 8:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x10,
+ 0x3, 0x70, 0x90);
+ break;
+ case 9:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ case 10:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x90);
+ break;
+ case 11:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+ 0xa, 0xe1, 0x90);
+ break;
+ case 12:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0xe1, 0x90);
+ break;
+ case 13:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0x60, 0x90);
+ break;
+ case 14:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3,
+ 0x12, 0x12, 0x60, 0x90);
+ break;
+ case 15:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+ 0xa, 0x60, 0x90);
+ break;
+ case 16:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0x60, 0x90);
+ break;
+ case 17:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x2f,
+ 0x2f, 0x60, 0x90);
+ break;
+ case 18:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0xe1, 0x90);
+ break;
+ case 19:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0xe1, 0x90);
+ break;
+ case 20:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0x60, 0x90);
+ break;
+ case 21:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x15,
+ 0x03, 0x70, 0x90);
+ break;
+ case 71:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ }
+ } else {
+ /* disable PS tdma */
+ switch (type) {
+ case 0:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x40, 0x0);
+ break;
+ case 1:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x48, 0x0);
+ break;
+ default:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x40, 0x0);
+ break;
+ }
+ }
+
+ /* update pre state */
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static void halbtc8821a2ant_coex_all_off(struct btc_coexist *btcoexist)
+{
+ /* fw all off */
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ /* sw all off */
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+ /* hw all off */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+ 0x55555555, 0x55555555, 0xffff, 0x3);
+}
+
+static void halbtc8821a2ant_coex_under_5g(struct btc_coexist *btcoexist)
+{
+ halbtc8821a2ant_coex_all_off(btcoexist);
+}
+
+static void halbtc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* force to reset coex mechanism */
+ halbtc8821a2ant_coex_table(btcoexist, FORCE_EXEC, 0x55555555,
+ 0x55555555, 0xffff, 0x3);
+
+ halbtc8821a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+}
+
+static void halbtc8821a2ant_bt_inquiry_page(struct btc_coexist *btcoexist)
+{
+ bool low_pwr_disable = true;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+}
+
+static bool halbtc8821a2ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ bool common = false, wifi_connected = false, wifi_busy = false;
+ bool low_pwr_disable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+
+ if (!wifi_connected &&
+ BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi IPS + BT IPS!!\n");
+
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+ common = true;
+ } else if (wifi_connected &&
+ (BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status)) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Busy + BT IPS!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi LPS + BT IPS!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ }
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+ common = true;
+ } else if (!wifi_connected &&
+ (BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status)) {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi IPS + BT LPS!!\n");
+
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+ common = true;
+ } else if (wifi_connected &&
+ (BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status)) {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Busy + BT LPS!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi LPS + BT LPS!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ }
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, true, true, true, true);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+ common = true;
+ } else if (!wifi_connected &&
+ (BT_8821A_2ANT_BT_STATUS_NON_IDLE ==
+ coex_dm->bt_status)) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi IPS + BT Busy!!\n");
+
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+
+ common = true;
+ } else {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Busy + BT Busy!!\n");
+ common = false;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi LPS + BT Busy!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC, true, 21);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC, false);
+
+ common = true;
+ }
+ btc8821a2ant_sw_mech1(btcoexist, true, true, true, true);
+ }
+ return common;
+}
+
+static void btc8821a2_int1(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+
+ if (coex_dm->cur_ps_tdma == 71) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 71) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ }
+ }
+ }
+}
+
+static void btc8821a2_int2(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ }
+ }
+ }
+}
+
+static void btc8821a2_int3(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ }
+}
+
+static void btc8821a2ant_tdma_dur_adj(struct btc_coexist *btcoexist,
+ bool sco_hid, bool tx_pause,
+ u8 max_interval)
+{
+ static long up, dn, m, n, wait_count;
+ /* 0: no change, +1: increase WiFi duration,
+ * -1: decrease WiFi duration
+ */
+ int result;
+ u8 retry_count = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjust()\n");
+
+ if (coex_dm->reset_tdma_adjust) {
+ coex_dm->reset_tdma_adjust = false;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+ if (sco_hid) {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (max_interval == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (max_interval == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ } else {
+ if (max_interval == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (max_interval == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (max_interval == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ } else {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (max_interval == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (max_interval == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ }
+ } else {
+ if (max_interval == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (max_interval == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (max_interval == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ }
+ }
+ }
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ } else {
+ /* accquire the BT TRx retry count from BT_Info byte2 */
+ retry_count = coex_sta->bt_retry_cnt;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], retry_count = %d\n", retry_count);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], up = %d, dn = %d, m = %d, n = %d, wait_count = %d\n",
+ (int)up, (int)dn, (int)m, (int)n, (int)wait_count);
+ result = 0;
+ wait_count++;
+
+ if (retry_count == 0) {
+ /* no retry in the last 2-second duration */
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ /* if (retry count == 0) for 2*n seconds,
+ * make WiFi duration wider
+ */
+ wait_count = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Increase wifi duration!!\n");
+ }
+ } else if (retry_count <= 3) {
+ /* <=3 retry in the last 2-second duration */
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ /* if retry count< 3 for 2*2 seconds,
+ * shrink wifi duration
+ */
+ if (wait_count <= 2)
+ m++; /* avoid bounce in two levels */
+ else
+ m = 1;
+ /* m max value is 20, max time is 120 second,
+ * recheck if adjust WiFi duration.
+ */
+ if (m >= 20)
+ m = 20;
+
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+ }
+ } else {
+ /* retry count > 3, if retry count > 3 happens once,
+ * shrink WiFi duration
+ */
+ if (wait_count == 1)
+ m++; /* avoid bounce in two levels */
+ else
+ m = 1;
+ /* m max value is 20, max time is 120 second,
+ * recheck if adjust WiFi duration.
+ */
+ if (m >= 20)
+ m = 20;
+
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], max Interval = %d\n", max_interval);
+ if (max_interval == 1)
+ btc8821a2_int1(btcoexist, tx_pause, result);
+ else if (max_interval == 2)
+ btc8821a2_int2(btcoexist, tx_pause, result);
+ else if (max_interval == 3)
+ btc8821a2_int3(btcoexist, tx_pause, result);
+ }
+
+ /* if current PsTdma not match with the recorded one
+ * (when scan, dhcp...), then we have to adjust it back to
+ * the previous recorded one.
+ */
+ if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) {
+ bool scan = false, link = false, roam = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma = %d, recordPsTdma = %d\n",
+ coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (!scan && !link && !roam) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
+ coex_dm->tdma_adj_type);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n");
+ }
+ }
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6);
+}
+
+/* SCO only or SCO+PAN(HS)*/
+static void halbtc8821a2ant_action_sco(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for SCO quality at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+ 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3);
+ } else {
+ /* for SCO quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+ 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism
+ * halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ */
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0); /*for voice quality*/
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0); /*for voice quality*/
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism
+ * halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0); /*for voice quality*/
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0); /*for voice quality*/
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5aea5aea, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8821a2ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ /* fw dac swing is called in btc8821a2ant_tdma_dur_adj()
+ * halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ */
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 1);
+ } else {
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 1);
+ } else {
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state, bt_info_ext;
+ u32 wifi_bw;
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ /*fw dac swing is called in btc8821a2ant_tdma_dur_adj()
+ *halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ */
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if (bt_info_ext&BIT0) {
+ /*a2dp basic rate*/
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2);
+ } else {
+ /*a2dp edr rate*/
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5aff5aff, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5aff5aff, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* PAN(HS) only */
+static void halbtc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+ true);
+ } else {
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+ false);
+ }
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC, true);
+ } else {
+ halbtc8821a2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC, false);
+ }
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* PAN(EDR)+A2DP */
+static void halbtc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state, bt_info_ext;
+ u32 wifi_bw;
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ false, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ false, 3);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ true, 3);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ };
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ false, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ false, 3);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ true, 3);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5f5a5f, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5f5a5f, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 3);
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state, bt_info_ext;
+ u32 wifi_bw;
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ false, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ false, 3);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state, bt_info_ext;
+ u32 wifi_bw;
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5f5b5f5b, 0xffffff, 0x3);
+ } else {
+ /*for HID quality & wifi performance balance at 11n mode*/
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5f5b5f5b, 0xffffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /*a2dp basic rate*/
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ } else {
+ /*a2dp edr rate*/
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ bool wifi_under_5g = false;
+ u8 algorithm = 0;
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Manual control!!!\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+ if (wifi_under_5g) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n");
+ halbtc8821a2ant_coex_under_5g(btcoexist);
+ return;
+ }
+
+ algorithm = halbtc8821a2ant_action_algorithm(btcoexist);
+ if (coex_sta->c2h_bt_inquiry_page &&
+ (BT_8821A_2ANT_COEX_ALGO_PANHS != algorithm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT is under inquiry/page scan !!\n");
+ halbtc8821a2ant_bt_inquiry_page(btcoexist);
+ return;
+ }
+
+ coex_dm->cur_algorithm = algorithm;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm);
+
+ if (halbtc8821a2ant_is_common_action(btcoexist)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant common.\n");
+ coex_dm->reset_tdma_adjust = true;
+ } else {
+ if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], pre_algorithm = %d, cur_algorithm = %d\n",
+ coex_dm->pre_algorithm, coex_dm->cur_algorithm);
+ coex_dm->reset_tdma_adjust = true;
+ }
+ switch (coex_dm->cur_algorithm) {
+ case BT_8821A_2ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = SCO.\n");
+ halbtc8821a2ant_action_sco(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HID.\n");
+ halbtc8821a2ant_action_hid(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = A2DP.\n");
+ halbtc8821a2ant_action_a2dp(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n");
+ halbtc8821a2ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n");
+ halbtc8821a2ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HS mode.\n");
+ halbtc8821a2ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n");
+ halbtc8821a2ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n");
+ halbtc8821a2ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n");
+ btc8821a2ant_act_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n");
+ halbtc8821a2ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n");
+ halbtc8821a2ant_coex_all_off(btcoexist);
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+/*============================================================
+ *work around function start with wa_halbtc8821a2ant_
+ *============================================================
+ *============================================================
+ * extern function start with EXhalbtc8821a2ant_
+ *============================================================
+ */
+void ex_halbtc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ u8 u1tmp = 0;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 2Ant Init HW Config!!\n");
+
+ /* backup rf 0x1e value */
+ coex_dm->bt_rf0x1e_backup =
+ btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff);
+
+ /* 0x790[5:0] = 0x5 */
+ u1tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u1tmp &= 0xc0;
+ u1tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u1tmp);
+
+ /*Antenna config */
+ halbtc8821a2ant_set_ant_path(btcoexist,
+ BTC_ANT_WIFI_AT_MAIN, true, false);
+
+ /* PTA parameter */
+ halbtc8821a2ant_coex_table(btcoexist,
+ FORCE_EXEC, 0x55555555, 0x55555555,
+ 0xffff, 0x3);
+
+ /* Enable counter statistics */
+ /*0x76e[3] = 1, WLAN_Act control by PTA*/
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+}
+
+void
+ex_halbtc8821a2ant_init_coex_dm(
+ struct btc_coexist *btcoexist
+ )
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+
+ halbtc8821a2ant_init_coex_dm(btcoexist);
+}
+
+void
+ex_halbtc8821a2ant_display_coex_info(
+ struct btc_coexist *btcoexist
+ )
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ u8 *cli_buf = btcoexist->cli_buf;
+ u8 u1tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+ u32 u4tmp[4];
+ bool roam = false, scan = false, link = false, wifi_under_5g = false;
+ bool bt_hs_on = false, wifi_busy = false;
+ long wifi_rssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir;
+ u8 wifi_dot_11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[BT Coexist info]============");
+ CL_PRINTF(cli_buf);
+
+ if (!board_info->bt_exist) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
+ CL_PRINTF(cli_buf);
+ return;
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:",
+ board_info->pg_ant_num, board_info->btdm_ant_num);
+ CL_PRINTF(cli_buf);
+
+ if (btcoexist->manual_control) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s", "[Action Manual control]!!");
+ CL_PRINTF(cli_buf);
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %s / %d", "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_dot_11_chnl);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsMode(HsChnl)",
+ wifi_dot_11_chnl, bt_hs_on, wifi_hs_chnl);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info",
+ coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+ coex_dm->wifi_chnl_info[2]);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %ld/ %ld", "Wifi rssi/ HS rssi",
+ wifi_rssi, bt_hs_rssi);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan",
+ link, roam, scan);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U4_WIFI_BW, &wifi_bw);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %s / %s/ %s ", "Wifi status",
+ (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]",
+ ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+ ((BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status)
+ ? "idle" : ((BT_8821A_2ANT_BT_STATUS_CON_IDLE ==
+ coex_dm->bt_status) ? "connected-idle" : "busy"))),
+ coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+ CL_PRINTF(cli_buf);
+
+ if (stack_info->profile_notified) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP",
+ stack_info->sco_exist, stack_info->hid_exist,
+ stack_info->pan_exist, stack_info->a2dp_exist);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_disp_dbg_msg(btcoexist,
+ BTC_DBG_DISP_BT_LINK_INFO);
+ }
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
+ CL_PRINTF(cli_buf);
+
+ for (i = 0; i < BT_INFO_SRC_8821A_2ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+ glbt_info_src_8821a_2ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3],
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ CL_PRINTF(cli_buf);
+ }
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s",
+ "PS state, IPS/LPS",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ /* Sw mechanism*/
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Sw mechanism]============");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d/ %d/ %d ",
+ "SM1[ShRf/ LpRA/ LimDig/ btLna]",
+ coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra,
+ coex_dm->limited_dig, coex_dm->cur_bt_lna_constrain);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+ "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
+ coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
+ coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
+ CL_PRINTF(cli_buf);
+
+ /* Fw mechanism*/
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Fw mechanism]============");
+ CL_PRINTF(cli_buf);
+
+ if (!btcoexist->manual_control) {
+ ps_tdma_case = coex_dm->cur_ps_tdma;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d",
+ "PS TDMA",
+ coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1],
+ coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3],
+ coex_dm->ps_tdma_para[4], ps_tdma_case);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct",
+ coex_dm->cur_dec_bt_pwr,
+ coex_dm->cur_ignore_wlan_act);
+ CL_PRINTF(cli_buf);
+ }
+
+ /* Hw setting*/
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s", "============[Hw setting]============");
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal",
+ coex_dm->bt_rf0x1e_backup);
+ CL_PRINTF(cli_buf);
+
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x ",
+ "0x778 (W_Act)/ 0x6cc (CoTab Sel)",
+ u1tmp[0], u1tmp[1]);
+ CL_PRINTF(cli_buf);
+
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db);
+ u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x8db(ADC)/0xc5b[29:25](DAC)",
+ ((u1tmp[0]&0x60)>>5), ((u1tmp[1]&0x3e)>>1));
+ CL_PRINTF(cli_buf);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)",
+ u4tmp[0]&0xff, ((u4tmp[0]&0x30000000)>>28));
+ CL_PRINTF(cli_buf);
+
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x40/ 0x4c[24:23]/ 0x974",
+ u1tmp[0], ((u4tmp[0]&0x01800000)>>23), u4tmp[1]);
+ CL_PRINTF(cli_buf);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x550(bcn ctrl)/0x522",
+ u4tmp[0], u1tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa0a);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0xc50(DIG)/0xa0a(CCK-TH)",
+ u4tmp[0], u1tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48);
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b);
+ u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "OFDM-FA/ CCK-FA",
+ u4tmp[0], (u1tmp[0]<<8) + u1tmp[1]);
+ CL_PRINTF(cli_buf);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u4tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8",
+ u4tmp[0], u4tmp[1], u4tmp[2]);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "0x770 (hi-pri Rx/Tx)",
+ coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "0x774(low-pri Rx/Tx)",
+ coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+ CL_PRINTF(cli_buf);
+
+ /* Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang*/
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x41b);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x",
+ "0x41b (mgntQ hang chk == 0xf)",
+ u1tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8821a2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+ halbtc8821a2ant_coex_all_off(btcoexist);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+ /*halbtc8821a2ant_init_coex_dm(btcoexist);*/
+ }
+}
+
+void ex_halbtc8821a2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_lps = false;
+ }
+}
+
+void ex_halbtc8821a2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_SCAN_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ } else if (BTC_SCAN_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+ }
+}
+
+void ex_halbtc8821a2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_ASSOCIATE_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ } else if (BTC_ASSOCIATE_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+ }
+}
+
+void ex_halbtc8821a2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifi_central_chnl;
+
+ if (BTC_MEDIA_CONNECT == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+ }
+
+ /* only 2.4G we need to inform bt the chnl mask*/
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ &wifi_central_chnl);
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifi_central_chnl <= 14)) {
+ h2c_parameter[0] = 0x1;
+ h2c_parameter[1] = wifi_central_chnl;
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66 = 0x%x\n",
+ h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8821a2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type) {
+ if (type == BTC_PACKET_DHCP) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], DHCP Packet notify\n");
+ }
+}
+
+void ex_halbtc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ static u32 set_bt_lna_cnt, set_bt_psd_mode;
+ bool bt_busy = false, limited_dig = false;
+ bool wifi_connected = false, bt_hs_on = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ rsp_source = tmp_buf[0]&0xf;
+ if (rsp_source >= BT_INFO_SRC_8821A_2ANT_MAX)
+ rsp_source = BT_INFO_SRC_8821A_2ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length = %d, hex data = [",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+ if (i == 1)
+ bt_info = tmp_buf[i];
+ if (i == length-1) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmp_buf[i]);
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmp_buf[i]);
+ }
+ }
+
+ if (BT_INFO_SRC_8821A_2ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0]*/
+ coex_sta->bt_info_c2h[rsp_source][2]&0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3]*2+10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT*/
+ /* because bt is reset and loss of the info.*/
+ if ((coex_sta->bt_info_ext & BIT1)) {
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+ if (wifi_connected) {
+ ex_halbtc8821a2ant_media_status_notify(btcoexist,
+ BTC_MEDIA_CONNECT);
+ } else {
+ ex_halbtc8821a2ant_media_status_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+
+ set_bt_psd_mode = 0;
+ }
+ if (set_bt_psd_mode <= 3) {
+ halbtc8821a2ant_set_bt_psd_mode(btcoexist, FORCE_EXEC,
+ 0x0); /*fix CH-BW mode*/
+ set_bt_psd_mode++;
+ }
+
+ if (coex_dm->cur_bt_lna_constrain) {
+ if (!(coex_sta->bt_info_ext & BIT2)) {
+ if (set_bt_lna_cnt <= 3) {
+ btc8821a2_set_bt_lna_const(btcoexist,
+ FORCE_EXEC,
+ true);
+ set_bt_lna_cnt++;
+ }
+ }
+ } else {
+ set_bt_lna_cnt = 0;
+ }
+
+ if ((coex_sta->bt_info_ext & BIT3)) {
+ halbtc8821a2ant_ignore_wlan_act(btcoexist,
+ FORCE_EXEC, false);
+ } else {
+ /* BT already NOT ignore Wlan active, do nothing here.*/
+ }
+
+ if ((coex_sta->bt_info_ext & BIT4)) {
+ /* BT auto report already enabled, do nothing*/
+ } else {
+ halbtc8821a2ant_bt_auto_report(btcoexist,
+ FORCE_EXEC, true);
+ }
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ /* check BIT2 first ==> check if bt is under inquiry or page scan*/
+ if (bt_info & BT_INFO_8821A_2ANT_B_INQ_PAGE) {
+ coex_sta->c2h_bt_inquiry_page = true;
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+ } else {
+ coex_sta->c2h_bt_inquiry_page = false;
+ if (bt_info == 0x1) {
+ /* connection exists but not busy*/
+ coex_sta->bt_link_exist = true;
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CON_IDLE;
+ } else if (bt_info & BT_INFO_8821A_2ANT_B_CONNECTION) {
+ /* connection exists and some link is busy*/
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8821A_2ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8821A_2ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8821A_2ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+ } else {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE;
+ }
+
+ if (bt_hs_on)
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+ }
+
+ if (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status)
+ bt_busy = true;
+ else
+ bt_busy = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ if (BT_8821A_2ANT_BT_STATUS_IDLE != coex_dm->bt_status)
+ limited_dig = true;
+ else
+ limited_dig = false;
+ coex_dm->limited_dig = limited_dig;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_BL_BT_LIMITED_DIG, &limited_dig);
+
+ halbtc8821a2ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8821a2ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Halt notify\n");
+
+ halbtc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+ ex_halbtc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8821a2ant_periodical(struct btc_coexist *btcoexist)
+{
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], ==========================Periodical===========================\n");
+
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+ board_info->pg_ant_num,
+ board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ }
+
+ halbtc8821a2ant_query_bt_info(btcoexist);
+ halbtc8821a2ant_monitor_bt_ctr(btcoexist);
+ btc8821a2ant_mon_bt_en_dis(btcoexist);
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h
new file mode 100644
index 0000000..b4cf1f5
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h
@@ -0,0 +1,205 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*===========================================
+ * The following is for 8821A 2Ant BT Co-exist definition
+ *===========================================
+*/
+#define BT_INFO_8821A_2ANT_B_FTP BIT7
+#define BT_INFO_8821A_2ANT_B_A2DP BIT6
+#define BT_INFO_8821A_2ANT_B_HID BIT5
+#define BT_INFO_8821A_2ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8821A_2ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8821A_2ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8821A_2ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8821A_2ANT_B_CONNECTION BIT0
+
+#define BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT 2
+
+enum _BT_INFO_SRC_8821A_2ANT {
+ BT_INFO_SRC_8821A_2ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8821A_2ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8821A_2ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8821A_2ANT_MAX
+};
+
+enum _BT_8821A_2ANT_BT_STATUS {
+ BT_8821A_2ANT_BT_STATUS_IDLE = 0x0,
+ BT_8821A_2ANT_BT_STATUS_CON_IDLE = 0x1,
+ BT_8821A_2ANT_BT_STATUS_NON_IDLE = 0x2,
+ BT_8821A_2ANT_BT_STATUS_MAX
+};
+
+enum _BT_8821A_2ANT_COEX_ALGO {
+ BT_8821A_2ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8821A_2ANT_COEX_ALGO_SCO = 0x1,
+ BT_8821A_2ANT_COEX_ALGO_HID = 0x2,
+ BT_8821A_2ANT_COEX_ALGO_A2DP = 0x3,
+ BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS = 0x4,
+ BT_8821A_2ANT_COEX_ALGO_PANEDR = 0x5,
+ BT_8821A_2ANT_COEX_ALGO_PANHS = 0x6,
+ BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7,
+ BT_8821A_2ANT_COEX_ALGO_PANEDR_HID = 0x8,
+ BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9,
+ BT_8821A_2ANT_COEX_ALGO_HID_A2DP = 0xa,
+ BT_8821A_2ANT_COEX_ALGO_MAX = 0xb,
+};
+
+struct coex_dm_8821a_2ant {
+ /* fw mechanism */
+ bool pre_dec_bt_pwr;
+ bool cur_dec_bt_pwr;
+ bool pre_bt_lna_constrain;
+ bool cur_bt_lna_constrain;
+ u8 pre_bt_psd_mode;
+ u8 cur_bt_psd_mode;
+ u8 pre_fw_dac_swing_lvl;
+ u8 cur_fw_dac_swing_lvl;
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool reset_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+
+ /* sw mechanism */
+ bool pre_rf_rx_lpf_shrink;
+ bool cur_rf_rx_lpf_shrink;
+ u32 bt_rf0x1e_backup;
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ bool pre_dac_swing_on;
+ u32 pre_dac_swing_lvl;
+ bool cur_dac_swing_on;
+ u32 cur_dac_swing_lvl;
+ bool pre_adc_back_off;
+ bool cur_adc_back_off;
+ bool pre_agc_table_en;
+ bool cur_agc_table_en;
+ u32 pre_val0x6c0;
+ u32 cur_val0x6c0;
+ u32 pre_val0x6c4;
+ u32 cur_val0x6c4;
+ u32 pre_val0x6c8;
+ u32 cur_val0x6c8;
+ u8 pre_val0x6cc;
+ u8 cur_val0x6cc;
+ bool limited_dig;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+};
+
+struct coex_sta_8821a_2ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+ bool under_lps;
+ bool under_ips;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8821A_2ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8821A_2ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/*===========================================
+ * The following is interface which will notify coex module.
+ *===========================================
+ */
+void
+ex_halbtc8821a2ant_init_hwconfig(
+ struct btc_coexist *btcoexist
+ );
+void
+ex_halbtc8821a2ant_init_coex_dm(
+ struct btc_coexist *btcoexist
+ );
+void
+ex_halbtc8821a2ant_ips_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_lps_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_scan_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_connect_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_media_status_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_special_packet_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_bt_info_notify(
+ struct btc_coexist *btcoexist,
+ u8 *tmp_buf,
+ u8 length
+ );
+void
+ex_halbtc8821a2ant_halt_notify(
+ struct btc_coexist *btcoexist
+ );
+void
+ex_halbtc8821a2ant_periodical(
+ struct btc_coexist *btcoexist
+ );
+void
+ex_halbtc8821a2ant_display_coex_info(
+ struct btc_coexist *btcoexist
+ );
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
index 33da3df..0620b22 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -101,7 +101,7 @@ static bool halbtc_legacy(struct rtl_priv *adapter)
bool is_legacy = false;
- if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_B))
+ if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_G))
is_legacy = true;
return is_legacy;
@@ -389,7 +389,7 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf)
btcoexist->bt_info.reject_agg_pkt = *bool_tmp;
break;
case BTC_SET_BL_BT_CTRL_AGG_SIZE:
- btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp;
+ btcoexist->bt_info.bt_ctrl_buf_size = *bool_tmp;
break;
case BTC_SET_BL_INC_SCAN_DEV_NUM:
btcoexist->bt_info.increase_scan_dev_num = *bool_tmp;
@@ -417,10 +417,10 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf)
/* rtlpriv->mlmepriv.scan_compensation = *u8_tmp; */
break;
case BTC_SET_U1_1ANT_LPS:
- btcoexist->bt_info.lps_1ant = *u8_tmp;
+ btcoexist->bt_info.lps_val = *u8_tmp;
break;
case BTC_SET_U1_1ANT_RPWM:
- btcoexist->bt_info.rpwm_1ant = *u8_tmp;
+ btcoexist->bt_info.rpwm_val = *u8_tmp;
break;
/* the following are some action which will be triggered */
case BTC_SET_ACT_LEAVE_LPS:
@@ -497,7 +497,7 @@ static u32 halbtc_read_4byte(void *bt_context, u32 reg_addr)
return rtl_read_dword(rtlpriv, reg_addr);
}
-static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data)
+static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u32 data)
{
struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
struct rtl_priv *rtlpriv = btcoexist->adapter;
@@ -506,7 +506,7 @@ static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data)
}
static void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr,
- u32 bit_mask, u8 data)
+ u8 bit_mask, u8 data)
{
struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
struct rtl_priv *rtlpriv = btcoexist->adapter;
@@ -654,7 +654,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter)
btcoexist->cli_buf = &btc_dbg_buf[0];
- btcoexist->bt_info.b_bt_ctrl_buf_size = false;
+ btcoexist->bt_info.bt_ctrl_buf_size = false;
btcoexist->bt_info.agg_buf_size = 5;
btcoexist->bt_info.increase_scan_dev_num = false;
@@ -672,7 +672,7 @@ void exhalbtc_init_hw_config(struct btc_coexist *btcoexist)
btcoexist->statistics.cnt_init_hw_config++;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_init_hwconfig(btcoexist);
+ ex_btc8723b2ant_init_hwconfig(btcoexist);
}
void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
@@ -686,7 +686,7 @@ void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
btcoexist->statistics.cnt_init_coex_dm++;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_init_coex_dm(btcoexist);
+ ex_btc8723b2ant_init_coex_dm(btcoexist);
btcoexist->initilized = true;
}
@@ -711,7 +711,7 @@ void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_ips_notify(btcoexist, ips_type);
+ ex_btc8723b2ant_ips_notify(btcoexist, ips_type);
halbtc_nomal_low_power();
}
@@ -734,7 +734,7 @@ void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type)
lps_type = BTC_LPS_ENABLE;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_lps_notify(btcoexist, lps_type);
+ ex_btc8723b2ant_lps_notify(btcoexist, lps_type);
}
void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
@@ -757,7 +757,7 @@ void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_scan_notify(btcoexist, scan_type);
+ ex_btc8723b2ant_scan_notify(btcoexist, scan_type);
halbtc_nomal_low_power();
}
@@ -782,14 +782,12 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_connect_notify(btcoexist, asso_type);
+ ex_btc8723b2ant_connect_notify(btcoexist, asso_type);
}
void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
- enum _RT_MEDIA_STATUS media_status)
+ enum rt_media_status media_status)
{
- struct rtl_priv *rtlpriv = btcoexist->adapter;
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
u8 status;
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -805,9 +803,6 @@ void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
halbtc_leave_low_power();
- if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- btc8723b_med_stat_notify(btcoexist, status);
-
halbtc_nomal_low_power();
}
@@ -828,8 +823,8 @@ void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_special_packet_notify(btcoexist,
- packet_type);
+ ex_btc8723b2ant_special_packet_notify(btcoexist,
+ packet_type);
halbtc_nomal_low_power();
}
@@ -844,13 +839,11 @@ void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist,
btcoexist->statistics.cnt_bt_info_notify++;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length);
+ ex_btc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length);
}
void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
{
- struct rtl_priv *rtlpriv = btcoexist->adapter;
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
u8 stack_op_type;
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -863,10 +856,6 @@ void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
halbtc_leave_low_power();
- if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_stack_operation_notify(btcoexist,
- stack_op_type);
-
halbtc_nomal_low_power();
}
@@ -878,7 +867,7 @@ void exhalbtc_halt_notify(struct btc_coexist *btcoexist)
return;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_halt_notify(btcoexist);
+ ex_btc8723b2ant_halt_notify(btcoexist);
}
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
@@ -898,7 +887,7 @@ void exhalbtc_periodical(struct btc_coexist *btcoexist)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_periodical(btcoexist);
+ ex_btc8723b2ant_periodical(btcoexist);
halbtc_nomal_low_power();
}
@@ -997,5 +986,5 @@ void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist)
return;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_display_coex_info(btcoexist);
+ ex_btc8723b2ant_display_coex_info(btcoexist);
}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
index 049f4c8..0d185e6 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -55,9 +55,16 @@
#define BTC_RATE_DISABLE 0
#define BTC_RATE_ENABLE 1
+/* single Antenna definition */
#define BTC_ANT_PATH_WIFI 0
#define BTC_ANT_PATH_BT 1
#define BTC_ANT_PATH_PTA 2
+/* dual Antenna definition */
+#define BTC_ANT_WIFI_AT_MAIN 0
+#define BTC_ANT_WIFI_AT_AUX 1
+/* coupler Antenna definition */
+#define BTC_ANT_WIFI_AT_CPL_MAIN 0
+#define BTC_ANT_WIFI_AT_CPL_AUX 1
enum btc_chip_interface {
BTC_INTF_UNKNOWN = 0,
@@ -68,7 +75,7 @@ enum btc_chip_interface {
BTC_INTF_MAX
};
-enum BTC_CHIP_TYPE {
+enum btc_chip_type {
BTC_CHIP_UNDEF = 0,
BTC_CHIP_CSR_BC4 = 1,
BTC_CHIP_CSR_BC8 = 2,
@@ -78,11 +85,12 @@ enum BTC_CHIP_TYPE {
BTC_CHIP_MAX
};
-enum BTC_MSG_TYPE {
+enum btc_msg_type {
BTC_MSG_INTERFACE = 0x0,
BTC_MSG_ALGORITHM = 0x1,
BTC_MSG_MAX
};
+
extern u32 btc_dbg_type[];
/* following is for BTC_MSG_INTERFACE */
@@ -101,20 +109,15 @@ extern u32 btc_dbg_type[];
#define ALGO_TRACE_SW_DETAIL BIT8
#define ALGO_TRACE_SW_EXEC BIT9
-#define BT_COEX_ANT_TYPE_PG 0
-#define BT_COEX_ANT_TYPE_ANTDIV 1
-#define BT_COEX_ANT_TYPE_DETECTED 2
-#define BTC_MIMO_PS_STATIC 0
-#define BTC_MIMO_PS_DYNAMIC 1
-#define BTC_RATE_DISABLE 0
-#define BTC_RATE_ENABLE 1
-#define BTC_ANT_PATH_WIFI 0
-#define BTC_ANT_PATH_BT 1
-#define BTC_ANT_PATH_PTA 2
-
+/* following is for wifi link status */
+#define WIFI_STA_CONNECTED BIT0
+#define WIFI_AP_CONNECTED BIT1
+#define WIFI_HS_CONNECTED BIT2
+#define WIFI_P2P_GO_CONNECTED BIT3
+#define WIFI_P2P_GC_CONNECTED BIT4
#define CL_SPRINTF snprintf
-#define CL_PRINTF(buf) printk("%s", buf)
+#define CL_PRINTF printk
#define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \
do { \
@@ -123,46 +126,15 @@ extern u32 btc_dbg_type[];
} \
} while (0)
-#define BTC_PRINT_F(dbgtype, dbgflag, printstr, ...) \
- do { \
- if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\
- pr_info("%s: ", __func__); \
- printk(printstr, ##__VA_ARGS__); \
- } \
- } while (0)
-
-#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr) \
- do { \
- if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \
- int __i; \
- u8 *__ptr = (u8 *)_ptr; \
- printk printstr; \
- for (__i = 0; __i < 6; __i++) \
- printk("%02X%s", __ptr[__i], (__i == 5) ? \
- "" : "-"); \
- pr_info("\n"); \
- } \
- } while (0)
-
-#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \
- do { \
- if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \
- int __i; \
- u8 *__ptr = (u8 *)_hexdata; \
- printk(_titlestring); \
- for (__i = 0; __i < (int)_hexdatalen; __i++) { \
- printk("%02X%s", __ptr[__i], (((__i + 1) % 4) \
- == 0) ? " " : " ");\
- if (((__i + 1) % 16) == 0) \
- printk("\n"); \
- } \
- pr_debug("\n"); \
- } \
- } while (0)
-
-#define BTC_ANT_PATH_WIFI 0
-#define BTC_ANT_PATH_BT 1
-#define BTC_ANT_PATH_PTA 2
+#define BTC_RSSI_HIGH(_rssi_) \
+ ((_rssi_ == BTC_RSSI_STATE_HIGH || \
+ _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? true : false)
+#define BTC_RSSI_MEDIUM(_rssi_) \
+ ((_rssi_ == BTC_RSSI_STATE_MEDIUM || \
+ _rssi_ == BTC_RSSI_STATE_STAY_MEDIUM) ? true : false)
+#define BTC_RSSI_LOW(_rssi_) \
+ ((_rssi_ == BTC_RSSI_STATE_LOW || \
+ _rssi_ == BTC_RSSI_STATE_STAY_LOW) ? true : false)
enum btc_power_save_type {
BTC_PS_WIFI_NATIVE = 0,
@@ -224,7 +196,6 @@ enum btc_wifi_pnp {
BTC_WIFI_PNP_MAX
};
-
enum btc_get_type {
/* type bool */
BTC_GET_BL_HS_OPERATION,
@@ -253,6 +224,7 @@ enum btc_get_type {
BTC_GET_U4_WIFI_BW,
BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
BTC_GET_U4_WIFI_FW_VER,
+ BTC_GET_U4_WIFI_LINK_STATUS,
BTC_GET_U4_BT_PATCH_VER,
/* type u1Byte */
@@ -260,6 +232,7 @@ enum btc_get_type {
BTC_GET_U1_WIFI_CENTRAL_CHNL,
BTC_GET_U1_WIFI_HS_CHNL,
BTC_GET_U1_MAC_PHY_MODE,
+ BTC_GET_U1_AP_NUM,
/* for 1Ant */
BTC_GET_U1_LPS_MODE,
@@ -270,7 +243,6 @@ enum btc_get_type {
BTC_GET_MAX
};
-
enum btc_set_type {
/* type bool */
BTC_SET_BL_BT_DISABLE,
@@ -283,7 +255,6 @@ enum btc_set_type {
/* type u1Byte */
BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON,
- BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
BTC_SET_UI_SCAN_SIG_COMPENSATION,
BTC_SET_U1_AGG_BUF_SIZE,
@@ -295,6 +266,9 @@ enum btc_set_type {
/* type bool */
BTC_SET_BL_BT_SCO_BUSY,
/* type u1Byte */
+ BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
+ BTC_SET_U1_LPS_VAL,
+ BTC_SET_U1_RPWM_VAL,
BTC_SET_U1_1ANT_LPS,
BTC_SET_U1_1ANT_RPWM,
/* type trigger some action */
@@ -358,6 +332,20 @@ enum btc_notify_type_special_packet {
BTC_PACKET_MAX
};
+enum hci_ext_bt_operation {
+ HCI_BT_OP_NONE = 0x0,
+ HCI_BT_OP_INQUIRY_START = 0x1,
+ HCI_BT_OP_INQUIRY_FINISH = 0x2,
+ HCI_BT_OP_PAGING_START = 0x3,
+ HCI_BT_OP_PAGING_SUCCESS = 0x4,
+ HCI_BT_OP_PAGING_UNSUCCESS = 0x5,
+ HCI_BT_OP_PAIRING_START = 0x6,
+ HCI_BT_OP_PAIRING_FINISH = 0x7,
+ HCI_BT_OP_BT_DEV_ENABLE = 0x8,
+ HCI_BT_OP_BT_DEV_DISABLE = 0x9,
+ HCI_BT_OP_MAX
+};
+
enum btc_notify_type_stack_operation {
BTC_STACK_OP_NONE = 0x0,
BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1,
@@ -365,17 +353,16 @@ enum btc_notify_type_stack_operation {
BTC_STACK_OP_MAX
};
-
typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr);
typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr);
typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr);
-typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data);
+typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u32 data);
typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr,
- u32 bit_mask, u8 data1b);
+ u8 bit_mask, u8 data1b);
typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data);
@@ -413,20 +400,22 @@ struct btc_bt_info {
u8 agg_buf_size;
bool limited_dig;
bool reject_agg_pkt;
- bool b_bt_ctrl_buf_size;
+ bool bt_ctrl_buf_size;
bool increase_scan_dev_num;
u16 bt_hci_ver;
u16 bt_real_fw_ver;
u8 bt_fw_ver;
+ bool bt_disable_low_pwr;
+
/* the following is for 1Ant solution */
bool bt_ctrl_lps;
bool bt_pwr_save_mode;
bool bt_lps_on;
bool force_to_roam;
u8 force_exec_pwr_cmd_cnt;
- u8 lps_1ant;
- u8 rpwm_1ant;
+ u8 lps_val;
+ u8 rpwm_val;
u32 ra_mask;
};
@@ -457,6 +446,7 @@ struct btc_statistics {
u32 cnt_special_packet_notify;
u32 cnt_bt_info_notify;
u32 cnt_periodical;
+ u32 cnt_coex_dm_switch;
u32 cnt_stack_operation_notify;
u32 cnt_dbg_ctrl;
};
@@ -509,7 +499,6 @@ struct btc_coexist {
bfp_btc_set_bb_reg btc_set_bb_reg;
bfp_btc_get_bb_reg btc_get_bb_reg;
-
bfp_btc_set_rf_reg btc_set_rf_reg;
bfp_btc_get_rf_reg btc_get_rf_reg;
@@ -533,13 +522,14 @@ void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action);
void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
- enum _RT_MEDIA_STATUS media_status);
+ enum rt_media_status media_status);
void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
u8 length);
void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
+void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist);
void exhalbtc_periodical(struct btc_coexist *btcoexist);
void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
u8 *data);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
index 0ab94fe..b9b0cb7 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
@@ -22,19 +22,19 @@
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
-
#include "../wifi.h"
-#include "rtl_btc.h"
-#include "halbt_precomp.h"
-
#include <linux/vmalloc.h>
#include <linux/module.h>
+#include "rtl_btc.h"
+#include "halbt_precomp.h"
+
static struct rtl_btc_ops rtl_btc_operation = {
.btc_init_variables = rtl_btc_init_variables,
.btc_init_hal_vars = rtl_btc_init_hal_vars,
.btc_init_hw_config = rtl_btc_init_hw_config,
.btc_ips_notify = rtl_btc_ips_notify,
+ .btc_lps_notify = rtl_btc_lps_notify,
.btc_scan_notify = rtl_btc_scan_notify,
.btc_connect_notify = rtl_btc_connect_notify,
.btc_mediastatus_notify = rtl_btc_mediastatus_notify,
@@ -44,6 +44,7 @@ static struct rtl_btc_ops rtl_btc_operation = {
.btc_is_limited_dig = rtl_btc_is_limited_dig,
.btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
.btc_is_bt_disabled = rtl_btc_is_bt_disabled,
+ .btc_special_packet_notify = rtl_btc_special_packet_notify,
};
void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
@@ -85,6 +86,11 @@ void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
exhalbtc_ips_notify(&gl_bt_coexist, type);
}
+void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type)
+{
+ exhalbtc_lps_notify(&gl_bt_coexist, type);
+}
+
void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
{
exhalbtc_scan_notify(&gl_bt_coexist, scantype);
@@ -96,13 +102,14 @@ void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
}
void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
- enum _RT_MEDIA_STATUS mstatus)
+ enum rt_media_status mstatus)
{
exhalbtc_mediastatus_notify(&gl_bt_coexist, mstatus);
}
void rtl_btc_periodical(struct rtl_priv *rtlpriv)
{
+ /*rtl_bt_dm_monitor();*/
exhalbtc_periodical(&gl_bt_coexist);
}
@@ -150,12 +157,18 @@ bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv)
bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
{
+ /* It seems 'bt_disabled' is never be initialized or set. */
if (gl_bt_coexist.bt_info.bt_disabled)
return true;
else
return false;
}
+void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type)
+{
+ return exhalbtc_special_packet_notify(&gl_bt_coexist, pkt_type);
+}
+
struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
{
return &rtl_btc_operation;
@@ -174,11 +187,11 @@ u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
return num;
}
-enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT;
+ enum rt_media_status m_status = RT_MEDIA_DISCONNECT;
u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
index 805b22c..ccd5a0f 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
@@ -31,22 +31,24 @@ void rtl_btc_init_variables(struct rtl_priv *rtlpriv);
void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv);
void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv);
void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type);
+void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type);
void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype);
void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action);
void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
- enum _RT_MEDIA_STATUS mstatus);
+ enum rt_media_status mstatus);
void rtl_btc_periodical(struct rtl_priv *rtlpriv);
void rtl_btc_halt_notify(void);
void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length);
bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv);
bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv);
bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv);
+void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type);
struct rtl_btc_ops *rtl_btc_get_ops_pointer(void);
u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv);
u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv);
u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv);
-enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw);
+enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw);
#endif
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 67d1ee6..74a8ba4 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -646,7 +646,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
== 2) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
- "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%d\n",
+ "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n",
prio, ring->idx,
skb_queue_len(&ring->queue));
@@ -1469,7 +1469,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+ "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n",
hw_queue, ring->idx, idx,
skb_queue_len(&ring->queue));
@@ -1511,7 +1511,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
hw_queue != BEACON_QUEUE) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
- "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+ "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n",
hw_queue, ring->idx, idx,
skb_queue_len(&ring->queue));
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 361435f..1ac6383 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -317,6 +317,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
{RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/
{RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
{RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+ {RTL_USB_DEVICE(0x0df6, 0x0070, rtl92cu_hal_cfg)}, /*Sitecom - 150N */
{RTL_USB_DEVICE(0x0df6, 0x0077, rtl92cu_hal_cfg)}, /*Sitecom-WLA2100V2*/
{RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
{RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
index 592125a..1961b8e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
@@ -677,7 +677,7 @@ static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n",
+ "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",
rtlphy->pwrgroup_cnt, index,
rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]);
if (index == 13)
@@ -2531,7 +2531,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw,
if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) {/* Path-A for 5G */
u4tmp = curveindex_5g[channel-1];
RTPRINT(rtlpriv, FINIT, INIT_IQK,
- "ver 1 set RF-A, 5G, 0x28 = 0x%ulx !!\n", u4tmp);
+ "ver 1 set RF-A, 5G, 0x28 = 0x%x !!\n", u4tmp);
if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY &&
rtlpriv->rtlhal.interfaceindex == 1) {
bneed_powerdown_radio =
@@ -2550,7 +2550,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw,
} else if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) {
u4tmp = curveindex_2g[channel-1];
RTPRINT(rtlpriv, FINIT, INIT_IQK,
- "ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", u4tmp);
+ "ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", u4tmp);
if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY &&
rtlpriv->rtlhal.interfaceindex == 0) {
bneed_powerdown_radio =
@@ -2562,7 +2562,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw,
}
rtl_set_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800, u4tmp);
RTPRINT(rtlpriv, FINIT, INIT_IQK,
- "ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n",
+ "ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n",
rtl_get_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800));
if (bneed_powerdown_radio)
_rtl92d_phy_restore_rf_env(hw, erfpath, &u4regvalue);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
index 5d534df..f76c50f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
@@ -56,11 +56,11 @@ void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw)
}
}
-static enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+static enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT;
+ enum rt_media_status m_status = RT_MEDIA_DISCONNECT;
u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 407a793..541b077 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -170,6 +170,11 @@ enum rf_tx_num {
RF_TX_NUM_NONIMPLEMENT,
};
+#define PACKET_NORMAL 0
+#define PACKET_DHCP 1
+#define PACKET_ARP 2
+#define PACKET_EAPOL 3
+
struct txpower_info_2g {
u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
@@ -234,8 +239,9 @@ enum hardware_type {
HARDWARE_TYPE_RTL8192DU,
HARDWARE_TYPE_RTL8723AE,
HARDWARE_TYPE_RTL8723U,
- HARDWARE_TYPE_RTL8723BE,
HARDWARE_TYPE_RTL8188EE,
+ HARDWARE_TYPE_RTL8723BE,
+ HARDWARE_TYPE_RTL8192EE,
HARDWARE_TYPE_RTL8821AE,
HARDWARE_TYPE_RTL8812AE,
@@ -428,7 +434,7 @@ enum hw_variables {
HW_VAR_DATA_FILTER,
};
-enum _RT_MEDIA_STATUS {
+enum rt_media_status {
RT_MEDIA_DISCONNECT = 0,
RT_MEDIA_CONNECT = 1
};
@@ -2312,10 +2318,11 @@ struct rtl_btc_ops {
void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
void (*btc_init_hw_config) (struct rtl_priv *rtlpriv);
void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
+ void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type);
void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype);
void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action);
void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv,
- enum _RT_MEDIA_STATUS mstatus);
+ enum rt_media_status mstatus);
void (*btc_periodical) (struct rtl_priv *rtlpriv);
void (*btc_halt_notify) (void);
void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv,
@@ -2323,6 +2330,8 @@ struct rtl_btc_ops {
bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv);
bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv);
bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv);
+ void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv,
+ u8 pkt_type);
};
struct proxim {
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index a0aa8fa..735be53 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -345,7 +345,6 @@ static int wl1251_spi_remove(struct spi_device *spi)
{
struct wl1251 *wl = spi_get_drvdata(spi);
- free_irq(wl->irq, wl);
wl1251_free_hw(wl);
regulator_disable(wl->vio);
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index 392c882..69601f6 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -327,23 +327,22 @@ static int wl1271_probe(struct spi_device *spi)
struct wl12xx_spi_glue *glue;
struct wlcore_platdev_data pdev_data;
struct resource res[1];
- int ret = -ENOMEM;
+ int ret;
memset(&pdev_data, 0x00, sizeof(pdev_data));
pdev_data.pdata = dev_get_platdata(&spi->dev);
if (!pdev_data.pdata) {
dev_err(&spi->dev, "no platform data\n");
- ret = -ENODEV;
- goto out;
+ return -ENODEV;
}
pdev_data.if_ops = &spi_ops;
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&spi->dev, "can't allocate glue\n");
- goto out;
+ return -ENOMEM;
}
glue->dev = &spi->dev;
@@ -357,14 +356,13 @@ static int wl1271_probe(struct spi_device *spi)
ret = spi_setup(spi);
if (ret < 0) {
dev_err(glue->dev, "spi_setup failed\n");
- goto out_free_glue;
+ return ret;
}
glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO);
if (!glue->core) {
dev_err(glue->dev, "can't allocate platform_device\n");
- ret = -ENOMEM;
- goto out_free_glue;
+ return -ENOMEM;
}
glue->core->dev.parent = &spi->dev;
@@ -398,11 +396,6 @@ static int wl1271_probe(struct spi_device *spi)
out_dev_put:
platform_device_put(glue->core);
-
-out_free_glue:
- kfree(glue);
-
-out:
return ret;
}
@@ -411,7 +404,6 @@ static int wl1271_remove(struct spi_device *spi)
struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
platform_device_unregister(glue->core);
- kfree(glue);
return 0;
}
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
index 19396dc..bed2fede 100644
--- a/drivers/ssb/b43_pci_bridge.c
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -38,6 +38,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4350) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4351) },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
diff --git a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c
index c5fdcb8..2a1502f 100644
--- a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c
@@ -2128,7 +2128,7 @@ static int on_action_public23a(struct rtw_adapter *padapter,
IEEE80211_BAND_5GHZ);
if (cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, pframe,
- skb->len, 0, GFP_ATOMIC))
+ skb->len, 0))
return _SUCCESS;
return _FAIL;
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
index 93dc844..8b0ccb5 100644
--- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
@@ -279,6 +279,7 @@ static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter,
}
bss = cfg80211_inform_bss(wiphy, notify_channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
pnetwork->network.MacAddress,
pnetwork->network.tsf,
pnetwork->network.capability,
@@ -2379,7 +2380,7 @@ void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter,
IEEE80211_BAND_5GHZ);
cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, pmgmt_frame, frame_len,
- 0, GFP_ATOMIC);
+ 0);
#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
}
@@ -2425,7 +2426,7 @@ void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter,
frame_len = sizeof(struct ieee80211_hdr_3addr) + 2;
cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, (u8 *)&mgmt, frame_len,
- 0, GFP_ATOMIC);
+ 0);
#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
}
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 3727f6d..8942dcb 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -422,6 +422,7 @@ static int prism2_scan(struct wiphy *wiphy,
IEEE80211_BAND_2GHZ);
bss = cfg80211_inform_bss(wiphy,
ieee80211_get_channel(wiphy, freq),
+ CFG80211_BSS_FTYPE_UNKNOWN,
(const u8 *) &(msg2.bssid.data.data),
msg2.timestamp.data, msg2.capinfo.data,
msg2.beaconperiod.data,
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index 205f4a3..cd6d0af 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -237,7 +237,7 @@ static int bcma_hcd_probe(struct bcma_device *dev)
bcma_hcd_init_chip(dev);
/* In AI chips EHCI is addrspace 0, OHCI is 1 */
- ohci_addr = dev->addr1;
+ ohci_addr = dev->addr_s[0];
if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
&& chipinfo->rev == 0)
ohci_addr = 0x18009000;
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 0272e49..6345979 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -267,7 +267,7 @@ struct bcma_device {
u8 core_unit;
u32 addr;
- u32 addr1;
+ u32 addr_s[8];
u32 wrap;
void __iomem *io_addr;
@@ -332,10 +332,10 @@ struct bcma_bus {
struct bcma_device *mapped_core;
struct list_head cores;
u8 nr_cores;
- u8 init_done:1;
u8 num;
struct bcma_drv_cc drv_cc;
+ struct bcma_drv_cc_b drv_cc_b;
struct bcma_drv_pci drv_pci[2];
struct bcma_drv_pcie2 drv_pcie2;
struct bcma_drv_mips drv_mips;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 63d105c..db6fa21 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -644,6 +644,12 @@ struct bcma_drv_cc {
#endif
};
+struct bcma_drv_cc_b {
+ struct bcma_device *core;
+ u8 setup_done:1;
+ void __iomem *mii;
+};
+
/* Register access */
#define bcma_cc_read32(cc, offset) \
bcma_read32((cc)->core, offset)
@@ -699,4 +705,6 @@ extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
+void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value);
+
#endif /* LINUX_BCMA_DRIVER_CC_H_ */
diff --git a/include/linux/bcma/bcma_regs.h b/include/linux/bcma/bcma_regs.h
index 917dcd7..e64ae7b 100644
--- a/include/linux/bcma/bcma_regs.h
+++ b/include/linux/bcma/bcma_regs.h
@@ -39,6 +39,11 @@
#define BCMA_RESET_CTL_RESET 0x0001
#define BCMA_RESET_ST 0x0804
+#define BCMA_NS_ROM_IOST_BOOT_DEV_MASK 0x0003
+#define BCMA_NS_ROM_IOST_BOOT_DEV_NOR 0x0000
+#define BCMA_NS_ROM_IOST_BOOT_DEV_NAND 0x0001
+#define BCMA_NS_ROM_IOST_BOOT_DEV_ROM 0x0002
+
/* BCMA PCI config space registers. */
#define BCMA_PCI_PMCSR 0x44
#define BCMA_PCI_PE 0x100
diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
index 4203c55..f24d245 100644
--- a/include/linux/bcma/bcma_soc.h
+++ b/include/linux/bcma/bcma_soc.h
@@ -10,6 +10,7 @@ struct bcma_soc {
};
int __init bcma_host_soc_register(struct bcma_soc *soc);
+int __init bcma_host_soc_init(struct bcma_soc *soc);
int bcma_bus_register(struct bcma_bus *bus);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 63ab3873..8018c91 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -838,6 +838,16 @@ enum ieee80211_vht_opmode_bits {
#define WLAN_SA_QUERY_TR_ID_LEN 2
+/**
+ * struct ieee80211_tpc_report_ie
+ *
+ * This structure refers to "TPC Report element"
+ */
+struct ieee80211_tpc_report_ie {
+ u8 tx_power;
+ u8 link_margin;
+} __packed;
+
struct ieee80211_mgmt {
__le16 frame_control;
__le16 duration;
@@ -973,6 +983,13 @@ struct ieee80211_mgmt {
u8 action_code;
u8 operating_mode;
} __packed vht_opmode_notif;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u8 tpc_elem_id;
+ u8 tpc_elem_length;
+ struct ieee80211_tpc_report_ie tpc;
+ } __packed tpc_report;
} u;
} __packed action;
} u;
@@ -1865,6 +1882,7 @@ enum ieee80211_category {
WLAN_CATEGORY_DLS = 2,
WLAN_CATEGORY_BACK = 3,
WLAN_CATEGORY_PUBLIC = 4,
+ WLAN_CATEGORY_RADIO_MEASUREMENT = 5,
WLAN_CATEGORY_HT = 7,
WLAN_CATEGORY_SA_QUERY = 8,
WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
@@ -2378,4 +2396,51 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024))
#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x))
+/**
+ * ieee80211_action_contains_tpc - checks if the frame contains TPC element
+ * @skb: the skb containing the frame, length will be checked
+ *
+ * This function checks if it's either TPC report action frame or Link
+ * Measurement report action frame as defined in IEEE Std. 802.11-2012 8.5.2.5
+ * and 8.5.7.5 accordingly.
+ */
+static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
+{
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+
+ if (!ieee80211_is_action(mgmt->frame_control))
+ return false;
+
+ if (skb->len < IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.tpc_report))
+ return false;
+
+ /*
+ * TPC report - check that:
+ * category = 0 (Spectrum Management) or 5 (Radio Measurement)
+ * spectrum management action = 3 (TPC/Link Measurement report)
+ * TPC report EID = 35
+ * TPC report element length = 2
+ *
+ * The spectrum management's tpc_report struct is used here both for
+ * parsing tpc_report and radio measurement's link measurement report
+ * frame, since the relevant part is identical in both frames.
+ */
+ if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT &&
+ mgmt->u.action.category != WLAN_CATEGORY_RADIO_MEASUREMENT)
+ return false;
+
+ /* both spectrum mgmt and link measurement have same action code */
+ if (mgmt->u.action.u.tpc_report.action_code !=
+ WLAN_ACTION_SPCT_TPC_RPRT)
+ return false;
+
+ if (mgmt->u.action.u.tpc_report.tpc_elem_id != WLAN_EID_TPC_REPORT ||
+ mgmt->u.action.u.tpc_report.tpc_elem_length !=
+ sizeof(struct ieee80211_tpc_report_ie))
+ return false;
+
+ return true;
+}
+
#endif /* LINUX_IEEE80211_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b5d5af3..206b92b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -302,7 +302,7 @@ struct hci_dev {
__u32 req_status;
__u32 req_result;
- struct crypto_blkcipher *tfm_aes;
+ void *smp_data;
struct discovery_state discovery;
struct hci_conn_hash conn_hash;
@@ -464,6 +464,8 @@ struct hci_conn_params {
HCI_AUTO_CONN_ALWAYS,
HCI_AUTO_CONN_LINK_LOSS,
} auto_connect;
+
+ struct hci_conn *conn;
};
extern struct list_head hci_dev_list;
@@ -537,7 +539,6 @@ enum {
HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND,
HCI_CONN_SCO_SETUP_PEND,
- HCI_CONN_LE_SMP_PEND,
HCI_CONN_MGMT_CONNECTED,
HCI_CONN_SSP_ENABLED,
HCI_CONN_SC_ENABLED,
@@ -551,6 +552,7 @@ enum {
HCI_CONN_FIPS,
HCI_CONN_STK_ENCRYPT,
HCI_CONN_AUTH_INITIATOR,
+ HCI_CONN_DROP,
};
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
@@ -700,7 +702,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
return NULL;
}
-void hci_disconnect(struct hci_conn *conn, __u8 reason);
+int hci_disconnect(struct hci_conn *conn, __u8 reason);
bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
@@ -754,9 +756,10 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status);
* _get()/_drop() in it, but require the caller to have a valid ref (FIXME).
*/
-static inline void hci_conn_get(struct hci_conn *conn)
+static inline struct hci_conn *hci_conn_get(struct hci_conn *conn)
{
get_device(&conn->dev);
+ return conn;
}
static inline void hci_conn_put(struct hci_conn *conn)
@@ -788,7 +791,7 @@ static inline void hci_conn_drop(struct hci_conn *conn)
if (!conn->out)
timeo *= 2;
} else {
- timeo = msecs_to_jiffies(10);
+ timeo = 0;
}
break;
@@ -797,7 +800,7 @@ static inline void hci_conn_drop(struct hci_conn *conn)
break;
default:
- timeo = msecs_to_jiffies(10);
+ timeo = 0;
break;
}
@@ -968,6 +971,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE))
#define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
+#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
+ !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+
/* ----- HCI protocols ----- */
#define HCI_PROTO_DEFER 0x01
@@ -1256,6 +1262,8 @@ bool hci_req_pending(struct hci_dev *hdev);
void hci_req_add_le_scan_disable(struct hci_request *req);
void hci_req_add_le_passive_scan(struct hci_request *req);
+void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req);
+
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout);
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
@@ -1334,8 +1342,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u32 passkey,
u8 entered);
-void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, u8 status);
+void mgmt_auth_failed(struct hci_conn *conn, u8 status);
void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
@@ -1351,6 +1358,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, s8 rssi, u8 *name, u8 name_len);
void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+bool mgmt_powering_down(struct hci_dev *hdev);
void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent);
void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk);
void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 8df15ad..ead99f0 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -633,10 +633,11 @@ struct l2cap_conn {
struct sk_buff_head pending_rx;
struct work_struct pending_rx_work;
+ struct work_struct id_addr_update_work;
+
__u8 disc_reason;
- struct delayed_work security_timer;
- struct smp_chan *smp_chan;
+ struct l2cap_chan *smp;
struct list_head chan_l;
struct mutex chan_lock;
@@ -708,6 +709,8 @@ enum {
FLAG_EFS_ENABLE,
FLAG_DEFER_SETUP,
FLAG_LE_CONN_REQ_SENT,
+ FLAG_PENDING_SECURITY,
+ FLAG_HOLD_HCI_CONN,
};
enum {
@@ -837,18 +840,43 @@ static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan
return NULL;
}
+static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+ return -ENOSYS;
+}
+
+static inline struct sk_buff *l2cap_chan_no_alloc_skb(struct l2cap_chan *chan,
+ unsigned long hdr_len,
+ unsigned long len, int nb)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
{
}
+static inline void l2cap_chan_no_close(struct l2cap_chan *chan)
+{
+}
+
static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
{
}
+static inline void l2cap_chan_no_state_change(struct l2cap_chan *chan,
+ int state, int err)
+{
+}
+
static inline void l2cap_chan_no_defer(struct l2cap_chan *chan)
{
}
+static inline void l2cap_chan_no_suspend(struct l2cap_chan *chan)
+{
+}
+
static inline void l2cap_chan_no_resume(struct l2cap_chan *chan)
{
}
@@ -911,14 +939,13 @@ int l2cap_ertm_init(struct l2cap_chan *chan);
void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
void l2cap_chan_del(struct l2cap_chan *chan, int err);
-void l2cap_conn_update_id_addr(struct hci_conn *hcon);
void l2cap_send_conn_req(struct l2cap_chan *chan);
void l2cap_move_start(struct l2cap_chan *chan);
void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
u8 status);
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
-void l2cap_conn_get(struct l2cap_conn *conn);
+struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn);
void l2cap_conn_put(struct l2cap_conn *conn);
int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0a080c4..ab21299 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1503,12 +1503,14 @@ enum cfg80211_signal_type {
* @tsf: TSF contained in the frame that carried these IEs
* @rcu_head: internal use, for freeing
* @len: length of the IEs
+ * @from_beacon: these IEs are known to come from a beacon
* @data: IE data
*/
struct cfg80211_bss_ies {
u64 tsf;
struct rcu_head rcu_head;
int len;
+ bool from_beacon;
u8 data[];
};
@@ -3765,11 +3767,25 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
}
/**
- * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ * enum cfg80211_bss_frame_type - frame type that the BSS data came from
+ * @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is
+ * from a beacon or probe response
+ * @CFG80211_BSS_FTYPE_BEACON: data comes from a beacon
+ * @CFG80211_BSS_FTYPE_PRESP: data comes from a probe response
+ */
+enum cfg80211_bss_frame_type {
+ CFG80211_BSS_FTYPE_UNKNOWN,
+ CFG80211_BSS_FTYPE_BEACON,
+ CFG80211_BSS_FTYPE_PRESP,
+};
+
+/**
+ * cfg80211_inform_bss_width - inform cfg80211 of a new BSS
*
* @wiphy: the wiphy reporting the BSS
* @rx_channel: The channel the frame was received on
* @scan_width: width of the control channel
+ * @ftype: frame type (if known)
* @bssid: the BSSID of the BSS
* @tsf: the TSF sent by the peer in the beacon/probe response (or 0)
* @capability: the capability field sent by the peer
@@ -3789,6 +3805,7 @@ struct cfg80211_bss * __must_check
cfg80211_inform_bss_width(struct wiphy *wiphy,
struct ieee80211_channel *rx_channel,
enum nl80211_bss_scan_width scan_width,
+ enum cfg80211_bss_frame_type ftype,
const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp);
@@ -3796,12 +3813,13 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
static inline struct cfg80211_bss * __must_check
cfg80211_inform_bss(struct wiphy *wiphy,
struct ieee80211_channel *rx_channel,
+ enum cfg80211_bss_frame_type ftype,
const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp)
{
return cfg80211_inform_bss_width(wiphy, rx_channel,
- NL80211_BSS_CHAN_WIDTH_20,
+ NL80211_BSS_CHAN_WIDTH_20, ftype,
bssid, tsf, capability,
beacon_interval, ie, ielen, signal,
gfp);
@@ -4412,7 +4430,6 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
* @buf: Management frame (header + body)
* @len: length of the frame data
* @flags: flags, as defined in enum nl80211_rxmgmt_flags
- * @gfp: context flags
*
* This function is called whenever an Action frame is received for a station
* mode interface, but is not processed in kernel.
@@ -4423,7 +4440,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
* driver is responsible for rejecting the frame.
*/
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm,
- const u8 *buf, size_t len, u32 flags, gfp_t gfp);
+ const u8 *buf, size_t len, u32 flags);
/**
* cfg80211_mgmt_tx_status - notification of TX status for management frame
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index dae2e24..c9b2bec 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1226,7 +1226,8 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
*
* @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
* driver to indicate that it requires IV generation for this
- * particular key.
+ * particular key. Setting this flag does not necessarily mean that SKBs
+ * will have sufficient tailroom for ICV or MIC.
* @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
* the driver for a TKIP key if it requires Michael MIC
* generation in software.
@@ -1238,7 +1239,9 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
* @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
* if space should be prepared for the IV, but the IV
* itself should not be generated. Do not set together with
- * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
+ * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. Setting this flag does
+ * not necessarily mean that SKBs will have sufficient tailroom for ICV or
+ * MIC.
* @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received
* management frames. The flag can help drivers that have a hardware
* crypto implementation that doesn't deal with management frames
@@ -1405,7 +1408,7 @@ struct ieee80211_sta_rates {
* @supp_rates: Bitmap of supported rates (per band)
* @ht_cap: HT capabilities of this STA; restricted to our own capabilities
* @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
- * @wme: indicates whether the STA supports WME. Only valid during AP-mode.
+ * @wme: indicates whether the STA supports QoS/WME.
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *), size is determined in hw information.
* @uapsd_queues: bitmap of queues configured for uapsd. Only valid
@@ -1606,6 +1609,9 @@ struct ieee80211_tx_control {
* is not enabled the default action is to disconnect when getting the
* CSA frame.
*
+ * @IEEE80211_HW_SUPPORTS_CLONED_SKBS: The driver will never modify the payload
+ * or tailroom of TX skbs without copying them first.
+ *
* @IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands
* in one command, mac80211 doesn't have to run separate scans per band.
*/
@@ -1639,7 +1645,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26,
IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27,
IEEE80211_HW_CHANCTX_STA_CSA = 1<<28,
- /* bit 29 unused */
+ IEEE80211_HW_SUPPORTS_CLONED_SKBS = 1<<29,
IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS = 1<<30,
};
diff --git a/include/net/netns/ieee802154_6lowpan.h b/include/net/netns/ieee802154_6lowpan.h
index e207096..8170f8d 100644
--- a/include/net/netns/ieee802154_6lowpan.h
+++ b/include/net/netns/ieee802154_6lowpan.h
@@ -16,7 +16,6 @@ struct netns_sysctl_lowpan {
struct netns_ieee802154_lowpan {
struct netns_sysctl_lowpan sysctl;
struct netns_frags frags;
- int max_dsize;
};
#endif
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index 2599924..dad7ab2 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -167,7 +167,7 @@ struct ieee80211_reg_rule {
struct ieee80211_regdomain {
struct rcu_head rcu_head;
u32 n_reg_rules;
- char alpha2[2];
+ char alpha2[3];
enum nl80211_dfs_regions dfs_region;
struct ieee80211_reg_rule reg_rules[];
};
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f1db15b..d097568 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3055,14 +3055,20 @@ enum nl80211_bss_scan_width {
* @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
* @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
* @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * (if @NL80211_BSS_PRESP_DATA is present then this is known to be
+ * from a probe response, otherwise it may be from the same beacon
+ * that the NL80211_BSS_BEACON_TSF will be from)
* @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
* @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
* @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
* raw information elements from the probe response/beacon (bin);
- * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
- * from a Probe Response frame; otherwise they are from a Beacon frame.
+ * if the %NL80211_BSS_BEACON_IES attribute is present and the data is
+ * different then the IEs here are from a Probe Response frame; otherwise
+ * they are from a Beacon frame.
* However, if the driver does not indicate the source of the IEs, these
* IEs may be from either frame subtype.
+ * If present, the @NL80211_BSS_PRESP_DATA attribute indicates that the
+ * data here is known to be from a probe response, without any heuristics.
* @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
* in mBm (100 * dBm) (s32)
* @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
@@ -3074,6 +3080,10 @@ enum nl80211_bss_scan_width {
* yet been received
* @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
* (u32, enum nl80211_bss_scan_width)
+ * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64)
+ * (not present if no beacon frame has been received yet)
+ * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
+ * @NL80211_BSS_TSF is known to be from a probe response (flag attribute)
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -3091,6 +3101,8 @@ enum nl80211_bss {
NL80211_BSS_SEEN_MS_AGO,
NL80211_BSS_BEACON_IES,
NL80211_BSS_CHAN_WIDTH,
+ NL80211_BSS_BEACON_TSF,
+ NL80211_BSS_PRESP_DATA,
/* keep last */
__NL80211_BSS_AFTER_LAST,
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 206b65c..0920cb6 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -39,6 +39,7 @@ static struct dentry *lowpan_control_debugfs;
struct skb_cb {
struct in6_addr addr;
+ struct in6_addr gw;
struct l2cap_chan *chan;
int status;
};
@@ -158,6 +159,54 @@ static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev,
return NULL;
}
+static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
+ struct in6_addr *daddr,
+ struct sk_buff *skb)
+{
+ struct lowpan_peer *peer, *tmp;
+ struct in6_addr *nexthop;
+ struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
+ int count = atomic_read(&dev->peer_count);
+
+ BT_DBG("peers %d addr %pI6c rt %p", count, daddr, rt);
+
+ /* If we have multiple 6lowpan peers, then check where we should
+ * send the packet. If only one peer exists, then we can send the
+ * packet right away.
+ */
+ if (count == 1)
+ return list_first_entry(&dev->peers, struct lowpan_peer,
+ list);
+
+ if (!rt) {
+ nexthop = &lowpan_cb(skb)->gw;
+
+ if (ipv6_addr_any(nexthop))
+ return NULL;
+ } else {
+ nexthop = rt6_nexthop(rt);
+
+ /* We need to remember the address because it is needed
+ * by bt_xmit() when sending the packet. In bt_xmit(), the
+ * destination routing info is not set.
+ */
+ memcpy(&lowpan_cb(skb)->gw, nexthop, sizeof(struct in6_addr));
+ }
+
+ BT_DBG("gw %pI6c", nexthop);
+
+ list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+ BT_DBG("dst addr %pMR dst type %d ip %pI6c",
+ &peer->chan->dst, peer->chan->dst_type,
+ &peer->peer_addr);
+
+ if (!ipv6_addr_cmp(&peer->peer_addr, nexthop))
+ return peer;
+ }
+
+ return NULL;
+}
+
static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
{
struct lowpan_dev *entry, *tmp;
@@ -415,8 +464,18 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
read_unlock_irqrestore(&devices_lock, flags);
if (!peer) {
- BT_DBG("no such peer %pMR found", &addr);
- return -ENOENT;
+ /* The packet might be sent to 6lowpan interface
+ * because of routing (either via default route
+ * or user set route) so get peer according to
+ * the destination address.
+ */
+ read_lock_irqsave(&devices_lock, flags);
+ peer = peer_lookup_dst(dev, &hdr->daddr, skb);
+ read_unlock_irqrestore(&devices_lock, flags);
+ if (!peer) {
+ BT_DBG("no such peer %pMR found", &addr);
+ return -ENOENT;
+ }
}
daddr = peer->eui64_addr;
@@ -520,6 +579,8 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
read_lock_irqsave(&devices_lock, flags);
peer = peer_lookup_ba(dev, &addr, addr_type);
+ if (!peer)
+ peer = peer_lookup_dst(dev, &lowpan_cb(skb)->addr, skb);
read_unlock_irqrestore(&devices_lock, flags);
BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p",
@@ -671,6 +732,14 @@ static struct l2cap_chan *chan_open(struct l2cap_chan *pchan)
return chan;
}
+static void set_ip_addr_bits(u8 addr_type, u8 *addr)
+{
+ if (addr_type == BDADDR_LE_PUBLIC)
+ *addr |= 0x02;
+ else
+ *addr &= ~0x02;
+}
+
static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
struct lowpan_dev *dev)
{
@@ -693,6 +762,11 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8,
EUI64_ADDR_LEN);
+ /* IPv6 address needs to have the U/L bit set properly so toggle
+ * it back here.
+ */
+ set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8);
+
write_lock_irqsave(&devices_lock, flags);
INIT_LIST_HEAD(&peer->list);
peer_add(dev, peer);
@@ -772,16 +846,16 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
ifup(dev->netdev);
}
-static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *chan)
+static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
{
- struct l2cap_chan *pchan;
+ struct l2cap_chan *chan;
- pchan = chan_open(chan);
- pchan->ops = chan->ops;
+ chan = chan_open(pchan);
+ chan->ops = pchan->ops;
BT_DBG("chan %p pchan %p", chan, pchan);
- return pchan;
+ return chan;
}
static void delete_netdev(struct work_struct *work)
@@ -890,7 +964,7 @@ static void chan_resume_cb(struct l2cap_chan *chan)
static long chan_get_sndtimeo_cb(struct l2cap_chan *chan)
{
- return msecs_to_jiffies(1000);
+ return L2CAP_CONN_TIMEOUT;
}
static const struct l2cap_ops bt_6lowpan_chan_ops = {
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 016cdb6..2640d78 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -149,15 +149,14 @@ static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
if (ret) {
BT_DBG("crypto_ahash_setkey failed: err %d", ret);
} else {
- struct {
- struct shash_desc shash;
- char ctx[crypto_shash_descsize(tfm)];
- } desc;
+ char desc[sizeof(struct shash_desc) +
+ crypto_shash_descsize(tfm)] CRYPTO_MINALIGN_ATTR;
+ struct shash_desc *shash = (struct shash_desc *)desc;
- desc.shash.tfm = tfm;
- desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ shash->tfm = tfm;
+ shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = crypto_shash_digest(&desc.shash, plaintext, psize,
+ ret = crypto_shash_digest(shash, plaintext, psize,
output);
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index b50dabb..e3d7ae9 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -122,17 +122,30 @@ static void hci_reject_sco(struct hci_conn *conn)
hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp);
}
-void hci_disconnect(struct hci_conn *conn, __u8 reason)
+int hci_disconnect(struct hci_conn *conn, __u8 reason)
{
struct hci_cp_disconnect cp;
BT_DBG("hcon %p", conn);
+ /* When we are master of an established connection and it enters
+ * the disconnect timeout, then go ahead and try to read the
+ * current clock offset. Processing of the result is done
+ * within the event handling and hci_clock_offset_evt function.
+ */
+ if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER) {
+ struct hci_dev *hdev = conn->hdev;
+ struct hci_cp_read_clock_offset cp;
+
+ cp.handle = cpu_to_le16(conn->handle);
+ hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(cp), &cp);
+ }
+
conn->state = BT_DISCONN;
cp.handle = cpu_to_le16(conn->handle);
cp.reason = reason;
- hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
+ return hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
}
static void hci_amp_disconn(struct hci_conn *conn)
@@ -325,25 +338,6 @@ static void hci_conn_timeout(struct work_struct *work)
hci_amp_disconn(conn);
} else {
__u8 reason = hci_proto_disconn_ind(conn);
-
- /* When we are master of an established connection
- * and it enters the disconnect timeout, then go
- * ahead and try to read the current clock offset.
- *
- * Processing of the result is done within the
- * event handling and hci_clock_offset_evt function.
- */
- if (conn->type == ACL_LINK &&
- conn->role == HCI_ROLE_MASTER) {
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_read_clock_offset cp;
-
- cp.handle = cpu_to_le16(conn->handle);
-
- hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET,
- sizeof(cp), &cp);
- }
-
hci_disconnect(conn, reason);
}
break;
@@ -589,6 +583,15 @@ EXPORT_SYMBOL(hci_get_route);
void hci_le_conn_failed(struct hci_conn *conn, u8 status)
{
struct hci_dev *hdev = conn->hdev;
+ struct hci_conn_params *params;
+
+ params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst,
+ conn->dst_type);
+ if (params && params->conn) {
+ hci_conn_drop(params->conn);
+ hci_conn_put(params->conn);
+ params->conn = NULL;
+ }
conn->state = BT_CLOSED;
@@ -1282,11 +1285,16 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
BT_DBG("%s hcon %p", hdev->name, conn);
+ if (test_bit(HCI_CONN_DROP, &conn->flags)) {
+ BT_DBG("Refusing to create new hci_chan");
+ return NULL;
+ }
+
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
if (!chan)
return NULL;
- chan->conn = conn;
+ chan->conn = hci_conn_get(conn);
skb_queue_head_init(&chan->data_q);
chan->state = BT_CONNECTED;
@@ -1306,7 +1314,10 @@ void hci_chan_del(struct hci_chan *chan)
synchronize_rcu();
- hci_conn_drop(conn);
+ /* Prevent new hci_chan's to be created for this hci_conn */
+ set_bit(HCI_CONN_DROP, &conn->flags);
+
+ hci_conn_put(conn);
skb_queue_purge(&chan->data_q);
kfree(chan);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c32d361..0d3782a 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1898,6 +1898,8 @@ static int __hci_init(struct hci_dev *hdev)
debugfs_create_u16("discov_interleaved_timeout", 0644,
hdev->debugfs,
&hdev->discov_interleaved_timeout);
+
+ smp_register(hdev);
}
return 0;
@@ -2536,8 +2538,14 @@ static void hci_pend_le_actions_clear(struct hci_dev *hdev)
{
struct hci_conn_params *p;
- list_for_each_entry(p, &hdev->le_conn_params, list)
+ list_for_each_entry(p, &hdev->le_conn_params, list) {
+ if (p->conn) {
+ hci_conn_drop(p->conn);
+ hci_conn_put(p->conn);
+ p->conn = NULL;
+ }
list_del_init(&p->action);
+ }
BT_DBG("All LE pending actions cleared");
}
@@ -2578,8 +2586,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_lock(hdev);
hci_inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
hci_pend_le_actions_clear(hdev);
+ hci_conn_hash_flush(hdev);
hci_dev_unlock(hdev);
hci_notify(hdev, HCI_DEV_DOWN);
@@ -3233,7 +3241,7 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
}
list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
- if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) {
+ if (smp_irk_matches(hdev, irk->val, rpa)) {
bacpy(&irk->rpa, rpa);
return irk;
}
@@ -3718,6 +3726,18 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
return 0;
}
+static void hci_conn_params_free(struct hci_conn_params *params)
+{
+ if (params->conn) {
+ hci_conn_drop(params->conn);
+ hci_conn_put(params->conn);
+ }
+
+ list_del(&params->action);
+ list_del(&params->list);
+ kfree(params);
+}
+
/* This function requires the caller holds hdev->lock */
void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
{
@@ -3727,9 +3747,7 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
if (!params)
return;
- list_del(&params->action);
- list_del(&params->list);
- kfree(params);
+ hci_conn_params_free(params);
hci_update_background_scan(hdev);
@@ -3756,11 +3774,8 @@ void hci_conn_params_clear_all(struct hci_dev *hdev)
{
struct hci_conn_params *params, *tmp;
- list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) {
- list_del(&params->action);
- list_del(&params->list);
- kfree(params);
- }
+ list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list)
+ hci_conn_params_free(params);
hci_update_background_scan(hdev);
@@ -3882,7 +3897,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
!bacmp(&hdev->random_addr, &hdev->rpa))
return 0;
- err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa);
+ err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa);
if (err < 0) {
BT_ERR("%s failed to generate new RPA", hdev->name);
return err;
@@ -4090,18 +4105,9 @@ int hci_register_dev(struct hci_dev *hdev)
dev_set_name(&hdev->dev, "%s", hdev->name);
- hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0,
- CRYPTO_ALG_ASYNC);
- if (IS_ERR(hdev->tfm_aes)) {
- BT_ERR("Unable to create crypto context");
- error = PTR_ERR(hdev->tfm_aes);
- hdev->tfm_aes = NULL;
- goto err_wqueue;
- }
-
error = device_add(&hdev->dev);
if (error < 0)
- goto err_tfm;
+ goto err_wqueue;
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
@@ -4143,8 +4149,6 @@ int hci_register_dev(struct hci_dev *hdev)
return id;
-err_tfm:
- crypto_free_blkcipher(hdev->tfm_aes);
err_wqueue:
destroy_workqueue(hdev->workqueue);
destroy_workqueue(hdev->req_workqueue);
@@ -4196,8 +4200,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
rfkill_destroy(hdev->rfkill);
}
- if (hdev->tfm_aes)
- crypto_free_blkcipher(hdev->tfm_aes);
+ smp_unregister(hdev);
device_del(&hdev->dev);
@@ -5680,3 +5683,52 @@ void hci_update_background_scan(struct hci_dev *hdev)
if (err)
BT_ERR("Failed to run HCI request: err %d", err);
}
+
+static bool disconnected_whitelist_entries(struct hci_dev *hdev)
+{
+ struct bdaddr_list *b;
+
+ list_for_each_entry(b, &hdev->whitelist, list) {
+ struct hci_conn *conn;
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr);
+ if (!conn)
+ return true;
+
+ if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+ return true;
+ }
+
+ return false;
+}
+
+void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req)
+{
+ u8 scan;
+
+ if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
+ return;
+
+ if (!hdev_is_powered(hdev))
+ return;
+
+ if (mgmt_powering_down(hdev))
+ return;
+
+ if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
+ disconnected_whitelist_entries(hdev))
+ scan = SCAN_PAGE;
+ else
+ scan = SCAN_DISABLED;
+
+ if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE))
+ return;
+
+ if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+ scan |= SCAN_INQUIRY;
+
+ if (req)
+ hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+ else
+ hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index be35598..3a8381a 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2071,6 +2071,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
cp.handle = ev->handle;
hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
sizeof(cp), &cp);
+
+ hci_update_page_scan(hdev, NULL);
}
/* Set packet type for incoming connection */
@@ -2247,9 +2249,12 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
reason, mgmt_connected);
- if (conn->type == ACL_LINK &&
- test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
- hci_remove_link_key(hdev, &conn->dst);
+ if (conn->type == ACL_LINK) {
+ if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
+ hci_remove_link_key(hdev, &conn->dst);
+
+ hci_update_page_scan(hdev, NULL);
+ }
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (params) {
@@ -2315,8 +2320,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->sec_level = conn->pending_sec_level;
}
} else {
- mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
- ev->status);
+ mgmt_auth_failed(conn, ev->status);
}
clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
@@ -3895,8 +3899,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
* event gets always produced as initiator and is also mapped to
* the mgmt_auth_failed event */
if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status)
- mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
- ev->status);
+ mgmt_auth_failed(conn, ev->status);
hci_conn_drop(conn);
@@ -4188,16 +4191,16 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->dst_type = irk->addr_type;
}
- if (conn->dst_type == ADDR_LE_DEV_PUBLIC)
- addr_type = BDADDR_LE_PUBLIC;
- else
- addr_type = BDADDR_LE_RANDOM;
-
if (ev->status) {
hci_le_conn_failed(conn, ev->status);
goto unlock;
}
+ if (conn->dst_type == ADDR_LE_DEV_PUBLIC)
+ addr_type = BDADDR_LE_PUBLIC;
+ else
+ addr_type = BDADDR_LE_RANDOM;
+
/* Drop the connection if the device is blocked */
if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) {
hci_conn_drop(conn);
@@ -4220,9 +4223,16 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_proto_connect_cfm(conn, ev->status);
- params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
- if (params)
+ params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst,
+ conn->dst_type);
+ if (params) {
list_del_init(&params->action);
+ if (params->conn) {
+ hci_conn_drop(params->conn);
+ hci_conn_put(params->conn);
+ params->conn = NULL;
+ }
+ }
unlock:
hci_update_background_scan(hdev);
@@ -4304,8 +4314,16 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER);
- if (!IS_ERR(conn))
+ if (!IS_ERR(conn)) {
+ /* Store the pointer since we don't really have any
+ * other owner of the object besides the params that
+ * triggered it. This way we can abort the connection if
+ * the parameters get removed and keep the reference
+ * count consistent once the connection is established.
+ */
+ params->conn = hci_conn_get(conn);
return;
+ }
switch (PTR_ERR(conn)) {
case -EBUSY:
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 6c7ecf1..1b7d605 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -915,7 +915,7 @@ static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr,
/* connection management */
bacpy(&session->bdaddr, bdaddr);
- session->conn = conn;
+ session->conn = l2cap_conn_get(conn);
session->user.probe = hidp_session_probe;
session->user.remove = hidp_session_remove;
session->ctrl_sock = ctrl_sock;
@@ -941,13 +941,13 @@ static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr,
if (ret)
goto err_free;
- l2cap_conn_get(session->conn);
get_file(session->intr_sock->file);
get_file(session->ctrl_sock->file);
*out = session;
return 0;
err_free:
+ l2cap_conn_put(session->conn);
kfree(session);
return ret;
}
@@ -1327,10 +1327,8 @@ int hidp_connection_add(struct hidp_connadd_req *req,
conn = NULL;
l2cap_chan_lock(chan);
- if (chan->conn) {
- l2cap_conn_get(chan->conn);
- conn = chan->conn;
- }
+ if (chan->conn)
+ conn = l2cap_conn_get(chan->conn);
l2cap_chan_unlock(chan);
if (!conn)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 46547b9..b71430c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -210,6 +210,10 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
{
write_lock(&chan_list_lock);
+ /* Override the defaults (which are for conn-oriented) */
+ chan->omtu = L2CAP_DEFAULT_MTU;
+ chan->chan_type = L2CAP_CHAN_FIXED;
+
chan->scid = scid;
write_unlock(&chan_list_lock);
@@ -542,7 +546,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
l2cap_chan_hold(chan);
- hci_conn_hold(conn->hcon);
+ /* Only keep a reference for fixed channels if they requested it */
+ if (chan->chan_type != L2CAP_CHAN_FIXED ||
+ test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
+ hci_conn_hold(conn->hcon);
list_add(&chan->list, &conn->chan_l);
}
@@ -562,6 +569,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
+ chan->ops->teardown(chan, err);
+
if (conn) {
struct amp_mgr *mgr = conn->hcon->amp_mgr;
/* Delete from channel list */
@@ -571,7 +580,12 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
chan->conn = NULL;
- if (chan->scid != L2CAP_CID_A2MP)
+ /* Reference was only held for non-fixed channels or
+ * fixed channels that explicitly requested it using the
+ * FLAG_HOLD_HCI_CONN flag.
+ */
+ if (chan->chan_type != L2CAP_CHAN_FIXED ||
+ test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
hci_conn_drop(conn->hcon);
if (mgr && mgr->bredr_chan == chan)
@@ -585,8 +599,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
amp_disconnect_logical_link(hs_hchan);
}
- chan->ops->teardown(chan, err);
-
if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
return;
@@ -619,9 +631,11 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
}
EXPORT_SYMBOL_GPL(l2cap_chan_del);
-void l2cap_conn_update_id_addr(struct hci_conn *hcon)
+static void l2cap_conn_update_id_addr(struct work_struct *work)
{
- struct l2cap_conn *conn = hcon->l2cap_data;
+ struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+ id_addr_update_work);
+ struct hci_conn *hcon = conn->hcon;
struct l2cap_chan *chan;
mutex_lock(&conn->chan_lock);
@@ -1082,6 +1096,9 @@ static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll)
static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
{
+ if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
+ return true;
+
return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
}
@@ -1417,71 +1434,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
mutex_unlock(&conn->chan_lock);
}
-/* Find socket with cid and source/destination bdaddr.
- * Returns closest match, locked.
- */
-static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
- bdaddr_t *src,
- bdaddr_t *dst)
-{
- struct l2cap_chan *c, *c1 = NULL;
-
- read_lock(&chan_list_lock);
-
- list_for_each_entry(c, &chan_list, global_l) {
- if (state && c->state != state)
- continue;
-
- if (c->scid == cid) {
- int src_match, dst_match;
- int src_any, dst_any;
-
- /* Exact match. */
- src_match = !bacmp(&c->src, src);
- dst_match = !bacmp(&c->dst, dst);
- if (src_match && dst_match) {
- read_unlock(&chan_list_lock);
- return c;
- }
-
- /* Closest match */
- src_any = !bacmp(&c->src, BDADDR_ANY);
- dst_any = !bacmp(&c->dst, BDADDR_ANY);
- if ((src_match && dst_any) || (src_any && dst_match) ||
- (src_any && dst_any))
- c1 = c;
- }
- }
-
- read_unlock(&chan_list_lock);
-
- return c1;
-}
-
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
{
struct hci_conn *hcon = conn->hcon;
struct hci_dev *hdev = hcon->hdev;
- struct l2cap_chan *chan, *pchan;
- u8 dst_type;
- BT_DBG("");
+ BT_DBG("%s conn %p", hdev->name, conn);
- /* Check if we have socket listening on cid */
- pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
- &hcon->src, &hcon->dst);
- if (!pchan)
- return;
-
- /* Client ATT sockets should override the server one */
- if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT))
- return;
-
- dst_type = bdaddr_type(hcon, hcon->dst_type);
-
- /* If device is blocked, do not create a channel for it */
- if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
- return;
+ /* For outgoing pairing which doesn't necessarily have an
+ * associated socket (e.g. mgmt_pair_device).
+ */
+ if (hcon->out)
+ smp_conn_security(hcon, hcon->pending_sec_level);
/* For LE slave connections, make sure the connection interval
* is in the range of the minium and maximum interval that has
@@ -1501,22 +1465,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
l2cap_send_cmd(conn, l2cap_get_ident(conn),
L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req);
}
-
- l2cap_chan_lock(pchan);
-
- chan = pchan->ops->new_connection(pchan);
- if (!chan)
- goto clean;
-
- bacpy(&chan->src, &hcon->src);
- bacpy(&chan->dst, &hcon->dst);
- chan->src_type = bdaddr_type(hcon, hcon->src_type);
- chan->dst_type = dst_type;
-
- __l2cap_chan_add(conn, chan);
-
-clean:
- l2cap_chan_unlock(pchan);
}
static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -1526,17 +1474,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
BT_DBG("conn %p", conn);
- /* For outgoing pairing which doesn't necessarily have an
- * associated socket (e.g. mgmt_pair_device).
- */
- if (hcon->out && hcon->type == LE_LINK)
- smp_conn_security(hcon, hcon->pending_sec_level);
-
mutex_lock(&conn->chan_lock);
- if (hcon->type == LE_LINK)
- l2cap_le_conn_ready(conn);
-
list_for_each_entry(chan, &conn->chan_l, list) {
l2cap_chan_lock(chan);
@@ -1560,6 +1499,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
mutex_unlock(&conn->chan_lock);
+ if (hcon->type == LE_LINK)
+ l2cap_le_conn_ready(conn);
+
queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
}
@@ -1695,8 +1637,14 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
if (work_pending(&conn->pending_rx_work))
cancel_work_sync(&conn->pending_rx_work);
+ if (work_pending(&conn->id_addr_update_work))
+ cancel_work_sync(&conn->id_addr_update_work);
+
l2cap_unregister_all_users(conn);
+ /* Force the connection to be immediately dropped */
+ hcon->disc_timeout = 0;
+
mutex_lock(&conn->chan_lock);
/* Kill channels */
@@ -1719,29 +1667,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
cancel_delayed_work_sync(&conn->info_timer);
- if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
- cancel_delayed_work_sync(&conn->security_timer);
- smp_chan_destroy(conn);
- }
-
hcon->l2cap_data = NULL;
conn->hchan = NULL;
l2cap_conn_put(conn);
}
-static void security_timeout(struct work_struct *work)
-{
- struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
- security_timer.work);
-
- BT_DBG("conn %p", conn);
-
- if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
- smp_chan_destroy(conn);
- l2cap_conn_del(conn->hcon, ETIMEDOUT);
- }
-}
-
static void l2cap_conn_free(struct kref *ref)
{
struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref);
@@ -1750,9 +1680,10 @@ static void l2cap_conn_free(struct kref *ref)
kfree(conn);
}
-void l2cap_conn_get(struct l2cap_conn *conn)
+struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn)
{
kref_get(&conn->ref);
+ return conn;
}
EXPORT_SYMBOL(l2cap_conn_get);
@@ -1794,6 +1725,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
src_match = !bacmp(&c->src, src);
dst_match = !bacmp(&c->dst, dst);
if (src_match && dst_match) {
+ l2cap_chan_hold(c);
read_unlock(&chan_list_lock);
return c;
}
@@ -1807,6 +1739,9 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
}
}
+ if (c1)
+ l2cap_chan_hold(c1);
+
read_unlock(&chan_list_lock);
return c1;
@@ -2027,10 +1962,12 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
tx_skb->data + L2CAP_HDR_SIZE);
}
+ /* Update FCS */
if (chan->fcs == L2CAP_FCS_CRC16) {
- u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len);
- put_unaligned_le16(fcs, skb_put(tx_skb,
- L2CAP_FCS_SIZE));
+ u16 fcs = crc16(0, (u8 *) tx_skb->data,
+ tx_skb->len - L2CAP_FCS_SIZE);
+ put_unaligned_le16(fcs, skb_tail_pointer(tx_skb) -
+ L2CAP_FCS_SIZE);
}
l2cap_do_send(chan, tx_skb);
@@ -2334,7 +2271,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
} else {
sar = L2CAP_SAR_START;
sdu_len = len;
- pdu_len -= L2CAP_SDULEN_SIZE;
}
while (len > 0) {
@@ -2349,10 +2285,8 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
__skb_queue_tail(seg_queue, skb);
len -= pdu_len;
- if (sdu_len) {
+ if (sdu_len)
sdu_len = 0;
- pdu_len += L2CAP_SDULEN_SIZE;
- }
if (len <= pdu_len) {
sar = L2CAP_SAR_END;
@@ -2418,12 +2352,8 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
BT_DBG("chan %p, msg %p, len %zu", chan, msg, len);
- pdu_len = chan->conn->mtu - L2CAP_HDR_SIZE;
-
- pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
-
sdu_len = len;
- pdu_len -= L2CAP_SDULEN_SIZE;
+ pdu_len = chan->remote_mps - L2CAP_SDULEN_SIZE;
while (len > 0) {
if (len <= pdu_len)
@@ -3884,6 +3814,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
response:
l2cap_chan_unlock(pchan);
mutex_unlock(&conn->chan_lock);
+ l2cap_chan_put(pchan);
sendresp:
rsp.scid = cpu_to_le16(scid);
@@ -5487,6 +5418,11 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
l2cap_state_change(chan, BT_CONNECT2);
+ /* The following result value is actually not defined
+ * for LE CoC but we use it to let the function know
+ * that it should bail out after doing its cleanup
+ * instead of sending a response.
+ */
result = L2CAP_CR_PEND;
chan->ops->defer(chan);
} else {
@@ -5497,6 +5433,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
response_unlock:
l2cap_chan_unlock(pchan);
mutex_unlock(&conn->chan_lock);
+ l2cap_chan_put(pchan);
if (result == L2CAP_CR_PEND)
return 0;
@@ -6845,12 +6782,12 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
struct l2cap_chan *chan;
if (hcon->type != ACL_LINK)
- goto drop;
+ goto free_skb;
chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst,
ACL_LINK);
if (!chan)
- goto drop;
+ goto free_skb;
BT_DBG("chan %p, len %d", chan, skb->len);
@@ -6864,36 +6801,14 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
bacpy(&bt_cb(skb)->bdaddr, &hcon->dst);
bt_cb(skb)->psm = psm;
- if (!chan->ops->recv(chan, skb))
- return;
-
-drop:
- kfree_skb(skb);
-}
-
-static void l2cap_att_channel(struct l2cap_conn *conn,
- struct sk_buff *skb)
-{
- struct hci_conn *hcon = conn->hcon;
- struct l2cap_chan *chan;
-
- if (hcon->type != LE_LINK)
- goto drop;
-
- chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT,
- &hcon->src, &hcon->dst);
- if (!chan)
- goto drop;
-
- BT_DBG("chan %p, len %d", chan, skb->len);
-
- if (chan->imtu < skb->len)
- goto drop;
-
- if (!chan->ops->recv(chan, skb))
+ if (!chan->ops->recv(chan, skb)) {
+ l2cap_chan_put(chan);
return;
+ }
drop:
+ l2cap_chan_put(chan);
+free_skb:
kfree_skb(skb);
}
@@ -6942,19 +6857,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
l2cap_conless_channel(conn, psm, skb);
break;
- case L2CAP_CID_ATT:
- l2cap_att_channel(conn, skb);
- break;
-
case L2CAP_CID_LE_SIGNALING:
l2cap_le_sig_channel(conn, skb);
break;
- case L2CAP_CID_SMP:
- if (smp_sig_channel(conn, skb))
- l2cap_conn_del(conn->hcon, EACCES);
- break;
-
default:
l2cap_data_channel(conn, cid, skb);
break;
@@ -6993,8 +6899,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
kref_init(&conn->ref);
hcon->l2cap_data = conn;
- conn->hcon = hcon;
- hci_conn_get(conn->hcon);
+ conn->hcon = hci_conn_get(hcon);
conn->hchan = hchan;
BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
@@ -7023,13 +6928,11 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
INIT_LIST_HEAD(&conn->chan_l);
INIT_LIST_HEAD(&conn->users);
- if (hcon->type == LE_LINK)
- INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
- else
- INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
+ INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
skb_queue_head_init(&conn->pending_rx);
INIT_WORK(&conn->pending_rx_work, process_pending_rx);
+ INIT_WORK(&conn->id_addr_update_work, l2cap_conn_update_id_addr);
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
@@ -7172,9 +7075,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
bacpy(&chan->src, &hcon->src);
chan->src_type = bdaddr_type(hcon, hcon->src_type);
- l2cap_chan_unlock(chan);
l2cap_chan_add(conn, chan);
- l2cap_chan_lock(chan);
/* l2cap_chan_add takes its own ref so we can drop this one */
hci_conn_drop(hcon);
@@ -7239,19 +7140,99 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
return exact ? lm1 : lm2;
}
+/* Find the next fixed channel in BT_LISTEN state, continue iteration
+ * from an existing channel in the list or from the beginning of the
+ * global list (by passing NULL as first parameter).
+ */
+static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
+ bdaddr_t *src, u8 link_type)
+{
+ read_lock(&chan_list_lock);
+
+ if (c)
+ c = list_next_entry(c, global_l);
+ else
+ c = list_entry(chan_list.next, typeof(*c), global_l);
+
+ list_for_each_entry_from(c, &chan_list, global_l) {
+ if (c->chan_type != L2CAP_CHAN_FIXED)
+ continue;
+ if (c->state != BT_LISTEN)
+ continue;
+ if (bacmp(&c->src, src) && bacmp(&c->src, BDADDR_ANY))
+ continue;
+ if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR)
+ continue;
+ if (link_type == LE_LINK && c->src_type == BDADDR_BREDR)
+ continue;
+
+ l2cap_chan_hold(c);
+ read_unlock(&chan_list_lock);
+ return c;
+ }
+
+ read_unlock(&chan_list_lock);
+
+ return NULL;
+}
+
void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
{
+ struct hci_dev *hdev = hcon->hdev;
struct l2cap_conn *conn;
+ struct l2cap_chan *pchan;
+ u8 dst_type;
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
- if (!status) {
- conn = l2cap_conn_add(hcon);
- if (conn)
- l2cap_conn_ready(conn);
- } else {
+ if (status) {
l2cap_conn_del(hcon, bt_to_errno(status));
+ return;
+ }
+
+ conn = l2cap_conn_add(hcon);
+ if (!conn)
+ return;
+
+ dst_type = bdaddr_type(hcon, hcon->dst_type);
+
+ /* If device is blocked, do not create channels for it */
+ if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
+ return;
+
+ /* Find fixed channels and notify them of the new connection. We
+ * use multiple individual lookups, continuing each time where
+ * we left off, because the list lock would prevent calling the
+ * potentially sleeping l2cap_chan_lock() function.
+ */
+ pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr, hcon->type);
+ while (pchan) {
+ struct l2cap_chan *chan, *next;
+
+ /* Client fixed channels should override server ones */
+ if (__l2cap_get_chan_by_dcid(conn, pchan->scid))
+ goto next;
+
+ l2cap_chan_lock(pchan);
+ chan = pchan->ops->new_connection(pchan);
+ if (chan) {
+ bacpy(&chan->src, &hcon->src);
+ bacpy(&chan->dst, &hcon->dst);
+ chan->src_type = bdaddr_type(hcon, hcon->src_type);
+ chan->dst_type = dst_type;
+
+ __l2cap_chan_add(conn, chan);
+ }
+
+ l2cap_chan_unlock(pchan);
+next:
+ next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr,
+ hcon->type);
+ l2cap_chan_put(pchan);
+ pchan = next;
}
+
+ l2cap_conn_ready(conn);
}
int l2cap_disconn_ind(struct hci_conn *hcon)
@@ -7299,12 +7280,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt);
- if (hcon->type == LE_LINK) {
- if (!status && encrypt)
- smp_distribute_keys(conn);
- cancel_delayed_work(&conn->security_timer);
- }
-
mutex_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) {
@@ -7318,15 +7293,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
continue;
}
- if (chan->scid == L2CAP_CID_ATT) {
- if (!status && encrypt) {
- chan->sec_level = hcon->sec_level;
- l2cap_chan_ready(chan);
- }
-
- l2cap_chan_unlock(chan);
- continue;
- }
+ if (!status && encrypt)
+ chan->sec_level = hcon->sec_level;
if (!__l2cap_no_conn_pending(chan)) {
l2cap_chan_unlock(chan);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 1884f72..31f106e 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -99,15 +99,6 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
return -EINVAL;
- if (la.l2_cid) {
- /* When the socket gets created it defaults to
- * CHAN_CONN_ORIENTED, so we need to overwrite the
- * default here.
- */
- chan->chan_type = L2CAP_CHAN_FIXED;
- chan->omtu = L2CAP_DEFAULT_MTU;
- }
-
if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
/* We only allow ATT user space socket */
if (la.l2_cid &&
@@ -155,6 +146,14 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
case L2CAP_CHAN_RAW:
chan->sec_level = BT_SECURITY_SDP;
break;
+ case L2CAP_CHAN_FIXED:
+ /* Fixed channels default to the L2CAP core not holding a
+ * hci_conn reference for them. For fixed channels mapping to
+ * L2CAP sockets we do want to hold a reference so set the
+ * appropriate flag to request it.
+ */
+ set_bit(FLAG_HOLD_HCI_CONN, &chan->flags);
+ break;
}
bacpy(&chan->src, &la.l2_bdaddr);
@@ -790,6 +789,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
if (chan->scid == L2CAP_CID_ATT) {
if (smp_conn_security(conn->hcon, sec.level))
break;
+ set_bit(FLAG_PENDING_SECURITY, &chan->flags);
sk->sk_state = BT_CONFIG;
chan->state = BT_CONFIG;
@@ -1359,6 +1359,11 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan)
{
struct sock *sk = chan->data;
+ if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) {
+ sk->sk_state = BT_CONNECTED;
+ chan->state = BT_CONNECTED;
+ }
+
clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
sk->sk_state_change(sk);
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b8554d4..efb71b0 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -129,9 +129,6 @@ static const u16 mgmt_events[] = {
#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
-#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
- !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
-
struct pending_cmd {
struct list_head list;
u16 opcode;
@@ -1536,9 +1533,11 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
/* When the discoverable mode gets changed, make sure
* that class of device has the limited discoverable
- * bit correctly set.
+ * bit correctly set. Also update page scan based on whitelist
+ * entries.
*/
hci_req_init(&req, hdev);
+ hci_update_page_scan(hdev, &req);
update_class(&req);
hci_req_run(&req, NULL);
@@ -1785,6 +1784,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status)
if (conn_changed || discov_changed) {
new_settings(hdev, cmd->sk);
+ hci_update_page_scan(hdev, NULL);
if (discov_changed)
mgmt_update_adv_data(hdev);
hci_update_background_scan(hdev);
@@ -1818,6 +1818,7 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
return err;
if (changed) {
+ hci_update_page_scan(hdev, NULL);
hci_update_background_scan(hdev);
return new_settings(hdev, sk);
}
@@ -2787,7 +2788,6 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
{
struct mgmt_cp_disconnect *cp = data;
struct mgmt_rp_disconnect rp;
- struct hci_cp_disconnect dc;
struct pending_cmd *cmd;
struct hci_conn *conn;
int err;
@@ -2835,10 +2835,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
goto failed;
}
- dc.handle = cpu_to_le16(conn->handle);
- dc.reason = HCI_ERROR_REMOTE_USER_TERM;
-
- err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
+ err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -3062,6 +3059,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
conn->disconn_cfm_cb = NULL;
hci_conn_drop(conn);
+ hci_conn_put(conn);
mgmt_pending_remove(cmd);
}
@@ -3211,7 +3209,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
}
conn->io_capability = cp->io_cap;
- cmd->user_data = conn;
+ cmd->user_data = hci_conn_get(conn);
if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
hci_conn_security(conn, sec_level, auth_type, true))
@@ -4381,27 +4379,6 @@ unlock:
return err;
}
-static void set_bredr_scan(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 scan = 0;
-
- /* Ensure that fast connectable is disabled. This function will
- * not do anything if the page scan parameters are already what
- * they should be.
- */
- write_fast_connectable(req, false);
-
- if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
- !list_empty(&hdev->whitelist))
- scan |= SCAN_PAGE;
- if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
- scan |= SCAN_INQUIRY;
-
- if (scan)
- hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
static void set_bredr_complete(struct hci_dev *hdev, u8 status)
{
struct pending_cmd *cmd;
@@ -4507,9 +4484,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
hci_req_init(&req, hdev);
- if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
- !list_empty(&hdev->whitelist))
- set_bredr_scan(&req);
+ write_fast_connectable(&req, false);
+ hci_update_page_scan(hdev, &req);
/* Since only the advertising data flags will change, there
* is no need to update the scan response data.
@@ -4935,6 +4911,7 @@ static void get_conn_info_complete(struct pending_cmd *cmd, void *data)
match->mgmt_status, &rp, sizeof(rp));
hci_conn_drop(conn);
+ hci_conn_put(conn);
mgmt_pending_remove(cmd);
}
@@ -5091,7 +5068,7 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
}
hci_conn_hold(conn);
- cmd->user_data = conn;
+ cmd->user_data = hci_conn_get(conn);
conn->conn_info_timestamp = jiffies;
} else {
@@ -5155,8 +5132,10 @@ send_rsp:
cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
&rp, sizeof(rp));
mgmt_pending_remove(cmd);
- if (conn)
+ if (conn) {
hci_conn_drop(conn);
+ hci_conn_put(conn);
+ }
unlock:
hci_dev_unlock(hdev);
@@ -5219,7 +5198,7 @@ static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
if (conn) {
hci_conn_hold(conn);
- cmd->user_data = conn;
+ cmd->user_data = hci_conn_get(conn);
hci_cp.handle = cpu_to_le16(conn->handle);
hci_cp.which = 0x01; /* Piconet clock */
@@ -5235,27 +5214,6 @@ unlock:
return err;
}
-/* Helper for Add/Remove Device commands */
-static void update_page_scan(struct hci_dev *hdev, u8 scan)
-{
- if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
- return;
-
- if (!hdev_is_powered(hdev))
- return;
-
- /* If HCI_CONNECTABLE is set then Add/Remove Device should not
- * make any changes to page scanning.
- */
- if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
- return;
-
- if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
- scan |= SCAN_INQUIRY;
-
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
static void device_added(struct sock *sk, struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 type, u8 action)
{
@@ -5291,8 +5249,6 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev);
if (cp->addr.type == BDADDR_BREDR) {
- bool update_scan;
-
/* Only incoming connections action is supported for now */
if (cp->action != 0x01) {
err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
@@ -5301,15 +5257,12 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
- update_scan = list_empty(&hdev->whitelist);
-
err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
cp->addr.type);
if (err)
goto unlock;
- if (update_scan)
- update_page_scan(hdev, SCAN_PAGE);
+ hci_update_page_scan(hdev, NULL);
goto added;
}
@@ -5392,8 +5345,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
- if (list_empty(&hdev->whitelist))
- update_page_scan(hdev, SCAN_DISABLED);
+ hci_update_page_scan(hdev, NULL);
device_removed(sk, hdev, &cp->addr.bdaddr,
cp->addr.type);
@@ -5444,7 +5396,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
kfree(b);
}
- update_page_scan(hdev, SCAN_DISABLED);
+ hci_update_page_scan(hdev, NULL);
list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
@@ -5969,8 +5921,8 @@ static int powered_update_hci(struct hci_dev *hdev)
sizeof(link_sec), &link_sec);
if (lmp_bredr_capable(hdev)) {
- if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
- set_bredr_scan(&req);
+ write_fast_connectable(&req, false);
+ hci_update_page_scan(hdev, &req);
update_class(&req);
update_name(&req);
update_eir(&req);
@@ -6281,25 +6233,35 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
mgmt_pending_remove(cmd);
}
+bool mgmt_powering_down(struct hci_dev *hdev)
+{
+ struct pending_cmd *cmd;
+ struct mgmt_mode *cp;
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
+ if (!cmd)
+ return false;
+
+ cp = cmd->param;
+ if (!cp->val)
+ return true;
+
+ return false;
+}
+
void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 reason,
bool mgmt_connected)
{
struct mgmt_ev_device_disconnected ev;
- struct pending_cmd *power_off;
struct sock *sk = NULL;
- power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
- if (power_off) {
- struct mgmt_mode *cp = power_off->param;
-
- /* The connection is still in hci_conn_hash so test for 1
- * instead of 0 to know if this is the last one.
- */
- if (!cp->val && hci_conn_count(hdev) == 1) {
- cancel_delayed_work(&hdev->power_off);
- queue_work(hdev->req_workqueue, &hdev->power_off.work);
- }
+ /* The connection is still in hci_conn_hash so test for 1
+ * instead of 0 to know if this is the last one.
+ */
+ if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
+ cancel_delayed_work(&hdev->power_off);
+ queue_work(hdev->req_workqueue, &hdev->power_off.work);
}
if (!mgmt_connected)
@@ -6359,19 +6321,13 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status)
{
struct mgmt_ev_connect_failed ev;
- struct pending_cmd *power_off;
-
- power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
- if (power_off) {
- struct mgmt_mode *cp = power_off->param;
- /* The connection is still in hci_conn_hash so test for 1
- * instead of 0 to know if this is the last one.
- */
- if (!cp->val && hci_conn_count(hdev) == 1) {
- cancel_delayed_work(&hdev->power_off);
- queue_work(hdev->req_workqueue, &hdev->power_off.work);
- }
+ /* The connection is still in hci_conn_hash so test for 1
+ * instead of 0 to know if this is the last one.
+ */
+ if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
+ cancel_delayed_work(&hdev->power_off);
+ queue_work(hdev->req_workqueue, &hdev->power_off.work);
}
bacpy(&ev.addr.bdaddr, bdaddr);
@@ -6529,16 +6485,23 @@ int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
}
-void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, u8 status)
+void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
{
struct mgmt_ev_auth_failed ev;
+ struct pending_cmd *cmd;
+ u8 status = mgmt_status(hci_status);
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_bdaddr(link_type, addr_type);
- ev.status = mgmt_status(status);
+ bacpy(&ev.addr.bdaddr, &conn->dst);
+ ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
+ ev.status = status;
- mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
+ cmd = find_pairing(conn);
+
+ mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
+ cmd ? cmd->sk : NULL);
+
+ if (cmd)
+ pairing_complete(cmd, status);
}
void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index fd32943..25c9040 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -31,9 +31,13 @@
#include "smp.h"
+#define SMP_ALLOW_CMD(smp, code) set_bit(code, &smp->allow_cmd)
+#define SMP_DISALLOW_CMD(smp, code) clear_bit(code, &smp->allow_cmd)
+
#define SMP_TIMEOUT msecs_to_jiffies(30000)
#define AUTH_REQ_MASK 0x07
+#define KEY_DIST_MASK 0x07
enum {
SMP_FLAG_TK_VALID,
@@ -44,7 +48,10 @@ enum {
};
struct smp_chan {
- struct l2cap_conn *conn;
+ struct l2cap_conn *conn;
+ struct delayed_work security_timer;
+ unsigned long allow_cmd; /* Bitmask of allowed commands */
+
u8 preq[7]; /* SMP Pairing Request */
u8 prsp[7]; /* SMP Pairing Response */
u8 prnd[16]; /* SMP Pairing Random (local) */
@@ -139,12 +146,18 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
return 0;
}
-bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
- bdaddr_t *bdaddr)
+bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)
{
+ struct l2cap_chan *chan = hdev->smp_data;
+ struct crypto_blkcipher *tfm;
u8 hash[3];
int err;
+ if (!chan || !chan->data)
+ return false;
+
+ tfm = chan->data;
+
BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk);
err = smp_ah(tfm, irk, &bdaddr->b[3], hash);
@@ -154,10 +167,17 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
return !memcmp(bdaddr->b, hash, 3);
}
-int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa)
+int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
{
+ struct l2cap_chan *chan = hdev->smp_data;
+ struct crypto_blkcipher *tfm;
int err;
+ if (!chan || !chan->data)
+ return -EOPNOTSUPP;
+
+ tfm = chan->data;
+
get_random_bytes(&rpa->b[3], 3);
rpa->b[5] &= 0x3f; /* Clear two most significant bits */
@@ -235,47 +255,38 @@ static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16],
return err;
}
-static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
- u16 dlen, void *data)
+static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
{
- struct sk_buff *skb;
- struct l2cap_hdr *lh;
- int len;
-
- len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
-
- if (len > conn->mtu)
- return NULL;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp;
+ struct kvec iv[2];
+ struct msghdr msg;
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb)
- return NULL;
+ if (!chan)
+ return;
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->len = cpu_to_le16(sizeof(code) + dlen);
- lh->cid = cpu_to_le16(L2CAP_CID_SMP);
+ BT_DBG("code 0x%2.2x", code);
- memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
+ iv[0].iov_base = &code;
+ iv[0].iov_len = 1;
- memcpy(skb_put(skb, dlen), data, dlen);
+ iv[1].iov_base = data;
+ iv[1].iov_len = len;
- return skb;
-}
+ memset(&msg, 0, sizeof(msg));
-static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
-{
- struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
+ msg.msg_iov = (struct iovec *) &iv;
+ msg.msg_iovlen = 2;
- BT_DBG("code 0x%2.2x", code);
+ l2cap_chan_send(chan, &msg, 1 + len);
- if (!skb)
+ if (!chan->data)
return;
- skb->priority = HCI_PRIO_MAX;
- hci_send_acl(conn->hchan, skb, 0);
+ smp = chan->data;
- cancel_delayed_work_sync(&conn->security_timer);
- schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
+ cancel_delayed_work_sync(&smp->security_timer);
+ schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT);
}
static __u8 authreq_to_seclevel(__u8 authreq)
@@ -302,7 +313,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
struct smp_cmd_pairing *req,
struct smp_cmd_pairing *rsp, __u8 authreq)
{
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
struct hci_conn *hcon = conn->hcon;
struct hci_dev *hdev = hcon->hdev;
u8 local_dist = 0, remote_dist = 0;
@@ -345,7 +357,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
{
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
(max_key_size < SMP_MIN_ENC_KEY_SIZE))
@@ -356,21 +369,60 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
return 0;
}
+static void smp_chan_destroy(struct l2cap_conn *conn)
+{
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
+ bool complete;
+
+ BUG_ON(!smp);
+
+ cancel_delayed_work_sync(&smp->security_timer);
+
+ complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
+ mgmt_smp_complete(conn->hcon, complete);
+
+ kfree(smp->csrk);
+ kfree(smp->slave_csrk);
+
+ crypto_free_blkcipher(smp->tfm_aes);
+
+ /* If pairing failed clean up any keys we might have */
+ if (!complete) {
+ if (smp->ltk) {
+ list_del(&smp->ltk->list);
+ kfree(smp->ltk);
+ }
+
+ if (smp->slave_ltk) {
+ list_del(&smp->slave_ltk->list);
+ kfree(smp->slave_ltk);
+ }
+
+ if (smp->remote_irk) {
+ list_del(&smp->remote_irk->list);
+ kfree(smp->remote_irk);
+ }
+ }
+
+ chan->data = NULL;
+ kfree(smp);
+ hci_conn_drop(conn->hcon);
+}
+
static void smp_failure(struct l2cap_conn *conn, u8 reason)
{
struct hci_conn *hcon = conn->hcon;
+ struct l2cap_chan *chan = conn->smp;
if (reason)
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
&reason);
clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags);
- mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type,
- HCI_ERROR_AUTH_FAILURE);
+ mgmt_auth_failed(hcon, HCI_ERROR_AUTH_FAILURE);
- cancel_delayed_work_sync(&conn->security_timer);
-
- if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
+ if (chan->data)
smp_chan_destroy(conn);
}
@@ -405,7 +457,8 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
u8 local_io, u8 remote_io)
{
struct hci_conn *hcon = conn->hcon;
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
u8 method;
u32 passkey = 0;
int ret = 0;
@@ -503,6 +556,11 @@ static u8 smp_confirm(struct smp_chan *smp)
smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+ if (conn->hcon->out)
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+ else
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+
return 0;
}
@@ -574,82 +632,262 @@ static u8 smp_random(struct smp_chan *smp)
return 0;
}
-static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
+static void smp_notify_keys(struct l2cap_conn *conn)
{
- struct smp_chan *smp;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
+ struct hci_conn *hcon = conn->hcon;
+ struct hci_dev *hdev = hcon->hdev;
+ struct smp_cmd_pairing *req = (void *) &smp->preq[1];
+ struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
+ bool persistent;
- smp = kzalloc(sizeof(*smp), GFP_ATOMIC);
- if (!smp) {
- clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
- return NULL;
+ if (smp->remote_irk) {
+ mgmt_new_irk(hdev, smp->remote_irk);
+ /* Now that user space can be considered to know the
+ * identity address track the connection based on it
+ * from now on.
+ */
+ bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
+ hcon->dst_type = smp->remote_irk->addr_type;
+ queue_work(hdev->workqueue, &conn->id_addr_update_work);
+
+ /* When receiving an indentity resolving key for
+ * a remote device that does not use a resolvable
+ * private address, just remove the key so that
+ * it is possible to use the controller white
+ * list for scanning.
+ *
+ * Userspace will have been told to not store
+ * this key at this point. So it is safe to
+ * just remove it.
+ */
+ if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) {
+ list_del(&smp->remote_irk->list);
+ kfree(smp->remote_irk);
+ smp->remote_irk = NULL;
+ }
}
- smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(smp->tfm_aes)) {
- BT_ERR("Unable to create ECB crypto context");
- kfree(smp);
- clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
- return NULL;
+ /* The LTKs and CSRKs should be persistent only if both sides
+ * had the bonding bit set in their authentication requests.
+ */
+ persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
+
+ if (smp->csrk) {
+ smp->csrk->bdaddr_type = hcon->dst_type;
+ bacpy(&smp->csrk->bdaddr, &hcon->dst);
+ mgmt_new_csrk(hdev, smp->csrk, persistent);
}
- smp->conn = conn;
- conn->smp_chan = smp;
+ if (smp->slave_csrk) {
+ smp->slave_csrk->bdaddr_type = hcon->dst_type;
+ bacpy(&smp->slave_csrk->bdaddr, &hcon->dst);
+ mgmt_new_csrk(hdev, smp->slave_csrk, persistent);
+ }
- hci_conn_hold(conn->hcon);
+ if (smp->ltk) {
+ smp->ltk->bdaddr_type = hcon->dst_type;
+ bacpy(&smp->ltk->bdaddr, &hcon->dst);
+ mgmt_new_ltk(hdev, smp->ltk, persistent);
+ }
- return smp;
+ if (smp->slave_ltk) {
+ smp->slave_ltk->bdaddr_type = hcon->dst_type;
+ bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
+ mgmt_new_ltk(hdev, smp->slave_ltk, persistent);
+ }
}
-void smp_chan_destroy(struct l2cap_conn *conn)
+static void smp_allow_key_dist(struct smp_chan *smp)
{
- struct smp_chan *smp = conn->smp_chan;
- bool complete;
+ /* Allow the first expected phase 3 PDU. The rest of the PDUs
+ * will be allowed in each PDU handler to ensure we receive
+ * them in the correct order.
+ */
+ if (smp->remote_key_dist & SMP_DIST_ENC_KEY)
+ SMP_ALLOW_CMD(smp, SMP_CMD_ENCRYPT_INFO);
+ else if (smp->remote_key_dist & SMP_DIST_ID_KEY)
+ SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO);
+ else if (smp->remote_key_dist & SMP_DIST_SIGN)
+ SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
+}
- BUG_ON(!smp);
+static void smp_distribute_keys(struct smp_chan *smp)
+{
+ struct smp_cmd_pairing *req, *rsp;
+ struct l2cap_conn *conn = smp->conn;
+ struct hci_conn *hcon = conn->hcon;
+ struct hci_dev *hdev = hcon->hdev;
+ __u8 *keydist;
- complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
- mgmt_smp_complete(conn->hcon, complete);
+ BT_DBG("conn %p", conn);
- kfree(smp->csrk);
- kfree(smp->slave_csrk);
+ rsp = (void *) &smp->prsp[1];
- crypto_free_blkcipher(smp->tfm_aes);
+ /* The responder sends its keys first */
+ if (hcon->out && (smp->remote_key_dist & KEY_DIST_MASK)) {
+ smp_allow_key_dist(smp);
+ return;
+ }
- /* If pairing failed clean up any keys we might have */
- if (!complete) {
- if (smp->ltk) {
- list_del(&smp->ltk->list);
- kfree(smp->ltk);
- }
+ req = (void *) &smp->preq[1];
- if (smp->slave_ltk) {
- list_del(&smp->slave_ltk->list);
- kfree(smp->slave_ltk);
- }
+ if (hcon->out) {
+ keydist = &rsp->init_key_dist;
+ *keydist &= req->init_key_dist;
+ } else {
+ keydist = &rsp->resp_key_dist;
+ *keydist &= req->resp_key_dist;
+ }
- if (smp->remote_irk) {
- list_del(&smp->remote_irk->list);
- kfree(smp->remote_irk);
+ BT_DBG("keydist 0x%x", *keydist);
+
+ if (*keydist & SMP_DIST_ENC_KEY) {
+ struct smp_cmd_encrypt_info enc;
+ struct smp_cmd_master_ident ident;
+ struct smp_ltk *ltk;
+ u8 authenticated;
+ __le16 ediv;
+ __le64 rand;
+
+ get_random_bytes(enc.ltk, sizeof(enc.ltk));
+ get_random_bytes(&ediv, sizeof(ediv));
+ get_random_bytes(&rand, sizeof(rand));
+
+ smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
+
+ authenticated = hcon->sec_level == BT_SECURITY_HIGH;
+ ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
+ SMP_LTK_SLAVE, authenticated, enc.ltk,
+ smp->enc_key_size, ediv, rand);
+ smp->slave_ltk = ltk;
+
+ ident.ediv = ediv;
+ ident.rand = rand;
+
+ smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
+
+ *keydist &= ~SMP_DIST_ENC_KEY;
+ }
+
+ if (*keydist & SMP_DIST_ID_KEY) {
+ struct smp_cmd_ident_addr_info addrinfo;
+ struct smp_cmd_ident_info idinfo;
+
+ memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
+
+ smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
+
+ /* The hci_conn contains the local identity address
+ * after the connection has been established.
+ *
+ * This is true even when the connection has been
+ * established using a resolvable random address.
+ */
+ bacpy(&addrinfo.bdaddr, &hcon->src);
+ addrinfo.addr_type = hcon->src_type;
+
+ smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
+ &addrinfo);
+
+ *keydist &= ~SMP_DIST_ID_KEY;
+ }
+
+ if (*keydist & SMP_DIST_SIGN) {
+ struct smp_cmd_sign_info sign;
+ struct smp_csrk *csrk;
+
+ /* Generate a new random key */
+ get_random_bytes(sign.csrk, sizeof(sign.csrk));
+
+ csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
+ if (csrk) {
+ csrk->master = 0x00;
+ memcpy(csrk->val, sign.csrk, sizeof(csrk->val));
}
+ smp->slave_csrk = csrk;
+
+ smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
+
+ *keydist &= ~SMP_DIST_SIGN;
}
- kfree(smp);
- conn->smp_chan = NULL;
- hci_conn_drop(conn->hcon);
+ /* If there are still keys to be received wait for them */
+ if (smp->remote_key_dist & KEY_DIST_MASK) {
+ smp_allow_key_dist(smp);
+ return;
+ }
+
+ set_bit(SMP_FLAG_COMPLETE, &smp->flags);
+ smp_notify_keys(conn);
+
+ smp_chan_destroy(conn);
+}
+
+static void smp_timeout(struct work_struct *work)
+{
+ struct smp_chan *smp = container_of(work, struct smp_chan,
+ security_timer.work);
+ struct l2cap_conn *conn = smp->conn;
+
+ BT_DBG("conn %p", conn);
+
+ hci_disconnect(conn->hcon, HCI_ERROR_REMOTE_USER_TERM);
+}
+
+static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
+{
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp;
+
+ smp = kzalloc(sizeof(*smp), GFP_ATOMIC);
+ if (!smp)
+ return NULL;
+
+ smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(smp->tfm_aes)) {
+ BT_ERR("Unable to create ECB crypto context");
+ kfree(smp);
+ return NULL;
+ }
+
+ smp->conn = conn;
+ chan->data = smp;
+
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_FAIL);
+
+ INIT_DELAYED_WORK(&smp->security_timer, smp_timeout);
+
+ hci_conn_hold(conn->hcon);
+
+ return smp;
}
int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
{
struct l2cap_conn *conn = hcon->l2cap_data;
+ struct l2cap_chan *chan;
struct smp_chan *smp;
u32 value;
+ int err;
BT_DBG("");
- if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
+ if (!conn)
+ return -ENOTCONN;
+
+ chan = conn->smp;
+ if (!chan)
return -ENOTCONN;
- smp = conn->smp_chan;
+ l2cap_chan_lock(chan);
+ if (!chan->data) {
+ err = -ENOTCONN;
+ goto unlock;
+ }
+
+ smp = chan->data;
switch (mgmt_op) {
case MGMT_OP_USER_PASSKEY_REPLY:
@@ -664,12 +902,16 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
case MGMT_OP_USER_PASSKEY_NEG_REPLY:
case MGMT_OP_USER_CONFIRM_NEG_REPLY:
smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
- return 0;
+ err = 0;
+ goto unlock;
default:
smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
- return -EOPNOTSUPP;
+ err = -EOPNOTSUPP;
+ goto unlock;
}
+ err = 0;
+
/* If it is our turn to send Pairing Confirm, do so now */
if (test_bit(SMP_FLAG_CFM_PENDING, &smp->flags)) {
u8 rsp = smp_confirm(smp);
@@ -677,12 +919,15 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
smp_failure(conn, rsp);
}
- return 0;
+unlock:
+ l2cap_chan_unlock(chan);
+ return err;
}
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
+ struct l2cap_chan *chan = conn->smp;
struct hci_dev *hdev = conn->hcon->hdev;
struct smp_chan *smp;
u8 key_size, auth, sec_level;
@@ -696,10 +941,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
if (conn->hcon->role != HCI_ROLE_SLAVE)
return SMP_CMD_NOTSUPP;
- if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
+ if (!chan->data)
smp = smp_chan_create(conn);
else
- smp = conn->smp_chan;
+ smp = chan->data;
if (!smp)
return SMP_UNSPECIFIED;
@@ -708,6 +953,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
(req->auth_req & SMP_AUTH_BONDING))
return SMP_PAIRING_NOTSUPP;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_REQ);
+
smp->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&smp->preq[1], req, sizeof(*req));
skb_pull(skb, sizeof(*req));
@@ -741,6 +988,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
/* Request setup of TK */
ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
@@ -753,7 +1001,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
u8 key_size, auth = SMP_AUTH_NONE;
int ret;
@@ -765,6 +1014,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
if (conn->hcon->role != HCI_ROLE_MASTER)
return SMP_CMD_NOTSUPP;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
+
skb_pull(skb, sizeof(*rsp));
req = (void *) &smp->preq[1];
@@ -814,20 +1065,27 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
{
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
if (skb->len < sizeof(smp->pcnf))
return SMP_INVALID_PARAMS;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+
memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
skb_pull(skb, sizeof(smp->pcnf));
- if (conn->hcon->out)
+ if (conn->hcon->out) {
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
smp->prnd);
- else if (test_bit(SMP_FLAG_TK_VALID, &smp->flags))
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+ return 0;
+ }
+
+ if (test_bit(SMP_FLAG_TK_VALID, &smp->flags))
return smp_confirm(smp);
else
set_bit(SMP_FLAG_CFM_PENDING, &smp->flags);
@@ -837,13 +1095,16 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
{
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
BT_DBG("conn %p", conn);
if (skb->len < sizeof(smp->rrnd))
return SMP_INVALID_PARAMS;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+
memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd));
skb_pull(skb, sizeof(smp->rrnd));
@@ -923,9 +1184,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
return 0;
- if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
- return 0;
-
smp = smp_chan_create(conn);
if (!smp)
return SMP_UNSPECIFIED;
@@ -943,6 +1201,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
memcpy(&smp->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
return 0;
}
@@ -950,8 +1209,10 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
{
struct l2cap_conn *conn = hcon->l2cap_data;
+ struct l2cap_chan *chan;
struct smp_chan *smp;
__u8 authreq;
+ int ret;
BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
@@ -959,6 +1220,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
if (!conn)
return 1;
+ chan = conn->smp;
+
if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
return 1;
@@ -972,12 +1235,19 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
return 0;
- if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
- return 0;
+ l2cap_chan_lock(chan);
+
+ /* If SMP is already in progress ignore this request */
+ if (chan->data) {
+ ret = 0;
+ goto unlock;
+ }
smp = smp_chan_create(conn);
- if (!smp)
- return 1;
+ if (!smp) {
+ ret = 1;
+ goto unlock;
+ }
authreq = seclevel_to_authreq(sec_level);
@@ -996,30 +1266,35 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
memcpy(&smp->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
} else {
struct smp_cmd_security_req cp;
cp.auth_req = authreq;
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_REQ);
}
set_bit(SMP_FLAG_INITIATOR, &smp->flags);
+ ret = 0;
- return 0;
+unlock:
+ l2cap_chan_unlock(chan);
+ return ret;
}
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
BT_DBG("conn %p", conn);
if (skb->len < sizeof(*rp))
return SMP_INVALID_PARAMS;
- /* Ignore this PDU if it wasn't requested */
- if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
- return 0;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_ENCRYPT_INFO);
+ SMP_ALLOW_CMD(smp, SMP_CMD_MASTER_IDENT);
skb_pull(skb, sizeof(*rp));
@@ -1031,7 +1306,8 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_master_ident *rp = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
struct hci_dev *hdev = conn->hcon->hdev;
struct hci_conn *hcon = conn->hcon;
struct smp_ltk *ltk;
@@ -1042,13 +1318,13 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
if (skb->len < sizeof(*rp))
return SMP_INVALID_PARAMS;
- /* Ignore this PDU if it wasn't requested */
- if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
- return 0;
-
/* Mark the information as received */
smp->remote_key_dist &= ~SMP_DIST_ENC_KEY;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_MASTER_IDENT);
+ if (smp->remote_key_dist & SMP_DIST_ID_KEY)
+ SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO);
+
skb_pull(skb, sizeof(*rp));
hci_dev_lock(hdev);
@@ -1057,8 +1333,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
authenticated, smp->tk, smp->enc_key_size,
rp->ediv, rp->rand);
smp->ltk = ltk;
- if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
- smp_distribute_keys(conn);
+ if (!(smp->remote_key_dist & KEY_DIST_MASK))
+ smp_distribute_keys(smp);
hci_dev_unlock(hdev);
return 0;
@@ -1067,16 +1343,16 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_ident_info *info = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
BT_DBG("");
if (skb->len < sizeof(*info))
return SMP_INVALID_PARAMS;
- /* Ignore this PDU if it wasn't requested */
- if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
- return 0;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_IDENT_INFO);
+ SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO);
skb_pull(skb, sizeof(*info));
@@ -1089,7 +1365,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
struct sk_buff *skb)
{
struct smp_cmd_ident_addr_info *info = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
struct hci_conn *hcon = conn->hcon;
bdaddr_t rpa;
@@ -1098,13 +1375,13 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
if (skb->len < sizeof(*info))
return SMP_INVALID_PARAMS;
- /* Ignore this PDU if it wasn't requested */
- if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
- return 0;
-
/* Mark the information as received */
smp->remote_key_dist &= ~SMP_DIST_ID_KEY;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO);
+ if (smp->remote_key_dist & SMP_DIST_SIGN)
+ SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
+
skb_pull(skb, sizeof(*info));
hci_dev_lock(hcon->hdev);
@@ -1133,7 +1410,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
smp->id_addr_type, smp->irk, &rpa);
distribute:
- smp_distribute_keys(conn);
+ if (!(smp->remote_key_dist & KEY_DIST_MASK))
+ smp_distribute_keys(smp);
hci_dev_unlock(hcon->hdev);
@@ -1143,7 +1421,8 @@ distribute:
static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_sign_info *rp = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
+ struct l2cap_chan *chan = conn->smp;
+ struct smp_chan *smp = chan->data;
struct hci_dev *hdev = conn->hcon->hdev;
struct smp_csrk *csrk;
@@ -1152,13 +1431,11 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
if (skb->len < sizeof(*rp))
return SMP_INVALID_PARAMS;
- /* Ignore this PDU if it wasn't requested */
- if (!(smp->remote_key_dist & SMP_DIST_SIGN))
- return 0;
-
/* Mark the information as received */
smp->remote_key_dist &= ~SMP_DIST_SIGN;
+ SMP_DISALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
+
skb_pull(skb, sizeof(*rp));
hci_dev_lock(hdev);
@@ -1168,16 +1445,17 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
memcpy(csrk->val, rp->csrk, sizeof(csrk->val));
}
smp->csrk = csrk;
- if (!(smp->remote_key_dist & SMP_DIST_SIGN))
- smp_distribute_keys(conn);
+ smp_distribute_keys(smp);
hci_dev_unlock(hdev);
return 0;
}
-int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
+static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
{
+ struct l2cap_conn *conn = chan->conn;
struct hci_conn *hcon = conn->hcon;
+ struct smp_chan *smp;
__u8 code, reason;
int err = 0;
@@ -1186,13 +1464,10 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
return 0;
}
- if (skb->len < 1) {
- kfree_skb(skb);
+ if (skb->len < 1)
return -EILSEQ;
- }
if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) {
- err = -EOPNOTSUPP;
reason = SMP_PAIRING_NOTSUPP;
goto done;
}
@@ -1200,18 +1475,19 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
code = skb->data[0];
skb_pull(skb, sizeof(code));
- /*
- * The SMP context must be initialized for all other PDUs except
- * pairing and security requests. If we get any other PDU when
- * not initialized simply disconnect (done if this function
- * returns an error).
+ smp = chan->data;
+
+ if (code > SMP_CMD_MAX)
+ goto drop;
+
+ if (smp && !test_bit(code, &smp->allow_cmd))
+ goto drop;
+
+ /* If we don't have a context the only allowed commands are
+ * pairing request and security request.
*/
- if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ &&
- !conn->smp_chan) {
- BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code);
- kfree_skb(skb);
- return -EOPNOTSUPP;
- }
+ if (!smp && code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ)
+ goto drop;
switch (code) {
case SMP_CMD_PAIRING_REQ:
@@ -1220,7 +1496,6 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
case SMP_CMD_PAIRING_FAIL:
smp_failure(conn, 0);
- reason = 0;
err = -EPERM;
break;
@@ -1262,197 +1537,217 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
default:
BT_DBG("Unknown command code 0x%2.2x", code);
-
reason = SMP_CMD_NOTSUPP;
- err = -EOPNOTSUPP;
goto done;
}
done:
- if (reason)
- smp_failure(conn, reason);
+ if (!err) {
+ if (reason)
+ smp_failure(conn, reason);
+ kfree_skb(skb);
+ }
- kfree_skb(skb);
return err;
+
+drop:
+ BT_ERR("%s unexpected SMP command 0x%02x from %pMR", hcon->hdev->name,
+ code, &hcon->dst);
+ kfree_skb(skb);
+ return 0;
}
-static void smp_notify_keys(struct l2cap_conn *conn)
+static void smp_teardown_cb(struct l2cap_chan *chan, int err)
{
- struct smp_chan *smp = conn->smp_chan;
- struct hci_conn *hcon = conn->hcon;
- struct hci_dev *hdev = hcon->hdev;
- struct smp_cmd_pairing *req = (void *) &smp->preq[1];
- struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
- bool persistent;
+ struct l2cap_conn *conn = chan->conn;
- if (smp->remote_irk) {
- mgmt_new_irk(hdev, smp->remote_irk);
- /* Now that user space can be considered to know the
- * identity address track the connection based on it
- * from now on.
- */
- bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
- hcon->dst_type = smp->remote_irk->addr_type;
- l2cap_conn_update_id_addr(hcon);
+ BT_DBG("chan %p", chan);
- /* When receiving an indentity resolving key for
- * a remote device that does not use a resolvable
- * private address, just remove the key so that
- * it is possible to use the controller white
- * list for scanning.
- *
- * Userspace will have been told to not store
- * this key at this point. So it is safe to
- * just remove it.
- */
- if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) {
- list_del(&smp->remote_irk->list);
- kfree(smp->remote_irk);
- smp->remote_irk = NULL;
- }
- }
+ if (chan->data)
+ smp_chan_destroy(conn);
- /* The LTKs and CSRKs should be persistent only if both sides
- * had the bonding bit set in their authentication requests.
- */
- persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
+ conn->smp = NULL;
+ l2cap_chan_put(chan);
+}
- if (smp->csrk) {
- smp->csrk->bdaddr_type = hcon->dst_type;
- bacpy(&smp->csrk->bdaddr, &hcon->dst);
- mgmt_new_csrk(hdev, smp->csrk, persistent);
- }
+static void smp_resume_cb(struct l2cap_chan *chan)
+{
+ struct smp_chan *smp = chan->data;
+ struct l2cap_conn *conn = chan->conn;
+ struct hci_conn *hcon = conn->hcon;
- if (smp->slave_csrk) {
- smp->slave_csrk->bdaddr_type = hcon->dst_type;
- bacpy(&smp->slave_csrk->bdaddr, &hcon->dst);
- mgmt_new_csrk(hdev, smp->slave_csrk, persistent);
- }
+ BT_DBG("chan %p", chan);
- if (smp->ltk) {
- smp->ltk->bdaddr_type = hcon->dst_type;
- bacpy(&smp->ltk->bdaddr, &hcon->dst);
- mgmt_new_ltk(hdev, smp->ltk, persistent);
- }
+ if (!smp)
+ return;
- if (smp->slave_ltk) {
- smp->slave_ltk->bdaddr_type = hcon->dst_type;
- bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
- mgmt_new_ltk(hdev, smp->slave_ltk, persistent);
- }
+ if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
+ return;
+
+ cancel_delayed_work(&smp->security_timer);
+
+ smp_distribute_keys(smp);
}
-int smp_distribute_keys(struct l2cap_conn *conn)
+static void smp_ready_cb(struct l2cap_chan *chan)
{
- struct smp_cmd_pairing *req, *rsp;
- struct smp_chan *smp = conn->smp_chan;
- struct hci_conn *hcon = conn->hcon;
- struct hci_dev *hdev = hcon->hdev;
- __u8 *keydist;
+ struct l2cap_conn *conn = chan->conn;
- BT_DBG("conn %p", conn);
+ BT_DBG("chan %p", chan);
- if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
- return 0;
+ conn->smp = chan;
+ l2cap_chan_hold(chan);
+}
- rsp = (void *) &smp->prsp[1];
+static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+ int err;
- /* The responder sends its keys first */
- if (hcon->out && (smp->remote_key_dist & 0x07))
- return 0;
+ BT_DBG("chan %p", chan);
- req = (void *) &smp->preq[1];
+ err = smp_sig_channel(chan, skb);
+ if (err) {
+ struct smp_chan *smp = chan->data;
- if (hcon->out) {
- keydist = &rsp->init_key_dist;
- *keydist &= req->init_key_dist;
- } else {
- keydist = &rsp->resp_key_dist;
- *keydist &= req->resp_key_dist;
+ if (smp)
+ cancel_delayed_work_sync(&smp->security_timer);
+
+ hci_disconnect(chan->conn->hcon, HCI_ERROR_AUTH_FAILURE);
}
- BT_DBG("keydist 0x%x", *keydist);
+ return err;
+}
- if (*keydist & SMP_DIST_ENC_KEY) {
- struct smp_cmd_encrypt_info enc;
- struct smp_cmd_master_ident ident;
- struct smp_ltk *ltk;
- u8 authenticated;
- __le16 ediv;
- __le64 rand;
+static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan,
+ unsigned long hdr_len,
+ unsigned long len, int nb)
+{
+ struct sk_buff *skb;
- get_random_bytes(enc.ltk, sizeof(enc.ltk));
- get_random_bytes(&ediv, sizeof(ediv));
- get_random_bytes(&rand, sizeof(rand));
+ skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
- smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
+ skb->priority = HCI_PRIO_MAX;
+ bt_cb(skb)->chan = chan;
- authenticated = hcon->sec_level == BT_SECURITY_HIGH;
- ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
- SMP_LTK_SLAVE, authenticated, enc.ltk,
- smp->enc_key_size, ediv, rand);
- smp->slave_ltk = ltk;
+ return skb;
+}
- ident.ediv = ediv;
- ident.rand = rand;
+static const struct l2cap_ops smp_chan_ops = {
+ .name = "Security Manager",
+ .ready = smp_ready_cb,
+ .recv = smp_recv_cb,
+ .alloc_skb = smp_alloc_skb_cb,
+ .teardown = smp_teardown_cb,
+ .resume = smp_resume_cb,
+
+ .new_connection = l2cap_chan_no_new_connection,
+ .state_change = l2cap_chan_no_state_change,
+ .close = l2cap_chan_no_close,
+ .defer = l2cap_chan_no_defer,
+ .suspend = l2cap_chan_no_suspend,
+ .set_shutdown = l2cap_chan_no_set_shutdown,
+ .get_sndtimeo = l2cap_chan_no_get_sndtimeo,
+ .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
+};
- smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
+static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
+{
+ struct l2cap_chan *chan;
- *keydist &= ~SMP_DIST_ENC_KEY;
- }
+ BT_DBG("pchan %p", pchan);
- if (*keydist & SMP_DIST_ID_KEY) {
- struct smp_cmd_ident_addr_info addrinfo;
- struct smp_cmd_ident_info idinfo;
+ chan = l2cap_chan_create();
+ if (!chan)
+ return NULL;
- memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
+ chan->chan_type = pchan->chan_type;
+ chan->ops = &smp_chan_ops;
+ chan->scid = pchan->scid;
+ chan->dcid = chan->scid;
+ chan->imtu = pchan->imtu;
+ chan->omtu = pchan->omtu;
+ chan->mode = pchan->mode;
- smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
+ BT_DBG("created chan %p", chan);
- /* The hci_conn contains the local identity address
- * after the connection has been established.
- *
- * This is true even when the connection has been
- * established using a resolvable random address.
- */
- bacpy(&addrinfo.bdaddr, &hcon->src);
- addrinfo.addr_type = hcon->src_type;
+ return chan;
+}
- smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
- &addrinfo);
+static const struct l2cap_ops smp_root_chan_ops = {
+ .name = "Security Manager Root",
+ .new_connection = smp_new_conn_cb,
+
+ /* None of these are implemented for the root channel */
+ .close = l2cap_chan_no_close,
+ .alloc_skb = l2cap_chan_no_alloc_skb,
+ .recv = l2cap_chan_no_recv,
+ .state_change = l2cap_chan_no_state_change,
+ .teardown = l2cap_chan_no_teardown,
+ .ready = l2cap_chan_no_ready,
+ .defer = l2cap_chan_no_defer,
+ .suspend = l2cap_chan_no_suspend,
+ .resume = l2cap_chan_no_resume,
+ .set_shutdown = l2cap_chan_no_set_shutdown,
+ .get_sndtimeo = l2cap_chan_no_get_sndtimeo,
+ .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
+};
- *keydist &= ~SMP_DIST_ID_KEY;
- }
+int smp_register(struct hci_dev *hdev)
+{
+ struct l2cap_chan *chan;
+ struct crypto_blkcipher *tfm_aes;
- if (*keydist & SMP_DIST_SIGN) {
- struct smp_cmd_sign_info sign;
- struct smp_csrk *csrk;
+ BT_DBG("%s", hdev->name);
- /* Generate a new random key */
- get_random_bytes(sign.csrk, sizeof(sign.csrk));
+ tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm_aes)) {
+ int err = PTR_ERR(tfm_aes);
+ BT_ERR("Unable to create crypto context");
+ return err;
+ }
- csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
- if (csrk) {
- csrk->master = 0x00;
- memcpy(csrk->val, sign.csrk, sizeof(csrk->val));
- }
- smp->slave_csrk = csrk;
+ chan = l2cap_chan_create();
+ if (!chan) {
+ crypto_free_blkcipher(tfm_aes);
+ return -ENOMEM;
+ }
- smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
+ chan->data = tfm_aes;
- *keydist &= ~SMP_DIST_SIGN;
- }
+ l2cap_add_scid(chan, L2CAP_CID_SMP);
- /* If there are still keys to be received wait for them */
- if ((smp->remote_key_dist & 0x07))
- return 0;
+ l2cap_chan_set_defaults(chan);
- clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
- cancel_delayed_work_sync(&conn->security_timer);
- set_bit(SMP_FLAG_COMPLETE, &smp->flags);
- smp_notify_keys(conn);
+ bacpy(&chan->src, &hdev->bdaddr);
+ chan->src_type = BDADDR_LE_PUBLIC;
+ chan->state = BT_LISTEN;
+ chan->mode = L2CAP_MODE_BASIC;
+ chan->imtu = L2CAP_DEFAULT_MTU;
+ chan->ops = &smp_root_chan_ops;
- smp_chan_destroy(conn);
+ hdev->smp_data = chan;
return 0;
}
+
+void smp_unregister(struct hci_dev *hdev)
+{
+ struct l2cap_chan *chan = hdev->smp_data;
+ struct crypto_blkcipher *tfm_aes;
+
+ if (!chan)
+ return;
+
+ BT_DBG("%s chan %p", hdev->name, chan);
+
+ tfm_aes = chan->data;
+ if (tfm_aes) {
+ chan->data = NULL;
+ crypto_free_blkcipher(tfm_aes);
+ }
+
+ hdev->smp_data = NULL;
+ l2cap_chan_put(chan);
+}
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
index 796f4f4..5240537 100644
--- a/net/bluetooth/smp.h
+++ b/net/bluetooth/smp.h
@@ -102,6 +102,8 @@ struct smp_cmd_security_req {
__u8 auth_req;
} __packed;
+#define SMP_CMD_MAX 0x0b
+
#define SMP_PASSKEY_ENTRY_FAILED 0x01
#define SMP_OOB_NOT_AVAIL 0x02
#define SMP_AUTH_REQUIREMENTS 0x03
@@ -126,14 +128,12 @@ enum {
/* SMP Commands */
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
-int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
-int smp_distribute_keys(struct l2cap_conn *conn);
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
-void smp_chan_destroy(struct l2cap_conn *conn);
+bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr);
+int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa);
-bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
- bdaddr_t *bdaddr);
-int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa);
+int smp_register(struct hci_dev *hdev);
+void smp_unregister(struct hci_dev *hdev);
#endif /* __SMP_H */
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
index 016b77e..5e788cd 100644
--- a/net/ieee802154/6lowpan_rtnl.c
+++ b/net/ieee802154/6lowpan_rtnl.c
@@ -77,14 +77,6 @@ lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
return netdev_priv(dev);
}
-static inline void lowpan_address_flip(u8 *src, u8 *dest)
-{
- int i;
-
- for (i = 0; i < IEEE802154_ADDR_LEN; i++)
- (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
-}
-
static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *_daddr,
const void *_saddr, unsigned int len)
@@ -246,7 +238,7 @@ lowpan_alloc_frag(struct sk_buff *skb, int size,
return ERR_PTR(-rc);
}
} else {
- frag = ERR_PTR(ENOMEM);
+ frag = ERR_PTR(-ENOMEM);
}
return frag;
@@ -437,7 +429,7 @@ static void lowpan_setup(struct net_device *dev)
/* Frame Control + Sequence Number + Address fields + Security Header */
dev->hard_header_len = 2 + 1 + 20 + 14;
dev->needed_tailroom = 2; /* FCS */
- dev->mtu = 1281;
+ dev->mtu = IPV6_MIN_MTU;
dev->tx_queue_len = 0;
dev->flags = IFF_BROADCAST | IFF_MULTICAST;
dev->watchdog_timeo = 0;
diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c
index ffec6ce..32755cb 100644
--- a/net/ieee802154/reassembly.c
+++ b/net/ieee802154/reassembly.c
@@ -355,8 +355,6 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
struct net *net = dev_net(skb->dev);
struct lowpan_frag_info *frag_info = lowpan_cb(skb);
struct ieee802154_addr source, dest;
- struct netns_ieee802154_lowpan *ieee802154_lowpan =
- net_ieee802154_lowpan(net);
int err;
source = mac_cb(skb)->source;
@@ -366,8 +364,10 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
if (err < 0)
goto err;
- if (frag_info->d_size > ieee802154_lowpan->max_dsize)
+ if (frag_info->d_size > IPV6_MIN_MTU) {
+ net_warn_ratelimited("lowpan_frag_rcv: datagram size exceeds MTU\n");
goto err;
+ }
fq = fq_find(net, frag_info, &source, &dest);
if (fq != NULL) {
@@ -415,13 +415,6 @@ static struct ctl_table lowpan_frags_ns_ctl_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
},
- {
- .procname = "6lowpanfrag_max_datagram_size",
- .data = &init_net.ieee802154_lowpan.max_dsize,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
{ }
};
@@ -458,7 +451,6 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
table[1].data = &ieee802154_lowpan->frags.low_thresh;
table[1].extra2 = &ieee802154_lowpan->frags.high_thresh;
table[2].data = &ieee802154_lowpan->frags.timeout;
- table[3].data = &ieee802154_lowpan->max_dsize;
/* Don't export sysctls to unprivileged users */
if (net->user_ns != &init_user_ns)
@@ -533,7 +525,6 @@ static int __net_init lowpan_frags_init_net(struct net *net)
ieee802154_lowpan->frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
ieee802154_lowpan->frags.low_thresh = IPV6_FRAG_LOW_THRESH;
ieee802154_lowpan->frags.timeout = IPV6_FRAG_TIMEOUT;
- ieee802154_lowpan->max_dsize = 0xFFFF;
inet_frags_init_net(&ieee802154_lowpan->frags);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 927b4ea..4d8989b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1011,15 +1011,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
}
- if (mask & BIT(NL80211_STA_FLAG_WME)) {
- if (set & BIT(NL80211_STA_FLAG_WME)) {
- set_sta_flag(sta, WLAN_STA_WME);
- sta->sta.wme = true;
- } else {
- clear_sta_flag(sta, WLAN_STA_WME);
- sta->sta.wme = false;
- }
- }
+ if (mask & BIT(NL80211_STA_FLAG_WME))
+ sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
if (mask & BIT(NL80211_STA_FLAG_MFP)) {
if (set & BIT(NL80211_STA_FLAG_MFP))
@@ -3352,7 +3345,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
band = chanctx_conf->def.chan->band;
sta = sta_info_get_bss(sdata, peer);
if (sta) {
- qos = test_sta_flag(sta, WLAN_STA_WME);
+ qos = sta->sta.wme;
} else {
rcu_read_unlock();
return -ENOLINK;
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 6d537f0..4c74e8d 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -541,18 +541,20 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
continue;
if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
continue;
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ continue;
if (!compat)
compat = &sdata->vif.bss_conf.chandef;
compat = cfg80211_chandef_compatible(
&sdata->vif.bss_conf.chandef, compat);
- if (!compat)
+ if (WARN_ON_ONCE(!compat))
break;
}
rcu_read_unlock();
- if (WARN_ON_ONCE(!compat))
+ if (!compat)
return;
ieee80211_change_chanctx(local, ctx, compat);
@@ -637,41 +639,6 @@ out:
return ret;
}
-static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_chanctx_conf *conf;
- struct ieee80211_chanctx *ctx;
- bool use_reserved_switch = false;
-
- lockdep_assert_held(&local->chanctx_mtx);
-
- conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
- lockdep_is_held(&local->chanctx_mtx));
- if (!conf)
- return;
-
- ctx = container_of(conf, struct ieee80211_chanctx, conf);
-
- if (sdata->reserved_chanctx) {
- if (sdata->reserved_chanctx->replace_state ==
- IEEE80211_CHANCTX_REPLACES_OTHER &&
- ieee80211_chanctx_num_reserved(local,
- sdata->reserved_chanctx) > 1)
- use_reserved_switch = true;
-
- ieee80211_vif_unreserve_chanctx(sdata);
- }
-
- ieee80211_assign_vif_chanctx(sdata, NULL);
- if (ieee80211_chanctx_refcount(local, ctx) == 0)
- ieee80211_free_chanctx(local, ctx);
-
- /* Unreserving may ready an in-place reservation. */
- if (use_reserved_switch)
- ieee80211_vif_use_reserved_switch(local);
-}
-
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx)
{
@@ -762,63 +729,6 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
}
-int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
- const struct cfg80211_chan_def *chandef,
- enum ieee80211_chanctx_mode mode)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_chanctx *ctx;
- u8 radar_detect_width = 0;
- int ret;
-
- lockdep_assert_held(&local->mtx);
-
- WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
-
- mutex_lock(&local->chanctx_mtx);
-
- ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
- chandef,
- sdata->wdev.iftype);
- if (ret < 0)
- goto out;
- if (ret > 0)
- radar_detect_width = BIT(chandef->width);
-
- sdata->radar_required = ret;
-
- ret = ieee80211_check_combinations(sdata, chandef, mode,
- radar_detect_width);
- if (ret < 0)
- goto out;
-
- __ieee80211_vif_release_channel(sdata);
-
- ctx = ieee80211_find_chanctx(local, chandef, mode);
- if (!ctx)
- ctx = ieee80211_new_chanctx(local, chandef, mode);
- if (IS_ERR(ctx)) {
- ret = PTR_ERR(ctx);
- goto out;
- }
-
- sdata->vif.bss_conf.chandef = *chandef;
-
- ret = ieee80211_assign_vif_chanctx(sdata, ctx);
- if (ret) {
- /* if assign fails refcount stays the same */
- if (ieee80211_chanctx_refcount(local, ctx) == 0)
- ieee80211_free_chanctx(local, ctx);
- goto out;
- }
-
- ieee80211_recalc_smps_chanctx(local, ctx);
- ieee80211_recalc_radar_chanctx(local, ctx);
- out:
- mutex_unlock(&local->chanctx_mtx);
- return ret;
-}
-
static void
__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
bool clear)
@@ -1267,8 +1177,7 @@ err:
return err;
}
-int
-ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
+static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata, *sdata_tmp;
struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
@@ -1444,7 +1353,7 @@ ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
list_del(&sdata->reserved_chanctx_list);
list_move(&sdata->assigned_chanctx_list,
- &new_ctx->assigned_vifs);
+ &ctx->assigned_vifs);
sdata->reserved_chanctx = NULL;
ieee80211_vif_chanctx_reservation_complete(sdata);
@@ -1520,6 +1429,98 @@ err:
return err;
}
+static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx_conf *conf;
+ struct ieee80211_chanctx *ctx;
+ bool use_reserved_switch = false;
+
+ lockdep_assert_held(&local->chanctx_mtx);
+
+ conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ if (!conf)
+ return;
+
+ ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+ if (sdata->reserved_chanctx) {
+ if (sdata->reserved_chanctx->replace_state ==
+ IEEE80211_CHANCTX_REPLACES_OTHER &&
+ ieee80211_chanctx_num_reserved(local,
+ sdata->reserved_chanctx) > 1)
+ use_reserved_switch = true;
+
+ ieee80211_vif_unreserve_chanctx(sdata);
+ }
+
+ ieee80211_assign_vif_chanctx(sdata, NULL);
+ if (ieee80211_chanctx_refcount(local, ctx) == 0)
+ ieee80211_free_chanctx(local, ctx);
+
+ /* Unreserving may ready an in-place reservation. */
+ if (use_reserved_switch)
+ ieee80211_vif_use_reserved_switch(local);
+}
+
+int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_chan_def *chandef,
+ enum ieee80211_chanctx_mode mode)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx *ctx;
+ u8 radar_detect_width = 0;
+ int ret;
+
+ lockdep_assert_held(&local->mtx);
+
+ WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
+
+ mutex_lock(&local->chanctx_mtx);
+
+ ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
+ chandef,
+ sdata->wdev.iftype);
+ if (ret < 0)
+ goto out;
+ if (ret > 0)
+ radar_detect_width = BIT(chandef->width);
+
+ sdata->radar_required = ret;
+
+ ret = ieee80211_check_combinations(sdata, chandef, mode,
+ radar_detect_width);
+ if (ret < 0)
+ goto out;
+
+ __ieee80211_vif_release_channel(sdata);
+
+ ctx = ieee80211_find_chanctx(local, chandef, mode);
+ if (!ctx)
+ ctx = ieee80211_new_chanctx(local, chandef, mode);
+ if (IS_ERR(ctx)) {
+ ret = PTR_ERR(ctx);
+ goto out;
+ }
+
+ sdata->vif.bss_conf.chandef = *chandef;
+
+ ret = ieee80211_assign_vif_chanctx(sdata, ctx);
+ if (ret) {
+ /* if assign fails refcount stays the same */
+ if (ieee80211_chanctx_refcount(local, ctx) == 0)
+ ieee80211_free_chanctx(local, ctx);
+ goto out;
+ }
+
+ ieee80211_recalc_smps_chanctx(local, ctx);
+ ieee80211_recalc_radar_chanctx(local, ctx);
+ out:
+ mutex_unlock(&local->chanctx_mtx);
+ return ret;
+}
+
int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 3db96648..33eb4a4 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -77,7 +77,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
TEST(PS_DRIVER), TEST(AUTHORIZED),
TEST(SHORT_PREAMBLE),
- TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
+ sta->sta.wme ? "WME\n" : "",
+ TEST(WDS), TEST(CLEAR_PS_FILT),
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
@@ -167,7 +168,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n",
sta->ampdu_mlme.dialog_token_allocator + 1);
p += scnprintf(p, sizeof(buf) + buf - p,
- "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
+ "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 9713dc5..5f9654d 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1038,7 +1038,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
}
if (sta && elems->wmm_info)
- set_sta_flag(sta, WLAN_STA_WME);
+ sta->sta.wme = true;
if (sta && elems->ht_operation && elems->ht_cap_elem &&
sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ef7a089..ffb20e5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1869,7 +1869,6 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
int __must_check
ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata);
int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
-int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local);
int __must_check
ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 01eede7..f75e5f1 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1175,8 +1175,8 @@ static void ieee80211_iface_work(struct work_struct *work)
if (sta) {
u16 last_seq;
- last_seq = le16_to_cpu(
- sta->last_seq_ctrl[rx_agg->tid]);
+ last_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(
+ sta->last_seq_ctrl[rx_agg->tid]));
__ieee80211_start_rx_ba_session(sta,
0, 0,
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index d808cff..6429d0e 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -130,9 +130,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
if (!ret) {
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
- if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
- (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
- (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+ if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
sdata->crypto_tx_tailroom_needed_cnt--;
WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
@@ -180,9 +178,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
sta = key->sta;
sdata = key->sdata;
- if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
- (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
- (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+ if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
increment_tailroom_need_count(sdata);
ret = drv_set_key(key->local, DISABLE_KEY, sdata,
@@ -878,9 +874,7 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
- if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
- (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
- (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+ if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
increment_tailroom_need_count(key->sdata);
}
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index cf032a8..a6699dc 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -729,7 +729,7 @@ void mesh_plink_broken(struct sta_info *sta)
tbl = rcu_dereference(mesh_paths);
for_each_mesh_entry(tbl, node, i) {
mpath = node->mpath;
- if (rcu_dereference(mpath->next_hop) == sta &&
+ if (rcu_access_pointer(mpath->next_hop) == sta &&
mpath->flags & MESH_PATH_ACTIVE &&
!(mpath->flags & MESH_PATH_FIXED)) {
spin_lock_bh(&mpath->state_lock);
@@ -794,7 +794,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
tbl = resize_dereference_mesh_paths();
for_each_mesh_entry(tbl, node, i) {
mpath = node->mpath;
- if (rcu_dereference(mpath->next_hop) == sta) {
+ if (rcu_access_pointer(mpath->next_hop) == sta) {
spin_lock(&tbl->hashwlock[i]);
__mesh_path_del(tbl, node);
spin_unlock(&tbl->hashwlock[i]);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 63b8741..b488e18 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -431,14 +431,12 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
return NULL;
sta->plink_state = NL80211_PLINK_LISTEN;
+ sta->sta.wme = true;
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
- set_sta_flag(sta, WLAN_STA_WME);
- sta->sta.wme = true;
-
return sta;
}
@@ -959,7 +957,8 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
if (!matches_local)
event = CNF_RJCT;
if (!mesh_plink_free_count(sdata) ||
- (sta->llid != llid || sta->plid != plid))
+ sta->llid != llid ||
+ (sta->plid && sta->plid != plid))
event = CNF_IGNR;
else
event = CNF_ACPT;
@@ -1003,7 +1002,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
enum ieee80211_self_protected_actioncode ftype;
u32 changed = 0;
u8 ie_len = elems->peering_len;
- __le16 _plid, _llid;
u16 plid, llid = 0;
if (!elems->peering) {
@@ -1038,13 +1036,10 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
/* Note the lines below are correct, the llid in the frame is the plid
* from the point of view of this host.
*/
- memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16));
- plid = le16_to_cpu(_plid);
+ plid = get_unaligned_le16(PLINK_GET_LLID(elems->peering));
if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
- (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) {
- memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16));
- llid = le16_to_cpu(_llid);
- }
+ (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
+ llid = get_unaligned_le16(PLINK_GET_PLID(elems->peering));
/* WARNING: Only for sta pointer, is dropped & re-acquired */
rcu_read_lock();
@@ -1080,6 +1075,10 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
goto unlock_rcu;
}
+ /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */
+ if (!sta->plid && event == CNF_ACPT)
+ sta->plid = plid;
+
changed |= mesh_plink_fsm(sdata, sta, event);
unlock_rcu:
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 31a8afa..8a73de6 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -149,6 +149,7 @@ static u32
ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
+ const struct ieee80211_ht_cap *ht_cap,
const struct ieee80211_ht_operation *ht_oper,
const struct ieee80211_vht_operation *vht_oper,
struct cfg80211_chan_def *chandef, bool tracking)
@@ -162,13 +163,19 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
chandef->center_freq1 = channel->center_freq;
chandef->center_freq2 = 0;
- if (!ht_oper || !sband->ht_cap.ht_supported) {
+ if (!ht_cap || !ht_oper || !sband->ht_cap.ht_supported) {
ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
goto out;
}
chandef->width = NL80211_CHAN_WIDTH_20;
+ if (!(ht_cap->cap_info &
+ cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40))) {
+ ret = IEEE80211_STA_DISABLE_40MHZ | IEEE80211_STA_DISABLE_VHT;
+ goto out;
+ }
+
ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
channel->band);
/* check that channel matches the right operating channel */
@@ -328,6 +335,7 @@ out:
static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
+ const struct ieee80211_ht_cap *ht_cap,
const struct ieee80211_ht_operation *ht_oper,
const struct ieee80211_vht_operation *vht_oper,
const u8 *bssid, u32 *changed)
@@ -367,8 +375,9 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
sband = local->hw.wiphy->bands[chan->band];
/* calculate new channel (type) based on HT/VHT operation IEs */
- flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper,
- vht_oper, &chandef, true);
+ flags = ieee80211_determine_chantype(sdata, sband, chan,
+ ht_cap, ht_oper, vht_oper,
+ &chandef, true);
/*
* Downgrade the new channel if we associated with restricted
@@ -2677,8 +2686,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
set_sta_flag(sta, WLAN_STA_MFP);
- if (elems.wmm_param)
- set_sta_flag(sta, WLAN_STA_WME);
+ sta->sta.wme = elems.wmm_param;
err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
@@ -3174,7 +3182,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, bssid);
- if (ieee80211_config_bw(sdata, sta, elems.ht_operation,
+ if (ieee80211_config_bw(sdata, sta,
+ elems.ht_cap_elem, elems.ht_operation,
elems.vht_operation, bssid, &changed)) {
mutex_unlock(&local->sta_mtx);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
@@ -3808,6 +3817,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ const struct ieee80211_ht_cap *ht_cap = NULL;
const struct ieee80211_ht_operation *ht_oper = NULL;
const struct ieee80211_vht_operation *vht_oper = NULL;
struct ieee80211_supported_band *sband;
@@ -3824,14 +3834,17 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
sband->ht_cap.ht_supported) {
- const u8 *ht_oper_ie, *ht_cap;
+ const u8 *ht_oper_ie, *ht_cap_ie;
ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
ht_oper = (void *)(ht_oper_ie + 2);
- ht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
- if (!ht_cap || ht_cap[1] < sizeof(struct ieee80211_ht_cap)) {
+ ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
+ if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap))
+ ht_cap = (void *)(ht_cap_ie + 2);
+
+ if (!ht_cap) {
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
ht_oper = NULL;
}
@@ -3862,7 +3875,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
cbss->channel,
- ht_oper, vht_oper,
+ ht_cap, ht_oper, vht_oper,
&chandef, false);
sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
@@ -4376,8 +4389,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
if (bss->wmm_used && bss->uapsd_supported &&
- (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) &&
- sdata->wmm_acm != 0xff) {
+ (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
assoc_data->uapsd = true;
ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
} else {
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index bd2c9b2..a8d862f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2725,7 +2725,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
sig = status->signal;
if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
- rx->skb->data, rx->skb->len, 0, GFP_ATOMIC)) {
+ rx->skb->data, rx->skb->len, 0)) {
if (rx->sta)
rx->sta->rx_packets++;
dev_kfree_skb(rx->skb);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index a0a9381..a9bb6eb 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -1094,7 +1094,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
if (rcu_access_pointer(local->sched_scan_sdata)) {
ret = drv_sched_scan_stop(local, sdata);
if (!ret)
- rcu_assign_pointer(local->sched_scan_sdata, NULL);
+ RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
}
out:
mutex_unlock(&local->mtx);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index c6ee213..7300305 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1094,8 +1094,11 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
unsigned long flags;
struct ps_data *ps;
- if (sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
+ u.ap);
+
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
ps = &sdata->bss->ps;
else if (ieee80211_vif_is_mesh(&sdata->vif))
ps = &sdata->u.mesh.ps;
@@ -1179,7 +1182,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb;
int size = sizeof(*nullfunc);
__le16 fc;
- bool qos = test_sta_flag(sta, WLAN_STA_WME);
+ bool qos = sta->sta.wme;
struct ieee80211_tx_info *info;
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -1834,7 +1837,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
- if (test_sta_flag(sta, WLAN_STA_WME))
+ if (sta->sta.wme)
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
if (test_sta_flag(sta, WLAN_STA_MFP))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index d411bcc..89c40d5 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -31,7 +31,6 @@
* when virtual port control is not in use.
* @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
* frames.
- * @WLAN_STA_WME: Station is a QoS-STA.
* @WLAN_STA_WDS: Station is one of our WDS peers.
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
@@ -69,7 +68,6 @@ enum ieee80211_sta_info_flags {
WLAN_STA_PS_STA,
WLAN_STA_AUTHORIZED,
WLAN_STA_SHORT_PREAMBLE,
- WLAN_STA_WME,
WLAN_STA_WDS,
WLAN_STA_CLEAR_PS_FILT,
WLAN_STA_MFP,
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 1b21050..f2cb3b6 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -316,8 +316,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
}
/* add the QoS param IE if both the peer and we support it */
- if (local->hw.queues >= IEEE80211_NUM_ACS &&
- test_sta_flag(sta, WLAN_STA_WME))
+ if (local->hw.queues >= IEEE80211_NUM_ACS && sta->sta.wme)
ieee80211_tdls_add_wmm_param_ie(sdata, skb);
/* add any custom IEs that go before HT operation */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 464106c..925c39f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1478,7 +1478,10 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
tail_need = max_t(int, tail_need, 0);
}
- if (skb_cloned(skb))
+ if (skb_cloned(skb) &&
+ (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CLONED_SKBS) ||
+ !skb_clone_writable(skb, ETH_HLEN) ||
+ sdata->crypto_tx_tailroom_needed_cnt))
I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
else if (head_need || tail_need)
I802_DEBUG_INC(local->tx_expand_skb_head);
@@ -1844,7 +1847,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 30;
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
- wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+ wme_sta = sta->sta.wme;
}
ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
u.ap);
@@ -1957,7 +1960,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (sta) {
authorized = test_sta_flag(sta,
WLAN_STA_AUTHORIZED);
- wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+ wme_sta = sta->sta.wme;
tdls_peer = test_sta_flag(sta,
WLAN_STA_TDLS_PEER);
tdls_auth = test_sta_flag(sta,
@@ -2035,7 +2038,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
sta = sta_info_get(sdata, hdr.addr1);
if (sta) {
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
- wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+ wme_sta = sta->sta.wme;
}
}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index d51422c..6459946 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -118,7 +118,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP_VLAN:
sta = rcu_dereference(sdata->u.vlan.sta);
if (sta) {
- qos = test_sta_flag(sta, WLAN_STA_WME);
+ qos = sta->sta.wme;
break;
}
case NL80211_IFTYPE_AP:
@@ -145,7 +145,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
if (!sta && ra && !is_multicast_ether_addr(ra)) {
sta = sta_info_get(sdata, ra);
if (sta)
- qos = test_sta_flag(sta, WLAN_STA_WME);
+ qos = sta->sta.wme;
}
rcu_read_unlock();
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
index 7f820a1..a14cf9e 100644
--- a/net/mac802154/rx.c
+++ b/net/mac802154/rx.c
@@ -86,9 +86,8 @@ fail:
static void mac802154_rx_worker(struct work_struct *work)
{
struct rx_work *rw = container_of(work, struct rx_work, work);
- struct sk_buff *skb = rw->skb;
- mac802154_subif_rx(rw->dev, skb, rw->lqi);
+ mac802154_subif_rx(rw->dev, rw->skb, rw->lqi);
kfree(rw);
}
@@ -101,7 +100,7 @@ ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
if (!skb)
return;
- work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC);
+ work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work)
return;
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index 8124353..fdf4c0e6 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -89,8 +89,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
if (!(priv->phy->channels_supported[page] & (1 << chan))) {
WARN_ON(1);
- kfree_skb(skb);
- return NETDEV_TX_OK;
+ goto err_tx;
}
mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb);
@@ -103,12 +102,10 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
data[1] = crc >> 8;
}
- if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
+ if (skb_cow_head(skb, priv->hw.extra_tx_headroom))
+ goto err_tx;
- work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC);
+ work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work) {
kfree_skb(skb);
return NETDEV_TX_BUSY;
@@ -129,4 +126,8 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
queue_work(priv->dev_workqueue, &work->work);
return NETDEV_TX_OK;
+
+err_tx:
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
}
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c
index 3c3069f..b796112 100644
--- a/net/mac802154/wpan.c
+++ b/net/mac802154/wpan.c
@@ -462,7 +462,10 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
skb->pkt_type = PACKET_OTHERHOST;
break;
default:
- break;
+ spin_unlock_bh(&sdata->mib_lock);
+ pr_debug("invalid dest mode\n");
+ kfree_skb(skb);
+ return NET_RX_DROP;
}
spin_unlock_bh(&sdata->mib_lock);
@@ -472,8 +475,7 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
rc = mac802154_llsec_decrypt(&sdata->sec, skb);
if (rc) {
pr_debug("decryption failed: %i\n", rc);
- kfree_skb(skb);
- return NET_RX_DROP;
+ goto fail;
}
sdata->dev->stats.rx_packets++;
@@ -485,9 +487,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
default:
pr_warn("ieee802154: bad frame received (type = %d)\n",
mac_cb(skb)->type);
- kfree_skb(skb);
- return NET_RX_DROP;
+ goto fail;
}
+
+fail:
+ kfree_skb(skb);
+ return NET_RX_DROP;
}
static void mac802154_print_addr(const char *name,
@@ -573,6 +578,7 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
ret = mac802154_parse_frame_start(skb, &hdr);
if (ret) {
pr_debug("got invalid frame\n");
+ kfree_skb(skb);
return;
}
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
index 14c98e4..02a86a2 100644
--- a/net/rfkill/rfkill-gpio.c
+++ b/net/rfkill/rfkill-gpio.c
@@ -158,6 +158,7 @@ static const struct acpi_device_id rfkill_acpi_match[] = {
{ "BCM2E1A", RFKILL_TYPE_BLUETOOTH },
{ "BCM2E39", RFKILL_TYPE_BLUETOOTH },
{ "BCM2E3D", RFKILL_TYPE_BLUETOOTH },
+ { "BCM2E64", RFKILL_TYPE_BLUETOOTH },
{ "BCM4752", RFKILL_TYPE_GPS },
{ "LNV4752", RFKILL_TYPE_GPS },
{ },
diff --git a/net/wireless/core.c b/net/wireless/core.c
index afee5e0..c6620aa 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -492,12 +492,6 @@ int wiphy_register(struct wiphy *wiphy)
int i;
u16 ifmodes = wiphy->interface_modes;
- /*
- * There are major locking problems in nl80211/mac80211 for CSA,
- * disable for all drivers until this has been reworked.
- */
- wiphy->flags &= ~WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-
#ifdef CONFIG_PM
if (WARN_ON(wiphy->wowlan &&
(wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
@@ -635,6 +629,9 @@ int wiphy_register(struct wiphy *wiphy)
if (IS_ERR(rdev->wiphy.debugfsdir))
rdev->wiphy.debugfsdir = NULL;
+ cfg80211_debugfs_rdev_add(rdev);
+ nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
+
if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
struct regulatory_request request;
@@ -646,8 +643,6 @@ int wiphy_register(struct wiphy *wiphy)
nl80211_send_reg_change_event(&request);
}
- cfg80211_debugfs_rdev_add(rdev);
-
rdev->wiphy.registered = true;
rtnl_unlock();
@@ -659,8 +654,6 @@ int wiphy_register(struct wiphy *wiphy)
return res;
}
- nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
-
return 0;
}
EXPORT_SYMBOL(wiphy_register);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 266766b..369fc33 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -605,7 +605,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
}
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
- const u8 *buf, size_t len, u32 flags, gfp_t gfp)
+ const u8 *buf, size_t len, u32 flags)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -648,7 +648,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
/* Indicate the received Action frame to user space */
if (nl80211_send_mgmt(rdev, wdev, reg->nlportid,
freq, sig_mbm,
- buf, len, flags, gfp))
+ buf, len, flags, GFP_ATOMIC))
continue;
result = true;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index df7b133..3011401 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6033,7 +6033,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
const struct cfg80211_bss_ies *ies;
void *hdr;
struct nlattr *bss;
- bool tsf = false;
ASSERT_WDEV_LOCK(wdev);
@@ -6060,18 +6059,27 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
goto nla_put_failure;
rcu_read_lock();
+ /* indicate whether we have probe response data or not */
+ if (rcu_access_pointer(res->proberesp_ies) &&
+ nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
+ goto fail_unlock_rcu;
+
+ /* this pointer prefers to be pointed to probe response data
+ * but is always valid
+ */
ies = rcu_dereference(res->ies);
if (ies) {
if (nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
goto fail_unlock_rcu;
- tsf = true;
if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
ies->len, ies->data))
goto fail_unlock_rcu;
}
+
+ /* and this pointer is always (unless driver didn't know) beacon data */
ies = rcu_dereference(res->beacon_ies);
- if (ies) {
- if (!tsf && nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
+ if (ies && ies->from_beacon) {
+ if (nla_put_u64(msg, NL80211_BSS_BEACON_TSF, ies->tsf))
goto fail_unlock_rcu;
if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
ies->len, ies->data))
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 0798c62..620a4b4 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -884,6 +884,7 @@ struct cfg80211_bss*
cfg80211_inform_bss_width(struct wiphy *wiphy,
struct ieee80211_channel *rx_channel,
enum nl80211_bss_scan_width scan_width,
+ enum cfg80211_bss_frame_type ftype,
const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp)
@@ -911,21 +912,32 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
tmp.pub.beacon_interval = beacon_interval;
tmp.pub.capability = capability;
/*
- * Since we do not know here whether the IEs are from a Beacon or Probe
+ * If we do not know here whether the IEs are from a Beacon or Probe
* Response frame, we need to pick one of the options and only use it
* with the driver that does not provide the full Beacon/Probe Response
* frame. Use Beacon frame pointer to avoid indicating that this should
* override the IEs pointer should we have received an earlier
* indication of Probe Response data.
*/
- ies = kmalloc(sizeof(*ies) + ielen, gfp);
+ ies = kzalloc(sizeof(*ies) + ielen, gfp);
if (!ies)
return NULL;
ies->len = ielen;
ies->tsf = tsf;
+ ies->from_beacon = false;
memcpy(ies->data, ie, ielen);
- rcu_assign_pointer(tmp.pub.beacon_ies, ies);
+ switch (ftype) {
+ case CFG80211_BSS_FTYPE_BEACON:
+ ies->from_beacon = true;
+ /* fall through to assign */
+ case CFG80211_BSS_FTYPE_UNKNOWN:
+ rcu_assign_pointer(tmp.pub.beacon_ies, ies);
+ break;
+ case CFG80211_BSS_FTYPE_PRESP:
+ rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
+ break;
+ }
rcu_assign_pointer(tmp.pub.ies, ies);
signal_valid = abs(rx_channel->center_freq - channel->center_freq) <=
@@ -982,11 +994,12 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
if (!channel)
return NULL;
- ies = kmalloc(sizeof(*ies) + ielen, gfp);
+ ies = kzalloc(sizeof(*ies) + ielen, gfp);
if (!ies)
return NULL;
ies->len = ielen;
ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
+ ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
if (ieee80211_is_probe_resp(mgmt->frame_control))
OpenPOWER on IntegriCloud