diff options
Diffstat (limited to 'drivers')
144 files changed, 19144 insertions, 1729 deletions
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index 91290f7f61b8..838b4b9d352f 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 09b632ad0fe2..b40be43c6f31 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 000000000000..c20b5f4ff290 --- /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/host_pci.c b/drivers/bcma/host_pci.c index f032ed6dd459..1e5ac0a79696 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) diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c index 1edd7e064621..718e054dd727 100644 --- a/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c @@ -165,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. @@ -178,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 0ff8d58831ef..c421403cab43 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 e9bd77249a4c..b3a403c136fb 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++; } } } @@ -438,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; @@ -452,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) @@ -463,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/btusb.c b/drivers/bluetooth/btusb.c index 0527b29c3954..a79d657c0845 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -331,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)) @@ -419,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)) @@ -513,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/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index c1a4ade32772..a3b6e27d9121 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -234,6 +234,7 @@ void ath_printk(const char *level, const struct ath_common *common, * AR9462. * @ATH_DBG_DFS: radar datection * @ATH_DBG_WOW: Wake on Wireless + * @ATH_DBG_DYNACK: dynack handling * @ATH_DBG_ANY: enable all debugging * * The debug level is used to control the amount and type of debugging output @@ -262,6 +263,7 @@ enum ATH_DEBUG { ATH_DBG_DFS = 0x00010000, ATH_DBG_WOW = 0x00020000, ATH_DBG_CHAN_CTX = 0x00040000, + ATH_DBG_DYNACK = 0x00080000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b858c8288196..1f35bd1ef563 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4838,7 +4838,6 @@ int ath10k_mac_register(struct ath10k *ar) IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_HAS_RATE_CONTROL | - IEEE80211_HW_SUPPORTS_STATIC_SMPS | IEEE80211_HW_AP_LINK_PS | IEEE80211_HW_SPECTRUM_MGMT; @@ -4846,8 +4845,10 @@ int ath10k_mac_register(struct ath10k *ar) * bytes is used for padding/alignment if necessary. */ ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4; + ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; + if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) - ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; + ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) { ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index b65c38fdaa4b..ab2709a43768 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -704,7 +704,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) * reset. */ static void -ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) +ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index b8f570ed39ad..896e63281b3b 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -92,6 +92,15 @@ config ATH9K_DFS_CERTIFIED developed. At this point enabling this option won't do anything except increase code size. +config ATH9K_DYNACK + bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)" + depends on ATH9K + default n + ---help--- + This option enables ath9k dynamic ACK timeout estimation algorithm + based on ACK frame RX timestamp, TX frame timestamp and frame + duration + config ATH9K_TX99 bool "Atheros ath9k TX99 testing support" depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 6b4020a57984..73704c1be736 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -49,6 +49,9 @@ ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ ar9003_mci.o + +ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o + obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 59af9f9712da..669cb3747208 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -381,6 +381,13 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->evm1 = ads->AR_TxEVM1; ts->evm2 = ads->AR_TxEVM2; + status = ACCESS_ONCE(ads->ds_ctl4); + ts->duration[0] = MS(status, AR_PacketDur0); + ts->duration[1] = MS(status, AR_PacketDur1); + status = ACCESS_ONCE(ads->ds_ctl5); + ts->duration[2] = MS(status, AR_PacketDur2); + ts->duration[3] = MS(status, AR_PacketDur3); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 71e38e85aa99..e5f7c11fa144 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -355,9 +355,11 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { struct ar9003_txs *ads; + struct ar9003_txc *adc; u32 status; ads = &ah->ts_ring[ah->ts_tail]; + adc = (struct ar9003_txc *)ads; status = ACCESS_ONCE(ads->status8); if ((status & AR_TxDone) == 0) @@ -426,6 +428,13 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12); + status = ACCESS_ONCE(adc->ctl15); + ts->duration[0] = MS(status, AR_PacketDur0); + ts->duration[1] = MS(status, AR_PacketDur1); + status = ACCESS_ONCE(adc->ctl16); + ts->duration[2] = MS(status, AR_PacketDur2); + ts->duration[3] = MS(status, AR_PacketDur3); + memset(ads, 0, sizeof(*ads)); return 0; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index c690601f7276..8cd116efe3ea 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -274,6 +274,9 @@ struct ath_node { struct ath_rx_rate_stats rx_rate_stats; #endif u8 key_idx[4]; + + u32 ackto; + struct list_head list; }; struct ath_tx_control { @@ -314,7 +317,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]; @@ -350,6 +352,9 @@ struct ath_chanctx { bool active; bool assigned; bool switch_after_beacon; + + short nvifs; + unsigned int rxfilter; }; enum ath_chanctx_event { @@ -376,6 +381,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; @@ -449,7 +457,7 @@ 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_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, +void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, enum ath_chanctx_event ev); void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, enum ath_chanctx_event ev); @@ -478,7 +486,7 @@ 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, +static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, enum ath_chanctx_event ev) { } @@ -527,7 +535,7 @@ static inline void ath_chanctx_check_active(struct ath_softc *sc, #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); @@ -572,6 +580,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, /* VIFs */ /********/ +#define P2P_DEFAULT_CTWIN 10 + struct ath_vif { struct list_head list; @@ -590,8 +600,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 { @@ -960,7 +972,6 @@ struct ath_softc { bool ps_enabled; bool ps_idle; short nbcnvifs; - short nvifs; unsigned long ps_usecount; struct ath_rx rx; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b2f56d8b9043..a6af855ef6ed 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -183,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); @@ -514,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 409f912a67c7..77c99eb55834 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -83,8 +83,6 @@ static int ath_set_channel(struct ath_softc *sc) if (hw->conf.radar_enabled) { u32 rxfilter; - /* set HW specific DFS configuration */ - ath9k_hw_set_radar_params(ah); rxfilter = ath9k_hw_getrxfilter(ah); rxfilter |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR; @@ -262,6 +260,9 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) cur = sc->cur_chan; prev = ath_chanctx_get_next(sc, cur); + if (!prev->switch_after_beacon) + return; + getrawmonotonic(&ts); cur_tsf = (u32) cur->tsf_val + ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts); @@ -310,7 +311,6 @@ 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; @@ -333,7 +333,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, 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; @@ -372,44 +372,91 @@ 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; } - if (noa_changed) + /* Prevent wrap-around issues */ + if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30)) + avp->noa_duration = 0; + + /* + * 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, - "periodic_noa_duration: %d, periodic_noa_start: %d, noa_index: %d\n", - avp->periodic_noa_duration, - avp->periodic_noa_start, - avp->noa_index); + 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: @@ -490,9 +537,11 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, "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; } @@ -560,10 +609,9 @@ void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, ath_chanctx_event(sc, NULL, ev); } -void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, +void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, enum ath_chanctx_event ev) { - sc->sched.next_tbtt = ts; ath_chanctx_event(sc, NULL, ev); } @@ -587,8 +635,18 @@ static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, 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; } @@ -601,7 +659,7 @@ static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, if (sc->next_chan == &sc->offchannel.chan) { sc->sched.offchannel_duration = - TU_TO_USEC(sc->offchannel.duration) + + jiffies_to_usecs(sc->offchannel.duration) + sc->sched.channel_switch_time; if (chandef) { @@ -688,7 +746,8 @@ void ath_offchannel_next(struct ath_softc *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.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 { @@ -724,6 +783,10 @@ void ath_scan_complete(struct ath_softc *sc, bool abort) 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); } @@ -959,8 +1022,8 @@ static void ath_offchannel_channel_change(struct ath_softc *sc) break; sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; - mod_timer(&sc->offchannel.timer, jiffies + - msecs_to_jiffies(sc->offchannel.duration)); + mod_timer(&sc->offchannel.timer, + jiffies + sc->offchannel.duration); ieee80211_ready_on_channel(sc->hw); break; case ATH_OFFCHANNEL_ROC_DONE: @@ -1022,7 +1085,10 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) sc->cur_chan = sc->next_chan; sc->cur_chan->stopped = false; sc->next_chan = NULL; - sc->sched.offchannel_duration = 0; + + 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; @@ -1165,6 +1231,30 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) 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) { @@ -1182,10 +1272,10 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, int noa_len, noa_desc, i = 0; u8 *hdr; - if (!avp->offchannel_duration && !avp->periodic_noa_duration) + if (!avp->offchannel_duration && !avp->noa_duration) return; - noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration; + 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)); @@ -1197,13 +1287,19 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, 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->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].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); + noa->desc[i].start_time = cpu_to_le32(avp->noa_start); + noa->desc[i].duration = cpu_to_le32(avp->noa_duration); i++; } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index d2279365be6f..46f20a309b5f 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)) @@ -1169,6 +1169,29 @@ static const struct file_operations fops_btcoex = { }; #endif +#ifdef CONFIG_ATH9K_DYNACK +static ssize_t read_file_ackto(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%u %c\n", ah->dynack.ackto, + (ah->dynack.enabled) ? 'A' : 'S'); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_ackto = { + .read = read_file_ackto, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; +#endif + /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" @@ -1374,5 +1397,10 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_btcoex); #endif +#ifdef CONFIG_ATH9K_DYNACK + debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_ackto); +#endif + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c new file mode 100644 index 000000000000..6ae8e0bc9e1f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> + * + * 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 "ath9k.h" +#include "hw.h" +#include "dynack.h" + +#define COMPUTE_TO (5 * HZ) +#define LATEACK_DELAY (10 * HZ) +#define LATEACK_TO 256 +#define MAX_DELAY 300 +#define EWMA_LEVEL 96 +#define EWMA_DIV 128 + +/** + * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation + * + */ +static inline u32 ath_dynack_ewma(u32 old, u32 new) +{ + return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV; +} + +/** + * ath_dynack_get_sifs - get sifs time based on phy used + * @ah: ath hw + * @phy: phy used + * + */ +static inline u32 ath_dynack_get_sifs(struct ath_hw *ah, int phy) +{ + u32 sifs = CCK_SIFS_TIME; + + if (phy == WLAN_RC_PHY_OFDM) { + if (IS_CHAN_QUARTER_RATE(ah->curchan)) + sifs = OFDM_SIFS_TIME_QUARTER; + else if (IS_CHAN_HALF_RATE(ah->curchan)) + sifs = OFDM_SIFS_TIME_HALF; + else + sifs = OFDM_SIFS_TIME; + } + return sifs; +} + +/** + * ath_dynack_bssidmask - filter out ACK frames based on BSSID mask + * @ah: ath hw + * @mac: receiver address + */ +static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac) +{ + int i; + struct ath_common *common = ath9k_hw_common(ah); + + for (i = 0; i < ETH_ALEN; i++) { + if ((common->macaddr[i] & common->bssidmask[i]) != + (mac[i] & common->bssidmask[i])) + return false; + } + + return true; +} + +/** + * ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout + * @ah: ath hw + * + * should be called while holding qlock + */ +static void ath_dynack_compute_ackto(struct ath_hw *ah) +{ + struct ath_node *an; + u32 to = 0; + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + + list_for_each_entry(an, &da->nodes, list) + if (an->ackto > to) + to = an->ackto; + + if (to && da->ackto != to) { + u32 slottime; + + slottime = (to - 3) / 2; + da->ackto = to; + ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n", + da->ackto, slottime); + ath9k_hw_setslottime(ah, slottime); + ath9k_hw_set_ack_timeout(ah, da->ackto); + ath9k_hw_set_cts_timeout(ah, da->ackto); + } +} + +/** + * ath_dynack_compute_to - compute STA ACK timeout + * @ah: ath hw + * + * should be called while holding qlock + */ +static void ath_dynack_compute_to(struct ath_hw *ah) +{ + u32 ackto, ack_ts; + u8 *dst, *src; + struct ieee80211_sta *sta; + struct ath_node *an; + struct ts_info *st_ts; + struct ath_dynack *da = &ah->dynack; + + rcu_read_lock(); + + while (da->st_rbf.h_rb != da->st_rbf.t_rb && + da->ack_rbf.h_rb != da->ack_rbf.t_rb) { + ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb]; + st_ts = &da->st_rbf.ts[da->st_rbf.h_rb]; + dst = da->st_rbf.addr[da->st_rbf.h_rb].h_dest; + src = da->st_rbf.addr[da->st_rbf.h_rb].h_src; + + ath_dbg(ath9k_hw_common(ah), DYNACK, + "ack_ts %u st_ts %u st_dur %u [%u-%u]\n", + ack_ts, st_ts->tstamp, st_ts->dur, + da->ack_rbf.h_rb, da->st_rbf.h_rb); + + if (ack_ts > st_ts->tstamp + st_ts->dur) { + ackto = ack_ts - st_ts->tstamp - st_ts->dur; + + if (ackto < MAX_DELAY) { + sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst, + src); + if (sta) { + an = (struct ath_node *)sta->drv_priv; + an->ackto = ath_dynack_ewma(an->ackto, + ackto); + ath_dbg(ath9k_hw_common(ah), DYNACK, + "%pM to %u\n", dst, an->ackto); + if (time_is_before_jiffies(da->lto)) { + ath_dynack_compute_ackto(ah); + da->lto = jiffies + COMPUTE_TO; + } + } + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + } + INCR(da->st_rbf.h_rb, ATH_DYN_BUF); + } else { + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + } + } + + rcu_read_unlock(); +} + +/** + * ath_dynack_sample_tx_ts - status timestamp sampling method + * @ah: ath hw + * @skb: socket buffer + * @ts: tx status info + * + */ +void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, + struct ath_tx_status *ts) +{ + u8 ridx; + struct ieee80211_hdr *hdr; + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled) + return; + + spin_lock_bh(&da->qlock); + + hdr = (struct ieee80211_hdr *)skb->data; + + /* late ACK */ + if (ts->ts_status & ATH9K_TXERR_XRETRY) { + if (ieee80211_is_assoc_req(hdr->frame_control) || + ieee80211_is_assoc_resp(hdr->frame_control)) { + ath_dbg(common, DYNACK, "late ack\n"); + ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2); + ath9k_hw_set_ack_timeout(ah, LATEACK_TO); + ath9k_hw_set_cts_timeout(ah, LATEACK_TO); + da->lto = jiffies + LATEACK_DELAY; + } + + spin_unlock_bh(&da->qlock); + return; + } + + ridx = ts->ts_rateindex; + + da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp; + da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration[ts->ts_rateindex]; + ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1); + ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2); + + if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) { + u32 phy, sifs; + const struct ieee80211_rate *rate; + struct ieee80211_tx_rate *rates = info->status.rates; + + rate = &common->sbands[info->band].bitrates[rates[ridx].idx]; + if (info->band == IEEE80211_BAND_2GHZ && + !(rate->flags & IEEE80211_RATE_ERP_G)) + phy = WLAN_RC_PHY_CCK; + else + phy = WLAN_RC_PHY_OFDM; + + sifs = ath_dynack_get_sifs(ah, phy); + da->st_rbf.ts[da->st_rbf.t_rb].dur -= sifs; + } + + ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n", + hdr->addr1, da->st_rbf.ts[da->st_rbf.t_rb].tstamp, + da->st_rbf.ts[da->st_rbf.t_rb].dur, da->st_rbf.h_rb, + (da->st_rbf.t_rb + 1) % ATH_DYN_BUF); + + INCR(da->st_rbf.t_rb, ATH_DYN_BUF); + if (da->st_rbf.t_rb == da->st_rbf.h_rb) + INCR(da->st_rbf.h_rb, ATH_DYN_BUF); + + ath_dynack_compute_to(ah); + + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_sample_tx_ts); + +/** + * ath_dynack_sample_ack_ts - ACK timestamp sampling method + * @ah: ath hw + * @skb: socket buffer + * @ts: rx timestamp + * + */ +void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, + u32 ts) +{ + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled) + return; + + spin_lock_bh(&da->qlock); + da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts; + + ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n", + da->ack_rbf.tstamp[da->ack_rbf.t_rb], + da->ack_rbf.h_rb, (da->ack_rbf.t_rb + 1) % ATH_DYN_BUF); + + INCR(da->ack_rbf.t_rb, ATH_DYN_BUF); + if (da->ack_rbf.t_rb == da->ack_rbf.h_rb) + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + + ath_dynack_compute_to(ah); + + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_sample_ack_ts); + +/** + * ath_dynack_node_init - init ath_node related info + * @ah: ath hw + * @an: ath node + * + */ +void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an) +{ + /* ackto = slottime + sifs + air delay */ + u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64; + struct ath_dynack *da = &ah->dynack; + + an->ackto = ackto; + + spin_lock(&da->qlock); + list_add_tail(&an->list, &da->nodes); + spin_unlock(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_node_init); + +/** + * ath_dynack_node_deinit - deinit ath_node related info + * @ah: ath hw + * @an: ath node + * + */ +void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an) +{ + struct ath_dynack *da = &ah->dynack; + + spin_lock(&da->qlock); + list_del(&an->list); + spin_unlock(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_node_deinit); + +/** + * ath_dynack_reset - reset dynack processing + * @ah: ath hw + * + */ +void ath_dynack_reset(struct ath_hw *ah) +{ + /* ackto = slottime + sifs + air delay */ + u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64; + struct ath_dynack *da = &ah->dynack; + + da->lto = jiffies; + da->ackto = ackto; + + da->st_rbf.t_rb = 0; + da->st_rbf.h_rb = 0; + da->ack_rbf.t_rb = 0; + da->ack_rbf.h_rb = 0; + + /* init acktimeout */ + ath9k_hw_setslottime(ah, (ackto - 3) / 2); + ath9k_hw_set_ack_timeout(ah, ackto); + ath9k_hw_set_cts_timeout(ah, ackto); +} +EXPORT_SYMBOL(ath_dynack_reset); + +/** + * ath_dynack_init - init dynack data structure + * @ah: ath hw + * + */ +void ath_dynack_init(struct ath_hw *ah) +{ + struct ath_dynack *da = &ah->dynack; + + memset(da, 0, sizeof(struct ath_dynack)); + + spin_lock_init(&da->qlock); + INIT_LIST_HEAD(&da->nodes); + + ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION; +} diff --git a/drivers/net/wireless/ath/ath9k/dynack.h b/drivers/net/wireless/ath/ath9k/dynack.h new file mode 100644 index 000000000000..6d7bef976742 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dynack.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> + * + * 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 DYNACK_H +#define DYNACK_H + +#define ATH_DYN_BUF 64 + +struct ath_hw; +struct ath_node; + +/** + * struct ath_dyn_rxbuf - ACK frame ring buffer + * @h_rb: ring buffer head + * @t_rb: ring buffer tail + * @tstamp: ACK RX timestamp buffer + */ +struct ath_dyn_rxbuf { + u16 h_rb, t_rb; + u32 tstamp[ATH_DYN_BUF]; +}; + +struct ts_info { + u32 tstamp; + u32 dur; +}; + +struct haddr_pair { + u8 h_dest[ETH_ALEN]; + u8 h_src[ETH_ALEN]; +}; + +/** + * struct ath_dyn_txbuf - tx frame ring buffer + * @h_rb: ring buffer head + * @t_rb: ring buffer tail + * @addr: dest/src address pair for a given TX frame + * @ts: TX frame timestamp buffer + */ +struct ath_dyn_txbuf { + u16 h_rb, t_rb; + struct haddr_pair addr[ATH_DYN_BUF]; + struct ts_info ts[ATH_DYN_BUF]; +}; + +/** + * struct ath_dynack - dynack processing info + * @enabled: enable dyn ack processing + * @ackto: current ACK timeout + * @lto: last ACK timeout computation + * @nodes: ath_node linked list + * @qlock: ts queue spinlock + * @ack_rbf: ACK ts ring buffer + * @st_rbf: status ts ring buffer + */ +struct ath_dynack { + bool enabled; + int ackto; + unsigned long lto; + + struct list_head nodes; + + /* protect timestamp queue access */ + spinlock_t qlock; + struct ath_dyn_rxbuf ack_rbf; + struct ath_dyn_txbuf st_rbf; +}; + +#if defined(CONFIG_ATH9K_DYNACK) +void ath_dynack_reset(struct ath_hw *ah); +void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an); +void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an); +void ath_dynack_init(struct ath_hw *ah); +void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts); +void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, + struct ath_tx_status *ts); +#else +static inline void ath_dynack_init(struct ath_hw *ah) {} +static inline void ath_dynack_node_init(struct ath_hw *ah, + struct ath_node *an) {} +static inline void ath_dynack_node_deinit(struct ath_hw *ah, + struct ath_node *an) {} +static inline void ath_dynack_sample_ack_ts(struct ath_hw *ah, + struct sk_buff *skb, u32 ts) {} +static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah, + struct sk_buff *skb, + struct ath_tx_status *ts) {} +#endif + +#endif /* DYNACK_H */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 5627917c5ff7..994fff1ff519 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1722,7 +1722,7 @@ static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) } static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, - u8 coverage_class) + s16 coverage_class) { struct ath9k_htc_priv *priv = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 69bbea1184d2..3aed729e4d5e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -647,6 +647,8 @@ int ath9k_hw_init(struct ath_hw *ah) return ret; } + ath_dynack_init(ah); + return 0; } EXPORT_SYMBOL(ath9k_hw_init); @@ -935,21 +937,21 @@ static void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us) REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val); } -static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) +void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) 0xFFFF); REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val); } -static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) +void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK)); REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val); } -static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) +void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS)); @@ -1053,6 +1055,14 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ctstimeout += 48 - sifstime - ah->slottime; } + if (ah->dynack.enabled) { + acktimeout = ah->dynack.ackto; + ctstimeout = acktimeout; + slottime = (acktimeout - 3) / 2; + } else { + ah->dynack.ackto = acktimeout; + } + ath9k_hw_set_sifs_time(ah, sifstime); ath9k_hw_setslottime(ah, slottime); ath9k_hw_set_ack_timeout(ah, acktimeout); @@ -1954,6 +1964,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9565(ah) && common->bt_ant_diversity) REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); + if (ah->hw->conf.radar_enabled) { + /* set HW specific DFS configuration */ + ah->radar_conf.ext_channel = IS_CHAN_HT40(chan); + ath9k_hw_set_radar_params(ah); + } + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 51b4ebe04c04..b9eef3362fbb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -29,6 +29,7 @@ #include "reg.h" #include "phy.h" #include "btcoex.h" +#include "dynack.h" #include "../regd.h" @@ -924,6 +925,8 @@ struct ath_hw { int (*external_reset)(void); const struct firmware *eeprom_blob; + + struct ath_dynack dynack; }; struct ath_bus_ops { @@ -1080,6 +1083,10 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); +void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us); +void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us); +void ath9k_hw_setslottime(struct ath_hw *ah, u32 us); + #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index ca10a8b3a381..156a944134dc 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -763,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 = @@ -810,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; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 6c56cafa5ca4..cd05a7791073 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -121,6 +121,7 @@ struct ath_tx_status { u32 evm0; u32 evm1; u32 evm2; + u32 duration[4]; }; struct ath_rx_status { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4a8c9b80b08e..fbf23ac61c97 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -224,16 +224,11 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; - 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 */ @@ -350,12 +345,16 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, memset(&an->key_idx, 0, sizeof(an->key_idx)); ath_tx_node_init(sc, an); + + ath_dynack_node_init(sc->sc_ah, an); } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; ath_tx_node_cleanup(sc, an); + + ath_dynack_node_deinit(sc->sc_ah, an); } void ath9k_tasklet(unsigned long data) @@ -916,8 +915,6 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, 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++; @@ -960,21 +957,6 @@ 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; - - if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START) - vif = sc->offchannel.scan_vif; - else - vif = sc->offchannel.roc_vif; - - if (vif) - ath9k_vif_iter(iter_data, vif->addr, vif); - iter_data->beacons = false; - } -#endif } static void ath9k_set_assoc_state(struct ath_softc *sc, @@ -985,13 +967,6 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, unsigned long flags; set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); - /* Set the AID, BSSID and do beacon-sync only when - * the HW opmode is STATION. - * - * But the primary bit is set above in any case. - */ - if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) - return; ether_addr_copy(common->curbssid, bss_conf->bssid); common->curaid = bss_conf->aid; @@ -1014,6 +989,43 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, vif->addr, common->curbssid); } +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +static void ath9k_set_offchannel_state(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_vif *vif = NULL; + + ath9k_ps_wakeup(sc); + + if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START) + vif = sc->offchannel.scan_vif; + else + vif = sc->offchannel.roc_vif; + + if (WARN_ON(!vif)) + goto exit; + + eth_zero_addr(common->curbssid); + eth_broadcast_addr(common->bssidmask); + ether_addr_copy(common->macaddr, vif->addr); + common->curaid = 0; + ah->opmode = vif->type; + ah->imask &= ~ATH9K_INT_SWBA; + ah->imask &= ~ATH9K_INT_TSFOOR; + ah->slottime = ATH9K_SLOT_TIME_9; + + ath_hw_setbssidmask(common); + ath9k_hw_setopmode(ah); + ath9k_hw_write_associd(sc->sc_ah); + ath9k_hw_set_interrupts(ah); + ath9k_hw_init_global_settings(ah); + +exit: + ath9k_ps_restore(sc); +} +#endif + /* Called with sc->mutex held. */ void ath9k_calculate_summary_state(struct ath_softc *sc, struct ath_chanctx *ctx) @@ -1021,12 +1033,18 @@ 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); if (ctx != sc->cur_chan) return; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + if (ctx == &sc->offchannel.chan) + return ath9k_set_offchannel_state(sc); +#endif + ath9k_ps_wakeup(sc); ath9k_calculate_iter_data(sc, ctx, &iter_data); @@ -1037,8 +1055,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); @@ -1067,13 +1088,11 @@ 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 || - !ctx->primary_sta->bss_conf.assoc) - ctx->primary_sta = iter_data.primary_sta; + ctx->primary_sta = iter_data.primary_sta; } else { ctx->primary_sta = NULL; memset(common->curbssid, 0, ETH_ALEN); @@ -1102,11 +1121,23 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, else clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); - ctx->primary_sta = iter_data.primary_sta; - 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) { @@ -1115,12 +1146,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; } @@ -1128,7 +1158,7 @@ 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); @@ -1138,12 +1168,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, 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; @@ -1163,7 +1189,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); @@ -1183,14 +1208,7 @@ 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); @@ -1210,7 +1228,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_p2p_remove_vif(sc, vif); - sc->nvifs--; + sc->cur_chan->nvifs--; sc->tx99_vif = NULL; if (!ath9k_is_chanctx_enabled()) list_del(&avp->list); @@ -1430,7 +1448,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); @@ -1695,9 +1716,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) && @@ -1859,7 +1880,22 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } -static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) +static void ath9k_enable_dynack(struct ath_softc *sc) +{ +#ifdef CONFIG_ATH9K_DYNACK + u32 rfilt; + struct ath_hw *ah = sc->sc_ah; + + ath_dynack_reset(ah); + + ah->dynack.enabled = true; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(ah, rfilt); +#endif +} + +static void ath9k_set_coverage_class(struct ieee80211_hw *hw, + s16 coverage_class) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; @@ -1868,11 +1904,22 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) return; mutex_lock(&sc->mutex); - ah->coverage_class = coverage_class; - ath9k_ps_wakeup(sc); - ath9k_hw_init_global_settings(ah); - ath9k_ps_restore(sc); + if (coverage_class >= 0) { + ah->coverage_class = coverage_class; + if (ah->dynack.enabled) { + u32 rfilt; + + ah->dynack.enabled = false; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(ah, rfilt); + } + ath9k_ps_wakeup(sc); + ath9k_hw_init_global_settings(ah); + ath9k_ps_restore(sc); + } else if (!ah->dynack.enabled) { + ath9k_enable_dynack(sc); + } mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2aaf233ee5d6..6914e21816e4 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,25 @@ 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) || + sc->sc_ah->dynack.enabled) 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; @@ -429,18 +432,20 @@ u32 ath_calcrxfilter(struct ath_softc *sc) 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 +468,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) @@ -535,6 +538,7 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); + bool skip_beacon = false; if (skb->len < 24 + 8 + 2 + 2) return; @@ -545,7 +549,16 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); - if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) + +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + if (ath9k_is_chanctx_enabled()) { + if (sc->cur_chan == &sc->offchannel.chan) + skip_beacon = true; + } +#endif + + if (!skip_beacon && + !(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) ath9k_set_beacon(sc); ath9k_p2p_beacon_sync(sc); @@ -867,8 +880,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); @@ -894,7 +912,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (ath9k_is_chanctx_enabled()) { if (rx_stats->is_mybeacon) - ath_chanctx_beacon_recv_ev(sc, rx_stats->rs_tstamp, + ath_chanctx_beacon_recv_ev(sc, ATH_CHANCTX_EVENT_BEACON_RECEIVED); } @@ -992,6 +1010,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) unsigned long flags; dma_addr_t new_buf_addr; unsigned int budget = 512; + struct ieee80211_hdr *hdr; if (edma) dma_type = DMA_BIDIRECTIONAL; @@ -1121,6 +1140,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ath9k_apply_ampdu_details(sc, &rs, rxs); ath_debug_rate_stats(sc, &rs, skb); + hdr = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_ack(hdr->frame_control)) + ath_dynack_sample_ack_ts(sc->sc_ah, skb, rs.rs_tstamp); + ieee80211_rx(hw, skb); requeue_drop_frag: diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 23972924c774..8a69d08ec55c 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 33531d9a4d50..5f30e580d942 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -232,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 281986613fb2..93ad31be0ada 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -587,6 +587,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, memcpy(tx_info->control.rates, rates, sizeof(rates)); ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok); rc_update = false; + if (bf == bf->bf_lastbf) + ath_dynack_sample_tx_ts(sc->sc_ah, + bf->bf_mpdu, + ts); } ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, @@ -687,6 +691,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, memcpy(info->control.rates, bf->rates, sizeof(info->control.rates)); ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); + ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts); } ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); } else diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index ce8c0381825e..481680a3aa55 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 c7a3465fd02a..a471d74ae409 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 a00f31881df9..f3a31e8c2535 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -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,9 +309,23 @@ 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])); +out: if (rc) { del_timer_sync(&wil->scan_timer); wil->scan_request = NULL; @@ -319,6 +334,22 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, 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) @@ -335,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); @@ -360,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 */ @@ -621,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) @@ -658,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; @@ -671,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 */ /* @@ -695,7 +760,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, if (rc) goto out; - netif_carrier_on(ndev); out: @@ -706,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__); @@ -715,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, @@ -746,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, @@ -755,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) | @@ -764,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 | @@ -786,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); @@ -818,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/debug.c b/drivers/net/wireless/ath/wil6210/debug.c index 9eeabf4a5879..8d99021d27a8 100644 --- a/drivers/net/wireless/ath/wil6210/debug.c +++ b/drivers/net/wireless/ath/wil6210/debug.c @@ -17,43 +17,37 @@ #include "wil6210.h" #include "trace.h" -int wil_err(struct wil6210_priv *wil, const char *fmt, ...) +void wil_err(struct wil6210_priv *wil, const char *fmt, ...) { struct net_device *ndev = wil_to_ndev(wil); struct va_format vaf = { .fmt = fmt, }; va_list args; - int ret; va_start(args, fmt); vaf.va = &args; - ret = netdev_err(ndev, "%pV", &vaf); + netdev_err(ndev, "%pV", &vaf); trace_wil6210_log_err(&vaf); va_end(args); - - return ret; } -int wil_info(struct wil6210_priv *wil, const char *fmt, ...) +void wil_info(struct wil6210_priv *wil, const char *fmt, ...) { struct net_device *ndev = wil_to_ndev(wil); struct va_format vaf = { .fmt = fmt, }; va_list args; - int ret; va_start(args, fmt); vaf.va = &args; - ret = netdev_info(ndev, "%pV", &vaf); + netdev_info(ndev, "%pV", &vaf); trace_wil6210_log_info(&vaf); va_end(args); - - return ret; } -int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...) +void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, @@ -64,6 +58,4 @@ int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...) vaf.va = &args; trace_wil6210_log_dbg(&vaf); va_end(args); - - return 0; } diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index b1c6a7293390..eb2204e5fdd4 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -61,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) @@ -85,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) { @@ -163,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; } @@ -182,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); @@ -199,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), @@ -208,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) @@ -271,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"); @@ -302,7 +308,7 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, int i; for (i = 0; tbl[i].name; i++) { - struct dentry *f = NULL; + struct dentry *f; switch (tbl[i].type) { case doff_u32: @@ -322,6 +328,8 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, 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", @@ -339,6 +347,7 @@ static const struct dbg_off isr_off[] = { {"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) @@ -422,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; @@ -474,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) @@ -499,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) @@ -509,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)) { @@ -545,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, @@ -555,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; @@ -625,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); @@ -664,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) @@ -682,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; @@ -702,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", @@ -816,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) @@ -878,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; } @@ -937,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 "; @@ -997,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) : "" @@ -1032,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) @@ -1046,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 "; @@ -1065,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); } } diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c new file mode 100644 index 000000000000..8c6f3b041f77 --- /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 000000000000..7a2c6c129ad5 --- /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 000000000000..44cb71f5ea5b --- /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 98bfbb6390b7..7269bac111b9 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -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 b69d90f0716f..21667e0c3d14 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -20,11 +20,19 @@ #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 */ @@ -67,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); @@ -86,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) @@ -205,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: @@ -223,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; @@ -257,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); @@ -295,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); @@ -312,6 +336,28 @@ void wil_priv_deinit(struct wil6210_priv *wil) destroy_workqueue(wil->wmi_wq); } +/* 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; @@ -321,60 +367,41 @@ static int 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) - - wmb(); /* If host reorder writes here -> race in NIC */ - W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ 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_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ - wmb(); /* If host reorder writes here -> race in NIC */ - W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_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) { @@ -384,12 +411,10 @@ static int 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. typical time is 200..250 msec */ do { @@ -407,16 +432,15 @@ static int 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 * RST_DELAY); return 0; +} #undef R #undef W #undef S #undef C -} void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) { @@ -431,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; @@ -450,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", @@ -468,7 +493,7 @@ int wil_reset(struct wil6210_priv *wil) wil->scan_request = NULL; } - wil6210_disable_irq(wil); + wil_mask_irq(wil); wmi_event_flush(wil); @@ -480,13 +505,38 @@ int wil_reset(struct wil6210_priv *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); @@ -522,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; @@ -568,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; } @@ -580,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); @@ -587,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", @@ -603,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; @@ -613,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 a44c2b61be08..1c0c77d9a14f 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -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"); @@ -169,6 +178,8 @@ 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; @@ -185,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); @@ -200,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 38dcbea49d44..66626a8ee728 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -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); @@ -220,9 +253,13 @@ 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, csr); pci_release_region(pdev, 0); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 97c6a24716a1..489cb73d139b 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -98,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 @@ -176,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; @@ -197,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 9bd920d272bb..2936ef0c18cb 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -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 = ⅆ - 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; @@ -532,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]); } } @@ -573,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); } @@ -583,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; @@ -612,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); } @@ -646,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; @@ -695,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)) @@ -721,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) { @@ -740,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); } @@ -750,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; @@ -833,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; @@ -902,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); @@ -934,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; @@ -982,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); @@ -996,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); @@ -1024,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 a1ac4f87d47b..de046716d2b7 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -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 f8718fe547c4..41aa79327584 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -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) @@ -136,6 +148,8 @@ struct RGF_ICR { /* 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) + \ @@ -154,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]; @@ -303,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; @@ -363,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)]; }; @@ -389,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; @@ -426,6 +437,9 @@ struct wil6210_priv { /* 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) @@ -435,10 +449,11 @@ 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, ...); -int wil_info(struct wil6210_priv *wil, const char *fmt, ...); +void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...); +void wil_err(struct wil6210_priv *wil, const char *fmt, ...); +void wil_info(struct wil6210_priv *wil, const char *fmt, ...); #define wil_dbg(wil, fmt, arg...) do { \ netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \ wil_dbg_trace(wil, fmt, ##arg); \ @@ -449,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,\ @@ -460,6 +476,19 @@ 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 /* defined(CONFIG_DYNAMIC_DEBUG) */ +static inline +void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize, + int groupsize, const void *buf, size_t len, bool ascii) +{ +} + +static inline +void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize, + int groupsize, const void *buf, size_t len, bool ascii) +{ +} +#endif /* defined(CONFIG_DYNAMIC_DEBUG) */ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, size_t count); @@ -477,7 +506,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); @@ -510,8 +541,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); @@ -547,4 +580,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 000000000000..8f1d78f8a74d --- /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 000000000000..158c73b049a9 --- /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 000000000000..b354a743240d --- /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 000000000000..2f2229edb498 --- /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 b1aaaee997d5..bd781c7adf2a 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -157,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; @@ -278,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; @@ -298,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); } @@ -595,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 { @@ -653,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; } @@ -708,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], @@ -748,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); @@ -953,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 */ @@ -1128,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) { @@ -1138,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 */ @@ -1184,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 061618cee9f6..27b97432d1c2 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -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, @@ -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/b43/b43.h b/drivers/net/wireless/b43/b43.h index 95a943326420..bb12586cd7cd 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -45,6 +45,7 @@ #define B43_MMIO_RAM_DATA 0x134 #define B43_MMIO_PS_STATUS 0x140 #define B43_MMIO_RADIO_HWENABLED_HI 0x158 +#define B43_MMIO_MAC_HW_CAP 0x15C /* MAC capabilities (corerev >= 13) */ #define B43_MMIO_SHM_CONTROL 0x160 #define B43_MMIO_SHM_DATA 0x164 #define B43_MMIO_SHM_DATA_UNALIGNED 0x166 @@ -253,6 +254,8 @@ enum { #define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ #define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5 Ghz channel */ #define B43_SHM_SH_CHAN_40MHZ 0x0200 /* Bit set, if 40 Mhz channel width */ +#define B43_SHM_SH_MACHW_L 0x00C0 /* Location where the ucode expects the MAC capabilities */ +#define B43_SHM_SH_MACHW_H 0x00C2 /* Location where the ucode expects the MAC capabilities */ #define B43_SHM_SH_HOSTF5 0x00D4 /* Hostflags 5 for ucode options */ #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ /* TSSI information */ @@ -297,6 +300,7 @@ enum { #define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */ #define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */ #define B43_SHM_SH_EXTNPHYCTL 0x00B0 /* Extended bytes for beacon PHY control (N) */ +#define B43_SHM_SH_BCN_LI 0x00B6 /* beacon listen interval */ /* SHM_SHARED ACK/CTS control */ #define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */ /* SHM_SHARED probe response variables */ @@ -476,6 +480,11 @@ enum { #define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */ #define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */ +/* B43_MMIO_PSM_PHY_HDR bits */ +#define B43_PSM_HDR_MAC_PHY_RESET 0x00000001 +#define B43_PSM_HDR_MAC_PHY_CLOCK_EN 0x00000002 +#define B43_PSM_HDR_MAC_PHY_FORCE_CLK 0x00000004 + /* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */ #define B43_BCMA_CLKCTLST_80211_PLL_REQ 0x00000100 #define B43_BCMA_CLKCTLST_PHY_PLL_REQ 0x00000200 diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 66ff718cc412..5d4173ee55bc 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1204,6 +1204,36 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ +void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev) +{ + struct bcma_drv_cc *bcma_cc __maybe_unused; + struct ssb_chipcommon *ssb_cc __maybe_unused; + + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_cc = &dev->dev->bdev->bus->drv_cc; + + bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0); + bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4); + bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4); + bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + ssb_cc = &dev->dev->sdev->bus->chipco; + + chipco_write32(ssb_cc, SSB_CHIPCO_CHIPCTL_ADDR, 0); + chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4); + chipco_set32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, 0x4); + chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4); + break; +#endif + } +} + #ifdef CONFIG_B43_BCMA static void b43_bcma_phy_reset(struct b43_wldev *dev) { @@ -2985,7 +3015,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 || @@ -3106,6 +3151,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev) case B43_PHYTYPE_HT: case B43_PHYTYPE_LCN: b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_9MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1); @@ -3884,6 +3930,12 @@ static int b43_switch_band(struct b43_wldev *dev, return 0; } +static void b43_set_beacon_listen_interval(struct b43_wldev *dev, u16 interval) +{ + interval = min_t(u16, interval, (u16)0xFF); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BCN_LI, interval); +} + /* Write the short and long frame retry limit values. */ static void b43_set_retry_limits(struct b43_wldev *dev, unsigned int short_retry, @@ -3912,6 +3964,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); b43_mac_suspend(dev); + if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) + b43_set_beacon_listen_interval(dev, conf->listen_interval); + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { phy->chandef = &conf->chandef; phy->channel = conf->chandef.chan->hw_value; @@ -4812,6 +4867,16 @@ static int b43_wireless_core_init(struct b43_wldev *dev) hf &= ~B43_HF_SKCFPUP; b43_hf_write(dev, hf); + /* tell the ucode MAC capabilities */ + if (dev->dev->core_rev >= 13) { + u32 mac_hw_cap = b43_read32(dev, B43_MMIO_MAC_HW_CAP); + + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_L, + mac_hw_cap & 0xffff); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_H, + (mac_hw_cap >> 16) & 0xffff); + } + b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT, B43_DEFAULT_LONG_RETRY_LIMIT); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3); @@ -4834,6 +4899,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev) /* Maximum Contention Window */ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); + /* write phytype and phyvers */ + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYTYPE, phy->type); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYVER, phy->rev); + if (b43_bus_host_is_pcmcia(dev->dev) || b43_bus_host_is_sdio(dev->dev)) { dev->__using_pio_transfers = true; diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 9f22e4b4c132..c46430cc725c 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -96,6 +96,8 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason); #define B43_PS_ASLEEP (1 << 3) /* Force device asleep */ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); +void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev); + void b43_mac_suspend(struct b43_wldev *dev); void b43_mac_enable(struct b43_wldev *dev); void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index c4dc8b020f60..bd68945965d6 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); + + 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); - b43_radio_mask(dev, 0x17F, ~0x1); + 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); } /************************************************** @@ -297,6 +321,26 @@ static void b43_phy_ht_bphy_init(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); } +static void b43_phy_ht_bphy_reset(struct b43_wldev *dev, bool reset) +{ + u16 tmp; + + tmp = b43_read16(dev, B43_MMIO_PSM_PHY_HDR); + b43_write16(dev, B43_MMIO_PSM_PHY_HDR, + tmp | B43_PSM_HDR_MAC_PHY_FORCE_CLK); + + /* Put BPHY in or take it out of the reset */ + if (reset) + b43_phy_set(dev, B43_PHY_B_BBCFG, + B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX); + else + b43_phy_mask(dev, B43_PHY_B_BBCFG, + (u16)~(B43_PHY_B_BBCFG_RSTCCA | + B43_PHY_B_BBCFG_RSTRX)); + + b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp); +} + /************************************************** * Samples **************************************************/ @@ -704,7 +748,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,22 +760,9 @@ 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 */ + b43_wireless_core_phy_pll_reset(dev); if (spuravoid) b43_phy_set(dev, B43_PHY_HT_BBCFG, B43_PHY_HT_BBCFG_RSTRX); @@ -747,13 +777,19 @@ static void b43_phy_ht_channel_setup(struct b43_wldev *dev, const struct b43_phy_ht_channeltab_e_phy *e, struct ieee80211_channel *new_channel) { - bool old_band_5ghz; + if (new_channel->band == IEEE80211_BAND_5GHZ) { + /* Switch to 2 GHz for a moment to access B-PHY regs */ + b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ); + + b43_phy_ht_bphy_reset(dev, true); - old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */ - if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) { - /* TODO */ - } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) { - /* TODO */ + /* Switch to 5 GHz */ + b43_phy_set(dev, B43_PHY_HT_BANDCTL, B43_PHY_HT_BANDCTL_5GHZ); + } else { + /* Switch to 2 GHz */ + b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ); + + b43_phy_ht_bphy_reset(dev, false); } b43_phy_write(dev, B43_PHY_HT_BW1, e->bw1); @@ -1002,19 +1038,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 diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h index 6cae370d1018..c086f56ce478 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) @@ -104,6 +106,9 @@ #define B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT 0 #define B43_PHY_HT_TX_PCTL_STATUS_C3 B43_PHY_EXTG(0x169) +#define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001) +#define B43_PHY_B_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_PHY_B_BBCFG_RSTRX 0x8000 /* Reset RX */ #define B43_PHY_HT_TEST B43_PHY_N_BMODE(0x00A) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index cf625d8732a7..9f0bcf3b8414 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6369,7 +6369,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, b43_mac_switch_freq(dev, spuravoid); if (dev->phy.rev == 3 || dev->phy.rev == 4) - ; /* TODO: reset PLL */ + b43_wireless_core_phy_pll_reset(dev); if (spuravoid) b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTRX); diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c index 38e31d857e3e..a3cf9efd7e21 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) \ @@ -58,73 +65,87 @@ .phy_regs.bw5 = r4, \ .phy_regs.bw6 = r5 +/* Extracted from MMIO dump of 6.30.223.141 + * TODO: Values for channels 12 & 13 are outdated (from some old 5.x driver)! + */ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radio2059[] = { - { .freq = 2412, - RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, - 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), - }, - { .freq = 2417, - RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, - 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), - }, - { .freq = 2422, - RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, - 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), - }, - { .freq = 2427, - RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, - 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), - }, - { .freq = 2432, - RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, - 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), - }, - { .freq = 2437, - RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, - 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), - }, - { .freq = 2442, - RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, - 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), - }, - { .freq = 2447, - RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, - 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), - }, - { .freq = 2452, - RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, - 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), - }, - { .freq = 2457, - RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, - 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), - }, - { .freq = 2462, - RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, - 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), - }, + { + .freq = 2412, + RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, + 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xd0, 0x00), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { + .freq = 2417, + RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, + 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xd0, 0x00), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { + .freq = 2422, + RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, + 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xd0, 0x00), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { + .freq = 2427, + RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, + 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xa0, 0x00), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { + .freq = 2432, + RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, + 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xa0, 0x00), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { + .freq = 2437, + RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, + 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xa0, 0x00), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { + .freq = 2442, + RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x80, 0x00), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { + .freq = 2447, + RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x80, 0x00), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { + .freq = 2452, + RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x80, 0x00), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { + .freq = 2457, + RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, + 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x60, 0x00), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { + .freq = 2462, + RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, + 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x60, 0x00), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, { .freq = 2467, RADIOREGS(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03, @@ -137,8 +158,196 @@ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radi 0x00, 0x00, 0x00, 0xf0, 0x00), PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), }, + { + .freq = 5180, + RADIOREGS(0xbe, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x06, + 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, + 0x0f, 0x4f, 0xa3, 0x00, 0xfc), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { + .freq = 5200, + RADIOREGS(0xc5, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x08, + 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xfb), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { + .freq = 5220, + RADIOREGS(0xcc, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0a, + 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xea), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { + .freq = 5240, + RADIOREGS(0xd2, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0c, + 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xda), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { + .freq = 5260, + RADIOREGS(0xd9, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0e, + 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xca), + PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3), + }, + { + .freq = 5280, + RADIOREGS(0xe0, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x10, + 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xb9), + PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1), + }, + { + .freq = 5300, + RADIOREGS(0xe6, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x12, + 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, + 0x0f, 0x4c, 0x83, 0x00, 0xb8), + PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0), + }, + { + .freq = 5320, + RADIOREGS(0xed, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x14, + 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, + 0x0f, 0x4c, 0x83, 0x00, 0xa8), + PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee), + }, + { + .freq = 5500, + RADIOREGS(0x29, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x26, + 0x02, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x75), + PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd), + }, + { + .freq = 5520, + RADIOREGS(0x30, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x28, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x75), + PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc), + }, + { + .freq = 5540, + RADIOREGS(0x36, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2a, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x75), + PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da), + }, + { + .freq = 5560, + RADIOREGS(0x3d, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2c, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x75), + PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8), + }, + { + .freq = 5580, + RADIOREGS(0x44, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2e, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x74), + PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7), + }, + { + .freq = 5600, + RADIOREGS(0x4a, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x30, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x09, 0x44, 0x23, 0x00, 0x54), + PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5), + }, + { + .freq = 5620, + RADIOREGS(0x51, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x32, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x09, 0x44, 0x23, 0x00, 0x54), + PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3), + }, + { + .freq = 5640, + RADIOREGS(0x58, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x34, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x09, 0x44, 0x23, 0x00, 0x43), + PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2), + }, + { + .freq = 5660, + RADIOREGS(0x5e, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x36, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x09, 0x43, 0x23, 0x00, 0x43), + PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0), + }, + { + .freq = 5680, + RADIOREGS(0x65, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x38, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x09, 0x42, 0x23, 0x00, 0x43), + PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce), + }, + { + .freq = 5700, + RADIOREGS(0x6c, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x3a, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x08, 0x42, 0x13, 0x00, 0x32), + PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd), + }, + { + .freq = 5745, + RADIOREGS(0x7b, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x7d, + 0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, + 0x08, 0x42, 0x13, 0x00, 0x21), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { + .freq = 5765, + RADIOREGS(0x81, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x81, + 0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, + 0x08, 0x42, 0x13, 0x00, 0x11), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { + .freq = 5785, + RADIOREGS(0x88, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x85, + 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, + 0x08, 0x42, 0x13, 0x00, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { + .freq = 5805, + RADIOREGS(0x8f, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x89, + 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, + 0x06, 0x41, 0x03, 0x00, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { + .freq = 5825, + RADIOREGS(0x95, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x8d, + 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, + 0x06, 0x41, 0x03, 0x00, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, }; +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 40a82d7f510c..9e22fb60588b 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/xmit.h b/drivers/net/wireless/b43/xmit.h index 98d90747836a..ba6115308068 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -97,9 +97,13 @@ struct b43_tx_legacy_rate_phy_ctl_entry { }; /* MAC TX control */ +#define B43_TXH_MAC_RTS_FB_SHORTPRMBL 0x80000000 /* RTS fallback preamble */ +#define B43_TXH_MAC_RTS_SHORTPRMBL 0x40000000 /* RTS main rate preamble */ +#define B43_TXH_MAC_FB_SHORTPRMBL 0x20000000 /* Main fallback preamble */ #define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */ #define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */ #define B43_TXH_MAC_KEYIDX_SHIFT 20 +#define B43_TXH_MAC_ALT_TXPWR 0x00080000 /* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */ #define B43_TXH_MAC_KEYALG 0x00070000 /* Security key algorithm */ #define B43_TXH_MAC_KEYALG_SHIFT 16 #define B43_TXH_MAC_AMIC 0x00008000 /* AMIC */ @@ -126,25 +130,25 @@ struct b43_tx_legacy_rate_phy_ctl_entry { #define B43_TXH_EFT_FB 0x03 /* Data frame fallback encoding */ #define B43_TXH_EFT_FB_CCK 0x00 /* CCK */ #define B43_TXH_EFT_FB_OFDM 0x01 /* OFDM */ -#define B43_TXH_EFT_FB_EWC 0x02 /* EWC */ -#define B43_TXH_EFT_FB_N 0x03 /* N */ +#define B43_TXH_EFT_FB_HT 0x02 /* HT */ +#define B43_TXH_EFT_FB_VHT 0x03 /* VHT */ #define B43_TXH_EFT_RTS 0x0C /* RTS/CTS encoding */ #define B43_TXH_EFT_RTS_CCK 0x00 /* CCK */ #define B43_TXH_EFT_RTS_OFDM 0x04 /* OFDM */ -#define B43_TXH_EFT_RTS_EWC 0x08 /* EWC */ -#define B43_TXH_EFT_RTS_N 0x0C /* N */ +#define B43_TXH_EFT_RTS_HT 0x08 /* HT */ +#define B43_TXH_EFT_RTS_VHT 0x0C /* VHT */ #define B43_TXH_EFT_RTSFB 0x30 /* RTS/CTS fallback encoding */ #define B43_TXH_EFT_RTSFB_CCK 0x00 /* CCK */ #define B43_TXH_EFT_RTSFB_OFDM 0x10 /* OFDM */ -#define B43_TXH_EFT_RTSFB_EWC 0x20 /* EWC */ -#define B43_TXH_EFT_RTSFB_N 0x30 /* N */ +#define B43_TXH_EFT_RTSFB_HT 0x20 /* HT */ +#define B43_TXH_EFT_RTSFB_VHT 0x30 /* VHT */ /* PHY TX control word */ #define B43_TXH_PHY_ENC 0x0003 /* Data frame encoding */ #define B43_TXH_PHY_ENC_CCK 0x0000 /* CCK */ #define B43_TXH_PHY_ENC_OFDM 0x0001 /* OFDM */ -#define B43_TXH_PHY_ENC_EWC 0x0002 /* EWC */ -#define B43_TXH_PHY_ENC_N 0x0003 /* N */ +#define B43_TXH_PHY_ENC_HT 0x0002 /* HT */ +#define B43_TXH_PHY_ENC_VHT 0x0003 /* VHT */ #define B43_TXH_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ #define B43_TXH_PHY_ANT 0x03C0 /* Antenna selection */ #define B43_TXH_PHY_ANT0 0x0000 /* Use antenna 0 */ @@ -162,7 +166,7 @@ struct b43_tx_legacy_rate_phy_ctl_entry { #define B43_TXH_PHY1_BW_20 0x0002 /* 20 MHz */ #define B43_TXH_PHY1_BW_20U 0x0003 /* 20 MHz upper */ #define B43_TXH_PHY1_BW_40 0x0004 /* 40 MHz */ -#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 50 MHz duplicate */ +#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 40 MHz duplicate */ #define B43_TXH_PHY1_MODE 0x0038 /* Mode */ #define B43_TXH_PHY1_MODE_SISO 0x0000 /* SISO */ #define B43_TXH_PHY1_MODE_CDD 0x0008 /* CDD */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 4fb9635d3919..796f5f9d5d5a 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -746,7 +746,7 @@ dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring, /* !! may be called with core in reset */ void dma_detach(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -842,7 +842,7 @@ static void _dma_rxenable(struct dma_info *di) void dma_rxinit(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -924,7 +924,7 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall) */ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct sk_buff_head dma_frames; struct sk_buff *p, *next; uint len; @@ -1022,7 +1022,7 @@ static bool dma64_txidle(struct dma_info *di) */ bool dma_rxfill(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct sk_buff *p; u16 rxin, rxout; u32 flags = 0; @@ -1106,7 +1106,7 @@ bool dma_rxfill(struct dma_pub *pub) void dma_rxreclaim(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct sk_buff *p; brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -1126,7 +1126,7 @@ void dma_counterreset(struct dma_pub *pub) /* get the address of the var in order to change later */ unsigned long dma_getvar(struct dma_pub *pub, const char *name) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); if (!strcmp(name, "&txavail")) return (unsigned long)&(di->dma.txavail); @@ -1137,7 +1137,7 @@ unsigned long dma_getvar(struct dma_pub *pub, const char *name) void dma_txinit(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); u32 control = D64_XC_XE; brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -1170,7 +1170,7 @@ void dma_txinit(struct dma_pub *pub) void dma_txsuspend(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -1182,7 +1182,7 @@ void dma_txsuspend(struct dma_pub *pub) void dma_txresume(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -1194,7 +1194,7 @@ void dma_txresume(struct dma_pub *pub) bool dma_txsuspended(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); return (di->ntxd == 0) || ((bcma_read32(di->core, @@ -1204,7 +1204,7 @@ bool dma_txsuspended(struct dma_pub *pub) void dma_txreclaim(struct dma_pub *pub, enum txd_range range) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct sk_buff *p; brcms_dbg_dma(di->core, "%s: %s\n", @@ -1225,7 +1225,7 @@ void dma_txreclaim(struct dma_pub *pub, enum txd_range range) bool dma_txreset(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); u32 status; if (di->ntxd == 0) @@ -1252,7 +1252,7 @@ bool dma_txreset(struct dma_pub *pub) bool dma_rxreset(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); u32 status; if (di->nrxd == 0) @@ -1377,7 +1377,7 @@ static void dma_update_txavail(struct dma_info *di) int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, struct sk_buff *p) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct brcms_ampdu_session *session = &di->ampdu_session; struct ieee80211_tx_info *tx_info; bool is_ampdu; @@ -1427,7 +1427,7 @@ int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, void dma_txflush(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct brcms_ampdu_session *session = &di->ampdu_session; if (!skb_queue_empty(&session->skb_list)) @@ -1436,7 +1436,7 @@ void dma_txflush(struct dma_pub *pub) int dma_txpending(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); return ntxdactive(di, di->txin, di->txout); } @@ -1446,7 +1446,7 @@ int dma_txpending(struct dma_pub *pub) */ void dma_kick_tx(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct brcms_ampdu_session *session = &di->ampdu_session; if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di)) @@ -1465,7 +1465,7 @@ void dma_kick_tx(struct dma_pub *pub) */ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); u16 start, end, i; u16 active_desc; struct sk_buff *txp; @@ -1547,7 +1547,7 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc) (void *pkt, void *arg_a), void *arg_a) { - struct dma_info *di = (struct dma_info *) dmah; + struct dma_info *di = container_of(dmah, struct dma_info, dma); uint i = di->txin; uint end = di->txout; struct sk_buff *skb; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index 57ecc05802e9..941b1e41f366 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c @@ -128,19 +128,19 @@ static const u8 ofdm_rate_lookup[] = { void wlc_phyreg_enter(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim); } void wlc_phyreg_exit(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim); } void wlc_radioreg_enter(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO); udelay(10); @@ -148,7 +148,7 @@ void wlc_radioreg_enter(struct brcms_phy_pub *pih) void wlc_radioreg_exit(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); pi->phy_wreg = 0; @@ -586,7 +586,7 @@ err: void wlc_phy_detach(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (pih) { if (--pi->refcnt) @@ -613,7 +613,7 @@ bool wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev, u16 *radioid, u16 *radiover) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); *phytype = (u16) pi->pubpi.phy_type; *phyrev = (u16) pi->pubpi.phy_rev; *radioid = pi->pubpi.radioid; @@ -624,19 +624,19 @@ wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev, bool wlc_phy_get_encore(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); return pi->pubpi.abgphy_encore; } u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); return pi->pubpi.coreflags; } void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (ISNPHY(pi)) { if (on) { @@ -673,7 +673,7 @@ void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on) u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u32 phy_bw_clkbits = 0; @@ -698,14 +698,14 @@ u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih) void wlc_phy_por_inform(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->phy_init_por = true; } void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->edcrs_threshold_lock = lock; @@ -717,14 +717,14 @@ void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->do_initcal = initcal; } void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (!pi || !pi->sh) return; @@ -734,7 +734,7 @@ void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate) void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (!pi || !pi->sh) return; @@ -746,7 +746,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec) { u32 mc; void (*phy_init)(struct brcms_phy *) = NULL; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (pi->init_in_progress) return; @@ -798,7 +798,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec) void wlc_phy_cal_init(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); void (*cal_init)(struct brcms_phy *) = NULL; if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & @@ -816,7 +816,7 @@ void wlc_phy_cal_init(struct brcms_phy_pub *pih) int wlc_phy_down(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); int callbacks = 0; if (pi->phycal_timer @@ -1070,7 +1070,7 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on) void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (set) mboolset(pi->measure_hold, id); @@ -1082,7 +1082,7 @@ void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set) void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (mute) mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE); @@ -1096,7 +1096,7 @@ void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) void wlc_phy_clear_tssi(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (ISNPHY(pi)) { return; @@ -1115,7 +1115,7 @@ static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi) void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); if (ISNPHY(pi)) { @@ -1149,35 +1149,35 @@ void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->bw; } void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->bw = bw; } void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->radio_chanspec = newch; } u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->radio_chanspec; } void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u16 m_cur_channel; void (*chanspec_set)(struct brcms_phy *, u16) = NULL; m_cur_channel = CHSPEC_CHANNEL(chanspec); @@ -1226,7 +1226,7 @@ int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec) void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, bool wide_filter) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->channel_14_wide_filter = wide_filter; @@ -1246,7 +1246,7 @@ void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, struct brcms_chanvec *channels) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); uint i; uint channel; @@ -1267,7 +1267,7 @@ wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); uint i; uint channel; u16 chspec; @@ -1311,7 +1311,7 @@ u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); *qdbm = pi->tx_user_target[0]; if (override != NULL) @@ -1323,7 +1323,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr) { bool mac_enabled = false; - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); memcpy(&pi->tx_user_target[TXP_FIRST_CCK], &txpwr->cck[0], BRCMS_NUM_RATES_CCK); @@ -1371,7 +1371,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); int i; if (qdbm > 127) @@ -1407,7 +1407,7 @@ void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr, u8 *max_pwr, int txp_rate_idx) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); uint i; *min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR; @@ -1456,7 +1456,7 @@ void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, u8 *max_txpwr, u8 *min_txpwr) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u8 tx_pwr_max = 0; u8 tx_pwr_min = 255; u8 max_num_rate; @@ -1493,14 +1493,14 @@ wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit, u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->tx_power_min; } u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->tx_power_max; } @@ -1812,21 +1812,21 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr, void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->txpwr_percent = txpwr_percent; } void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->sh->machwcap = machwcap; } void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u16 rxc; rxc = 0; @@ -1857,7 +1857,7 @@ void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, u16 chanspec) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec); @@ -1881,14 +1881,14 @@ wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->ofdm_rateset_war = war; } void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->bf_preempt_4306 = bf_preempt; } @@ -1945,7 +1945,7 @@ void wlc_phy_txpower_update_shm(struct brcms_phy *pi) bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); if (ISNPHY(pi)) return pi->nphy_txpwrctrl; @@ -1955,7 +1955,7 @@ bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); bool suspend; if (!pi->hwpwrctrl_capable) @@ -2038,7 +2038,7 @@ void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, uint channel) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); uint rate, num_rates; u8 min_pwr, max_pwr; @@ -2136,21 +2136,21 @@ wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->antsel_type = antsel_type; } bool wlc_phy_test_ison(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->phytest_on; } void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); bool suspend; pi->sh->rx_antdiv = val; @@ -2283,7 +2283,7 @@ static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi) void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u16 jssi_aux; u8 channel = 0; s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; @@ -2339,7 +2339,7 @@ void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih) static void wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; bool sampling_in_progress = (pi->phynoise_state != 0); bool wait_for_intr = true; @@ -2531,7 +2531,7 @@ int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, { int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK; uint radioid = pih->radioid; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if ((pi->sh->corerev >= 11) && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) { @@ -2591,7 +2591,7 @@ void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag) void wlc_phy_watchdog(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); bool delay_phy_cal = false; pi->sh->now++; @@ -2651,7 +2651,7 @@ void wlc_phy_watchdog(struct brcms_phy_pub *pih) void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); uint i; uint k; @@ -2711,7 +2711,7 @@ void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason) s16 nphy_currtemp = 0; s16 delta_temp = 0; bool do_periodic_cal = true; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (!ISNPHY(pi)) return; @@ -2804,7 +2804,7 @@ u8 wlc_phy_nbits(s32 value) void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->sh->hw_phytxchain = txchain; pi->sh->hw_phyrxchain = rxchain; @@ -2815,7 +2815,7 @@ void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->sh->phytxchain = txchain; @@ -2827,7 +2827,7 @@ void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); *txchain = pi->sh->phytxchain; *rxchain = pi->sh->phyrxchain; @@ -2837,7 +2837,7 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) { s16 nphy_currtemp; u8 active_bitmap; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33; @@ -2867,7 +2867,7 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u8 siso_mcs_id, cdd_mcs_id; siso_mcs_id = @@ -2944,7 +2944,7 @@ s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec) bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); if (ISNPHY(pi)) return wlc_phy_n_txpower_ipa_ison(pi); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index b2d6d6da3daf..5f1366234a0d 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -2865,7 +2865,7 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) { bool suspend, tx_gain_override_old; struct lcnphy_txgains old_gains; - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB, idleTssi0_regvalue_2C; u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); @@ -3084,7 +3084,7 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) s32 a1, b0, b1; s32 tssi, pwr, maxtargetpwr, mintargetpwr; bool suspend; - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC)); @@ -4348,7 +4348,7 @@ void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi) { s8 index; u16 index2; - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index 93869e89aa3d..084f18f4f950 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -14121,7 +14121,7 @@ static u8 ant_sw_ctrl_tbl_rev8_2057v7_core1[] = { bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u32 phybist0, phybist1, phybist2, phybist3, phybist4; if (NREV_GE(pi->pubpi.phy_rev, 16)) @@ -19734,7 +19734,7 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask) u16 regval; u16 tbl_buf[16]; uint i; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u16 tbl_opcode; bool suspend; @@ -19812,7 +19812,7 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask) u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih) { u16 regval, rxen_bits; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); regval = read_phy_reg(pi, 0xa2); rxen_bits = (regval >> 4) & 0xf; @@ -21342,7 +21342,7 @@ void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec) void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u16 mask = 0xfc00; u32 mc = 0; diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index 4e5c0f8c9496..8efd17c52f65 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -186,11 +186,9 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v) bss->ssid[i] : '_'); seq_putc(m, '\t'); - for (i = 0; i < bss->ssid_len; i++) - seq_printf(m, "%02x", bss->ssid[i]); + seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid); seq_putc(m, '\t'); - for (i = 0; i < bss->wpa_ie_len; i++) - seq_printf(m, "%02x", bss->wpa_ie[i]); + seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie); seq_putc(m, '\n'); return 0; } diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 3dcbe2cd2b28..26fec54dcd03 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; } @@ -5757,9 +5757,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; if (il->cfg->sku & IL_SKU_N) - hw->flags |= - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; + hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS | + NL80211_FEATURE_STATIC_SMPS; hw->sta_data_size = sizeof(struct il_station_priv); hw->vif_data_size = sizeof(struct il_vif_priv); diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index afb98f4fdaf3..2364a3c09b9e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -125,8 +125,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, */ if (priv->nvm_data->sku_cap_11n_enable) - hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; + hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS | + NL80211_FEATURE_STATIC_SMPS; /* * Enable 11w if advertised by firmware and software crypto diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 8e99dffa88e8..b04b8858c690 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -131,7 +131,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl7000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000 + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ + .non_shared_ant = ANT_A const struct iwl_cfg iwl7260_2ac_cfg = { @@ -220,6 +221,12 @@ static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { {0}, }; +static const struct iwl_ht_params iwl7265_ht_params = { + .stbc = true, + .ldpc = true, + .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), +}; + const struct iwl_cfg iwl3165_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 3165", .fw_name_pre = IWL3165_FW_PRE, @@ -234,7 +241,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, @@ -244,7 +251,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { .name = "Intel(R) Dual Band Wireless N 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, @@ -254,7 +261,7 @@ const struct iwl_cfg iwl7265_n_cfg = { .name = "Intel(R) Wireless N 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 23a67bfc086f..4ae8ba6ccfff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -103,6 +103,7 @@ static const struct iwl_base_params iwl8000_base_params = { }; static const struct iwl_ht_params iwl8000_ht_params = { + .ldpc = true, .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), }; @@ -115,7 +116,17 @@ static const struct iwl_ht_params iwl8000_ht_params = { .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl8000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000 + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ + .non_shared_ant = ANT_A + +const struct iwl_cfg iwl8260_2n_cfg = { + .name = "Intel(R) Dual Band Wireless N 8260", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, +}; const struct iwl_cfg iwl8260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 8260", @@ -135,6 +146,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .disable_dummy_notification = true, }; MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 3d7cc37420ae..2ef83a39ff10 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -171,6 +171,7 @@ struct iwl_base_params { /* * @stbc: support Tx STBC and 1*SS Rx STBC + * @ldpc: support Tx/Rx with LDPC * @use_rts_for_aggregation: use rts/cts protection for HT traffic * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40 */ @@ -178,6 +179,7 @@ struct iwl_ht_params { enum ieee80211_smps_mode smps_mode; const bool ht_greenfield_support; /* if used set to true */ const bool stbc; + const bool ldpc; bool use_rts_for_aggregation; u8 ht40_bands; }; @@ -228,6 +230,7 @@ struct iwl_pwr_tx_backoff { * @max_data_size: The maximal length of the fw data section * @valid_tx_ant: valid transmit antenna * @valid_rx_ant: valid receive antenna + * @non_shared_ant: the antenna that is for WiFi only * @nvm_ver: NVM version * @nvm_calib_ver: NVM calibration version * @lib: pointer to the lib ops @@ -260,6 +263,7 @@ struct iwl_cfg { const u32 max_inst_size; u8 valid_tx_ant; u8 valid_rx_ant; + u8 non_shared_ant; bool bt_shared_single_ant; u16 nvm_ver; u16 nvm_calib_ver; @@ -280,6 +284,7 @@ struct iwl_cfg { bool no_power_up_nic_in_init; const char *default_nvm_file; unsigned int max_rx_agg_size; + bool disable_dummy_notification; }; /* @@ -341,6 +346,7 @@ extern const struct iwl_cfg iwl3165_2ac_cfg; extern const struct iwl_cfg iwl7265_2ac_cfg; extern const struct iwl_cfg iwl7265_2n_cfg; extern const struct iwl_cfg iwl7265_n_cfg; +extern const struct iwl_cfg iwl8260_2n_cfg; extern const struct iwl_cfg iwl8260_2ac_cfg; extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 23d059af6476..3f6f015285e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -295,6 +295,16 @@ #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) + +/** + * hw_rev values + */ +enum { + SILICON_A_STEP = 0, + SILICON_B_STEP, +}; + + #define CSR_HW_REV_TYPE_MSK (0x000FFF0) #define CSR_HW_REV_TYPE_5300 (0x0000020) #define CSR_HW_REV_TYPE_5350 (0x0000030) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index aefd94cb6e91..ed673baedfd7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1363,7 +1363,7 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)") module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, int, S_IRUGO); MODULE_PARM_DESC(antenna_coupling, - "specify antenna coupling in dB (defualt: 0 dB)"); + "specify antenna coupling in dB (default: 0 dB)"); module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); MODULE_PARM_DESC(wd_disable, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 07ff7e0028ee..74b796dc4242 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -758,6 +758,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; } + if (cfg->ht_params->ldpc) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + if (iwlwifi_mod_params.amsdu_size_8K) ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index f68cba4e0444..62c46eb8b99c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -127,6 +127,7 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. + * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. */ @@ -137,6 +138,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), + IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), }; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 5eef4ae7333b..7a2cbf6f90db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -193,7 +193,7 @@ void iwl_force_nmi(struct iwl_trans *trans) * DEVICE_SET_NMI_8000B_REG - is used. */ if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || - ((trans->hw_rev & 0xc) == 0x0)) + (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL); else iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 40718f814f8d..c302e7468559 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -334,6 +334,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; + if (cfg->ht_params->ldpc) + vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; + if (num_tx_ants > 1) vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; else diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index c89985a58803..9eb85249e89c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -377,6 +377,7 @@ enum iwl_trans_status { * if unset 4k will be the RX buffer size * @bc_table_dword: set to true if the BC table expects the byte count to be * in DWORD (as opposed to bytes) + * @scd_set_active: should the transport configure the SCD for HCMD queue * @queue_watchdog_timeout: time (in ms) after which queues * are considered stuck and will trigger device restart * @command_names: array of command names, must be 256 entries @@ -392,6 +393,7 @@ struct iwl_trans_config { bool rx_buf_size_8k; bool bc_table_dword; + bool scd_set_active; unsigned int queue_watchdog_timeout; const char *const *command_names; }; @@ -826,12 +828,6 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); } -static inline void -iwl_trans_txq_enable_no_scd(struct iwl_trans *trans, int queue, u16 ssn) -{ - iwl_trans_txq_enable_cfg(trans, queue, ssn, NULL); -} - static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, u32 txq_bm) { diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index a28235913c2c..2d7c3ea3c4f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o iwlmvm-y += power.o coex.o coex_legacy.o -iwlmvm-y += tt.o offloading.o +iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 6e8f3e2aef74..8df2021f9856 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -1146,6 +1146,10 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) { + /* there is no other antenna, shared antenna is always available */ + if (mvm->cfg->bt_shared_single_ant) + return true; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index dd00e8f7f765..a355788b1166 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -65,12 +65,18 @@ #ifndef __MVM_CONSTANTS_H #define __MVM_CONSTANTS_H +#include <linux/ieee80211.h> + #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) +#define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8 #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 @@ -86,5 +92,7 @@ #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_CORUNNING 1 #define IWL_MVM_BT_COEX_MPLUT 1 +#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 +#define IWL_MVM_QUOTA_THRESHOLD 8 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index d98ee109c5e9..95eb9a5ef693 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -288,6 +288,9 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, { int temperature; + if (!mvm->ucode_loaded && !mvm->temperature_test) + return -EIO; + if (kstrtoint(buf, 10, &temperature)) return -EINVAL; /* not a legal temperature */ @@ -1256,6 +1259,18 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); PRINT_MVM_REF(IWL_MVM_REF_USER); + PRINT_MVM_REF(IWL_MVM_REF_TX); + PRINT_MVM_REF(IWL_MVM_REF_TX_AGG); + PRINT_MVM_REF(IWL_MVM_REF_ADD_IF); + PRINT_MVM_REF(IWL_MVM_REF_START_AP); + PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED); + PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX); + PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS); + PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL); + PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ); + PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE); + PRINT_MVM_REF(IWL_MVM_REF_NMI); + PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 541b844c6b5d..a2c662808a88 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -205,6 +205,10 @@ enum { REPLY_SF_CFG_CMD = 0xd1, REPLY_BEACON_FILTERING_CMD = 0xd2, + /* DTS measurements */ + CMD_DTS_MEASUREMENT_TRIGGER = 0xdc, + DTS_MEASUREMENT_NOTIFICATION = 0xdd, + REPLY_DEBUG_CMD = 0xf0, DEBUG_LOG_MSG = 0xf7, @@ -550,7 +554,7 @@ enum iwl_time_event_type { TE_WIDI_TX_SYNC, /* Channel Switch NoA */ - TE_P2P_GO_CSA_NOA, + TE_CHANNEL_SWITCH_PERIOD, TE_MAX }; /* MAC_EVENT_TYPE_API_E_VER_1 */ @@ -1601,6 +1605,8 @@ enum iwl_sf_scenario { #define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ +#define SF_CFG_DUMMY_NOTIF_OFF BIT(16) + /** * Smart Fifo configuration command. * @state: smart fifo state, types listed in enum %iwl_sf_sate. @@ -1616,4 +1622,32 @@ struct iwl_sf_cfg_cmd { __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; } __packed; /* SF_CFG_API_S_VER_2 */ +/* DTS measurements */ + +enum iwl_dts_measurement_flags { + DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0), + DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1), +}; + +/** + * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements + * + * @flags: indicates which measurements we want as specified in &enum + * iwl_dts_measurement_flags + */ +struct iwl_dts_measurement_cmd { + __le32 flags; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */ + +/** + * iwl_dts_measurement_notif - notification received with the measurements + * + * @temp: the measured temperature + * @voltage: the measured voltage + */ +struct iwl_dts_measurement_notif { + __le32 temp; + __le32 voltage; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 21d606028ca6..23fd711a67e4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -454,6 +454,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) for (i = 0; i < IWL_MVM_STATION_COUNT; i++) RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); + /* reset quota debouncing buffer - 0xff will yield invalid data */ + memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); + /* Add auxiliary station for scanning */ ret = iwl_mvm_add_aux_sta(mvm); if (ret) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 158aed501473..834267145929 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1234,13 +1234,13 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { u32 rel_time = (c + 1) * csa_vif->bss_conf.beacon_int - - IWL_MVM_CHANNEL_SWITCH_TIME; + IWL_MVM_CHANNEL_SWITCH_TIME_GO; u32 apply_time = gp2 + rel_time * 1024; - iwl_mvm_schedule_csa_noa(mvm, csa_vif, - IWL_MVM_CHANNEL_SWITCH_TIME - - IWL_MVM_CHANNEL_SWITCH_MARGIN, - apply_time); + iwl_mvm_schedule_csa_period(mvm, csa_vif, + IWL_MVM_CHANNEL_SWITCH_TIME_GO - + IWL_MVM_CHANNEL_SWITCH_MARGIN, + apply_time); } } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { /* we don't have CSA NoA scheduled yet, switch now */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 069bb8e81c36..4c2121094a0b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -303,9 +303,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TIMING_BEACON_ONLY | IEEE80211_HW_CONNECTION_MONITOR | - IEEE80211_HW_CHANCTX_STA_CSA | - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; + IEEE80211_HW_CHANCTX_STA_CSA; hw->queues = mvm->first_agg_queue; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; @@ -327,7 +325,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 && !iwlwifi_mod_params.uapsd_disable) { hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; - hw->uapsd_queues = IWL_UAPSD_AC_INFO; + hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; } @@ -409,7 +407,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | NL80211_FEATURE_LOW_PRIORITY_SCAN | - NL80211_FEATURE_P2P_GO_OPPPS; + NL80211_FEATURE_P2P_GO_OPPPS | + NL80211_FEATURE_DYNAMIC_SMPS | + NL80211_FEATURE_STATIC_SMPS; mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; @@ -670,8 +670,9 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, } #ifdef CONFIG_IWLWIFI_DEBUGFS -static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) +void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { + static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; @@ -763,20 +764,16 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) file_len += fw_error_dump->trans_ptr->len; dump_file->file_len = cpu_to_le32(file_len); mvm->fw_error_dump = fw_error_dump; + + /* notify the userspace about the error we had */ + kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); } #endif static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { -#ifdef CONFIG_IWLWIFI_DEBUGFS - static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; - iwl_mvm_fw_error_dump(mvm); - /* notify the userspace about the error we had */ - kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); -#endif - iwl_trans_stop_device(mvm->trans); mvm->scan_status = IWL_MVM_SCAN_NONE; @@ -815,12 +812,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->rx_ba_sessions = 0; } -static int iwl_mvm_mac_start(struct ieee80211_hw *hw) +int __iwl_mvm_mac_start(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; - mutex_lock(&mvm->mutex); + lockdep_assert_held(&mvm->mutex); /* Clean up some internal and mac80211 state on restart */ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) @@ -837,6 +833,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) iwl_mvm_d0i3_enable_tx(mvm, NULL); } + return ret; +} + +static int iwl_mvm_mac_start(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + mutex_lock(&mvm->mutex); + ret = __iwl_mvm_mac_start(mvm); mutex_unlock(&mvm->mutex); return ret; @@ -862,14 +868,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) mutex_unlock(&mvm->mutex); } -static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) +void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - flush_work(&mvm->d0i3_exit_work); - flush_work(&mvm->async_handlers_wk); - - mutex_lock(&mvm->mutex); + lockdep_assert_held(&mvm->mutex); /* disallow low power states when the FW is down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); @@ -890,6 +891,19 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) /* the fw is stopped, the aux sta is dead: clean up driver state */ iwl_mvm_del_aux_sta(mvm); + mvm->ucode_loaded = false; +} + +static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + flush_work(&mvm->d0i3_exit_work); + flush_work(&mvm->async_handlers_wk); + flush_work(&mvm->fw_error_dump_wk); + + mutex_lock(&mvm->mutex); + __iwl_mvm_mac_stop(mvm); mutex_unlock(&mvm->mutex); /* @@ -1198,14 +1212,15 @@ static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mcast_filter_cmd *cmd; struct netdev_hw_addr *addr; - int addr_count = netdev_hw_addr_list_count(mc_list); - bool pass_all = false; + int addr_count; + bool pass_all; int len; - if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) { - pass_all = true; + addr_count = netdev_hw_addr_list_count(mc_list); + pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES || + IWL_MVM_FW_MCAST_FILTER_PASS_ALL; + if (pass_all) addr_count = 0; - } len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4); cmd = kzalloc(len, GFP_ATOMIC); @@ -1405,28 +1420,6 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, } #endif -static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) -{ - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - int i; - - lockdep_assert_held(&mvm->mutex); - - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], - lockdep_is_held(&mvm->mutex)); - if (!sta || IS_ERR(sta) || !sta->tdls) - continue; - - mvmsta = iwl_mvm_sta_from_mac80211(sta); - ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, - NL80211_TDLS_TEARDOWN, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, - GFP_KERNEL); - } -} - static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1724,7 +1717,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, return; if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | - BSS_CHANGED_BANDWIDTH) && + BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) && iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL)) IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); @@ -1955,48 +1948,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - int count = 0; - int i; - - lockdep_assert_held(&mvm->mutex); - - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], - lockdep_is_held(&mvm->mutex)); - if (!sta || IS_ERR(sta) || !sta->tdls) - continue; - - if (vif) { - mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (mvmsta->vif != vif) - continue; - } - - count++; - } - - return count; -} - -static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - bool sta_added) -{ - int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); - - /* - * Disable ps when the first TDLS sta is added and re-enable it - * when the last TDLS sta is removed - */ - if ((tdls_sta_cnt == 1 && sta_added) || - (tdls_sta_cnt == 0 && !sta_added)) - iwl_mvm_power_update_mac(mvm); -} - static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2170,27 +2121,6 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); } -static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; - - /* - * iwl_mvm_protect_session() reads directly from the device - * (the system time), so make sure it is available. - */ - if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) - return; - - mutex_lock(&mvm->mutex); - /* Protect the session to hear the TDLS setup response on the channel */ - iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); - mutex_unlock(&mvm->mutex); - - iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); -} - static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e292de96e09a..552995810f9e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -87,11 +87,11 @@ /* A TimeUnit is 1024 microsecond */ #define MSEC_TO_TU(_msec) (_msec*1000/1024) -/* - * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" - * TBTT. This value should be big enough to ensure that we switch in time. +/* This value represents the number of TUs before CSA "beacon 0" TBTT + * when the CSA time-event needs to be scheduled to start. It must be + * big enough to ensure that we switch in time. */ -#define IWL_MVM_CHANNEL_SWITCH_TIME 40 +#define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40 /* * This value (in TUs) is used to fine tune the CSA NoA end time which should @@ -180,10 +180,6 @@ enum iwl_power_scheme { }; #define IWL_CONN_MAX_LISTEN_INTERVAL 10 -#define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -274,6 +270,8 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_TM_CMD, IWL_MVM_REF_EXIT_WORK, + /* update debugfs.c when changing this */ + IWL_MVM_REF_COUNT, }; @@ -649,6 +647,7 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; + struct work_struct fw_error_dump_wk; struct iwl_mvm_dump_ptrs *fw_error_dump; #ifdef CONFIG_IWLWIFI_LEDS @@ -709,6 +708,8 @@ struct iwl_mvm { */ bool temperature_test; /* Debug test temperature is enabled */ + struct iwl_time_quota_cmd last_quota_cmd; + #ifdef CONFIG_NL80211_TESTMODE u32 noa_duration; struct ieee80211_vif *noa_vif; @@ -788,6 +789,9 @@ struct iwl_rate_info { u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ }; +void __iwl_mvm_mac_stop(struct iwl_mvm *mvm); +int __iwl_mvm_mac_start(struct iwl_mvm *mvm); + /****************** * MVM Methods ******************/ @@ -1153,7 +1157,17 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* TDLS */ int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm); +void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool sta_added); +void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); +#ifdef CONFIG_IWLWIFI_DEBUGFS +void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +#else +static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {} +#endif #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 4fafd4bd89f4..af074563e770 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -64,6 +64,7 @@ *****************************************************************************/ #include <linux/firmware.h> #include "iwl-trans.h" +#include "iwl-csr.h" #include "mvm.h" #include "iwl-eeprom-parse.h" #include "iwl-eeprom-read.h" @@ -349,7 +350,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) /* Maximal size depends on HW family and step */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) max_section_size = IWL_MAX_NVM_SECTION_SIZE; - else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */ + else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; else /* Family 8000 B-step */ max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 87f278cc9b2c..f887779717d5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -332,6 +332,8 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(BCAST_FILTER_CMD), CMD(REPLY_SF_CFG_CMD), CMD(REPLY_BEACON_FILTERING_CMD), + CMD(CMD_DTS_MEASUREMENT_TRIGGER), + CMD(DTS_MEASUREMENT_NOTIFICATION), CMD(REPLY_THERMAL_MNG_BACKOFF), CMD(MAC_PM_POWER_TABLE), CMD(BT_COEX_CI), @@ -364,6 +366,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) return 0; } +static void iwl_mvm_fw_error_dump_wk(struct work_struct *work); + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -431,6 +435,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); + INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk); spin_lock_init(&mvm->d0i3_tx_lock); spin_lock_init(&mvm->refs_lock); @@ -460,6 +465,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; + trans_cfg.scd_set_active = true; snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), @@ -781,6 +787,16 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk) module_put(THIS_MODULE); } +static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) +{ + struct iwl_mvm *mvm = + container_of(work, struct iwl_mvm, fw_error_dump_wk); + + mutex_lock(&mvm->mutex); + iwl_mvm_fw_error_dump(mvm); + mutex_unlock(&mvm->mutex); +} + void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) { iwl_abort_notification_waits(&mvm->notif_wait); @@ -846,6 +862,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) if (fw_error && mvm->restart_fw > 0) mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); + } else if (fw_error) { + schedule_work(&mvm->fw_error_dump_wk); } } diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 5a29c193b72a..5b85b0cc7a2a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -286,12 +286,28 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, return true; } +static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; + bool radar_detect = false; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(vif->chanctx_conf); + WARN_ON(!chanctx_conf); + if (chanctx_conf) { + chan = chanctx_conf->def.chan; + radar_detect = chan->flags & IEEE80211_CHAN_RADAR; + } + rcu_read_unlock(); + + return radar_detect; +} + static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mac_power_cmd *cmd) { - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan; int dtimper, dtimper_msec; int keep_alive; bool radar_detect = false; @@ -320,7 +336,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || - !mvmvif->pm_enabled) + !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif)) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); @@ -333,14 +349,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, } /* Check if radar detection is required on current channel */ - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); - WARN_ON(!chanctx_conf); - if (chanctx_conf) { - chan = chanctx_conf->def.chan; - radar_detect = chan->flags & IEEE80211_CHAN_RADAR; - } - rcu_read_unlock(); + radar_detect = iwl_mvm_power_is_radar(vif); /* Check skip over DTIM conditions */ if (!radar_detect && (dtimper <= 10) && @@ -501,8 +510,6 @@ struct iwl_power_vifs { bool bss_active; bool ap_active; bool monitor_active; - bool bss_tdls; - bool p2p_tdls; }; static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, @@ -557,8 +564,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, /* only a single MAC of the same type */ WARN_ON(power_iterator->p2p_vif); power_iterator->p2p_vif = vif; - power_iterator->p2p_tdls = - !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->p2p_active = true; @@ -568,8 +573,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, /* only a single MAC of the same type */ WARN_ON(power_iterator->bss_vif); power_iterator->bss_vif = vif; - power_iterator->bss_tdls = - !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->bss_active = true; @@ -612,15 +615,13 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); /* enable PM on bss if bss stand alone */ - if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active && - !vifs->bss_tdls) { + if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { bss_mvmvif->pm_enabled = true; return; } /* enable PM on p2p if p2p stand alone */ - if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active && - !vifs->p2p_tdls) { + if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) p2p_mvmvif->pm_enabled = true; return; @@ -961,17 +962,22 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, iwl_mvm_power_build_cmd(mvm, vif, &cmd); if (enable) { - /* configure skip over dtim up to 300 msec */ + /* configure skip over dtim up to 306TU - 314 msec */ int dtimper = vif->bss_conf.dtim_period ?: 1; - int dtimper_msec = dtimper * vif->bss_conf.beacon_int; + int dtimper_tu = dtimper * vif->bss_conf.beacon_int; + bool radar_detect = iwl_mvm_power_is_radar(vif); - if (WARN_ON(!dtimper_msec)) + if (WARN_ON(!dtimper_tu)) return 0; - cmd.skip_dtim_periods = 300 / dtimper_msec; - if (cmd.skip_dtim_periods) - cmd.flags |= - cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + /* Check skip over DTIM conditions */ + /* TODO: check that multicast wake lock is off */ + if (!radar_detect && (dtimper < 10)) { + cmd.skip_dtim_periods = 306 / dtimper_tu; + if (cmd.skip_dtim_periods) + cmd.flags |= cpu_to_le16( + POWER_FLAGS_SKIP_OVER_DTIM_MSK); + } } iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 5fd502db03d1..dbb2594390e9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -175,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *disabled_vif) { struct iwl_time_quota_cmd cmd = {}; - int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; + int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat; struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, .colors = { -1, -1, -1, -1 }, .disabled_vif = disabled_vif, }; + struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd; + bool send = false; lockdep_assert_held(&mvm->mutex); @@ -293,15 +295,33 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, /* check that we have non-zero quota for all valid bindings */ for (i = 0; i < MAX_BINDINGS; i++) { + if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color) + send = true; + if (cmd.quotas[i].max_duration != last->quotas[i].max_duration) + send = true; + if (abs((int)le32_to_cpu(cmd.quotas[i].quota) - + (int)le32_to_cpu(last->quotas[i].quota)) + > IWL_MVM_QUOTA_THRESHOLD) + send = true; if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID)) continue; WARN_ONCE(cmd.quotas[i].quota == 0, "zero quota on binding %d\n", i); } - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to send quota: %d\n", ret); - return ret; + if (!send) { + /* don't send a practically unchanged command, the firmware has + * to re-initialize a lot of state and that can have an adverse + * impact on it + */ + return 0; + } + + err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd); + + if (err) + IWL_ERR(mvm, "Failed to send quota: %d\n", err); + else + mvm->last_quota_cmd = cmd; + return err; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 17002cf437db..f77dfe4df074 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -505,10 +505,10 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, const char *prefix) { - IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n", + IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n", prefix, rs_pretty_lq_type(rate->type), rate->index, rs_pretty_ant(rate->ant), - rate->bw, rate->sgi); + rate->bw, rate->sgi, rate->ldpc); } static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) @@ -672,8 +672,10 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, return -EINVAL; if (tbl->column != RS_COLUMN_INVALID) { - lq_sta->tx_stats[tbl->column][scale_index].total += attempts; - lq_sta->tx_stats[tbl->column][scale_index].success += successes; + struct lq_sta_pers *pers = &lq_sta->pers; + + pers->tx_stats[tbl->column][scale_index].total += attempts; + pers->tx_stats[tbl->column][scale_index].success += successes; } /* Select window for current tx bit rate */ @@ -742,6 +744,8 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, ucode_rate |= rate->bw; if (rate->sgi) ucode_rate |= RATE_MCS_SGI_MSK; + if (rate->ldpc) + ucode_rate |= RATE_MCS_LDPC_MSK; return ucode_rate; } @@ -779,6 +783,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, /* HT or VHT */ if (ucode_rate & RATE_MCS_SGI_MSK) rate->sgi = true; + if (ucode_rate & RATE_MCS_LDPC_MSK) + rate->ldpc = true; rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; @@ -965,13 +971,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, rate->index > IWL_RATE_MCS_9_INDEX); rate->index = rs_ht_to_legacy[rate->index]; + rate->ldpc = false; } else { /* Downgrade to SISO with same MCS if in MIMO */ rate->type = is_vht_mimo2(rate) ? LQ_VHT_SISO : LQ_HT_SISO; } - if (num_of_ant(rate->ant) > 1) rate->ant = first_antenna(mvm->fw->valid_tx_ant); @@ -1621,6 +1627,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, } rate->bw = rs_bw_from_sta_bw(sta); + rate->ldpc = lq_sta->ldpc; search_tbl->column = col_id; rs_set_expected_tpt_table(lq_sta, search_tbl); @@ -2031,18 +2038,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, return; } - /* force user max rate if set by user */ - if ((lq_sta->max_rate_idx != -1) && - (lq_sta->max_rate_idx < index)) { - index = lq_sta->max_rate_idx; - update_lq = 1; - window = &(tbl->win[index]); - IWL_DEBUG_RATE(mvm, - "Forcing user max rate %d\n", - index); - goto lq_update; - } - + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ window = &(tbl->win[index]); /* @@ -2130,10 +2126,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, low = high_low & 0xff; high = (high_low >> 8) & 0xff; - /* If user set max rate, dont allow higher than user constrain */ - if ((lq_sta->max_rate_idx != -1) && - (lq_sta->max_rate_idx < high)) - high = IWL_RATE_INVALID; + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ sr = window->success_ratio; @@ -2342,6 +2335,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rate->index = i; rate->ant = first_antenna(valid_tx_ant); rate->sgi = false; + rate->ldpc = false; rate->bw = RATE_MCS_CHAN_WIDTH_20; if (band == IEEE80211_BAND_5GHZ) rate->type = LQ_LEGACY_A; @@ -2364,23 +2358,13 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, struct ieee80211_tx_rate_control *txrc) { struct sk_buff *skb = txrc->skb; - struct ieee80211_supported_band *sband = txrc->sband; struct iwl_op_mode *op_mode __maybe_unused = (struct iwl_op_mode *)mvm_r; struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = mvm_sta; - /* Get max rate if user set max rate */ - if (lq_sta) { - lq_sta->max_rate_idx = txrc->max_rate_idx; - if ((sband->band == IEEE80211_BAND_5GHZ) && - (lq_sta->max_rate_idx != -1)) - lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE; - if ((lq_sta->max_rate_idx < 0) || - (lq_sta->max_rate_idx >= IWL_RATE_COUNT)) - lq_sta->max_rate_idx = -1; - } + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ /* Treat uninitialized rate scaling data same as non-existing. */ if (lq_sta && !lq_sta->pers.drv) { @@ -2581,7 +2565,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ - lq_sta->max_rate_idx = -1; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; lq_sta->band = sband->band; /* @@ -2610,9 +2593,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; lq_sta->is_vht = false; + if (mvm->cfg->ht_params->ldpc && + (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) + lq_sta->ldpc = true; } else { rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); lq_sta->is_vht = true; + + if (mvm->cfg->ht_params->ldpc && + (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) + lq_sta->ldpc = true; } lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, @@ -2622,11 +2612,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, BITS_PER_LONG); - IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n", + IWL_DEBUG_RATE(mvm, + "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n", lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, - lq_sta->is_vht); + lq_sta->is_vht, lq_sta->ldpc); IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", lq_sta->max_legacy_rate_idx, lq_sta->max_siso_rate_idx, @@ -3032,8 +3023,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_ht20(rate)) ? "20MHz" : (is_ht40(rate)) ? "40MHz" : (is_ht80(rate)) ? "80Mhz" : "BAD BW"); - desc += sprintf(buff+desc, " %s %s\n", + desc += sprintf(buff+desc, " %s %s %s\n", (rate->sgi) ? "SGI" : "NGI", + (rate->ldpc) ? "LDPC" : "BCC", (lq_sta->is_agg) ? "AGG on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", @@ -3181,7 +3173,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file, "%s,", column_name[col]); for (rate = 0; rate < IWL_RATE_COUNT; rate++) { - stats = &(lq_sta->tx_stats[col][rate]); + stats = &(lq_sta->pers.tx_stats[col][rate]); pos += scnprintf(pos, endpos - pos, "%llu/%llu,", stats->success, @@ -3200,7 +3192,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_lq_sta *lq_sta = file->private_data; - memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats)); + memset(lq_sta->pers.tx_stats, 0, sizeof(lq_sta->pers.tx_stats)); return count; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index f27b9d687a25..95c4b960fd71 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -207,6 +207,7 @@ struct rs_rate { u8 ant; u32 bw; bool sgi; + bool ldpc; }; @@ -329,10 +330,9 @@ struct iwl_lq_sta { */ u64 last_tx; bool is_vht; + bool ldpc; /* LDPC Rx is supported by the STA */ enum ieee80211_band band; - struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; - /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ unsigned long active_legacy_rate; unsigned long active_siso_rate; @@ -343,7 +343,6 @@ struct iwl_lq_sta { u8 max_siso_rate_idx; u8 max_mimo2_rate_idx; - s8 max_rate_idx; /* Max rate set by user */ u8 missed_rate_counter; struct iwl_lq_cmd lq; @@ -361,11 +360,14 @@ struct iwl_lq_sta { int tpc_reduce; /* persistent fields - initialized only once - keep last! */ - struct { + struct lq_sta_pers { #ifdef CONFIG_MAC80211_DEBUGFS u32 dbg_fixed_rate; u8 dbg_fixed_txp_reduction; #endif + u8 chains; + s8 chain_signal[IEEE80211_MAX_CHAINS]; + struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; struct iwl_mvm *drv; } pers; }; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index bf9c63dc4a7d..09545f23b24f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -160,8 +160,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid, static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) { if (band == IEEE80211_BAND_2GHZ) - return 30 + 3 * (n_ssids + 1); - return 20 + 2 * (n_ssids + 1); + return 20 + 3 * (n_ssids + 1); + return 10 + 2 * (n_ssids + 1); } static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index f88410c7cbfb..7eb78e2c240a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -179,6 +179,10 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, struct ieee80211_sta *sta; int ret = 0; + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF && + mvm->cfg->disable_dummy_notification) + sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); + /* * If an associated AP sta changed its antenna configuration, the state * will remain FULL_ON but SF parameters need to be reconsidered. diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index dd9f3a4347f6..666f16b4bed9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -948,8 +948,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } tid_data->ssn = 0xffff; + tid_data->state = IWL_AGG_OFF; + mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE; + spin_unlock_bh(&mvmsta->lock); + + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + + iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); + iwl_trans_txq_disable(mvm->trans, txq_id, true); - /* fall through */ + return 0; case IWL_AGG_STARTING: case IWL_EMPTYING_HW_QUEUE_ADDBA: /* @@ -1003,6 +1011,8 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); + iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true); } diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c new file mode 100644 index 000000000000..66c82df2d0a1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Mobile Communications GmbH + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Mobile Communications GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include "mvm.h" +#include "time-event.h" + +void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, + GFP_KERNEL); + } +} + +int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + int count = 0; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + if (vif) { + mvmsta = iwl_mvm_sta_from_mac80211(sta); + if (mvmsta->vif != vif) + continue; + } + + count++; + } + + return count; +} + +void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool sta_added) +{ + int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); + + /* + * Disable ps when the first TDLS sta is added and re-enable it + * when the last TDLS sta is removed + */ + if ((tdls_sta_cnt == 1 && sta_added) || + (tdls_sta_cnt == 0 && !sta_added)) + iwl_mvm_power_update_mac(mvm); +} + +void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; + + /* + * iwl_mvm_protect_session() reads directly from the device + * (the system time), so make sure it is available. + */ + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) + return; + + mutex_lock(&mvm->mutex); + /* Protect the session to hear the TDLS setup response on the channel */ + iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); + mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); +} diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 447d3b1003df..b7f9e61d14e2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -700,9 +700,9 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) iwl_mvm_roc_finished(mvm); } -int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 duration, u32 apply_time) +int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 apply_time) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; @@ -711,14 +711,14 @@ int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); if (te_data->running) { - IWL_DEBUG_TE(mvm, "CS NOA is already scheduled\n"); + IWL_DEBUG_TE(mvm, "CS period is already scheduled\n"); return -EBUSY; } time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); time_cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); - time_cmd.id = cpu_to_le32(TE_P2P_GO_CSA_NOA); + time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD); time_cmd.apply_time = cpu_to_le32(apply_time); time_cmd.max_frags = TE_V2_FRAG_NONE; time_cmd.duration = cpu_to_le32(duration); diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index bee3b2446b35..b350e47e19da 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -219,7 +219,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, void iwl_mvm_roc_done_wk(struct work_struct *wk); /** - * iwl_mvm_schedule_csa_noa - request NoA for channel switch + * iwl_mvm_schedule_csa_period - request channel switch absence period * @mvm: the mvm component * @vif: the virtual interface for which the channel switch is issued * @duration: the duration of the NoA in TU. @@ -228,9 +228,9 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk); * This function is used to schedule NoA time event and is used to perform * the channel switch flow. */ -int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 duration, u32 apply_time); +int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 apply_time); /** * iwl_mvm_te_scheduled - check if the fw received the TE cmd diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index c3e1fe4282f1..c750ca7b8269 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -69,275 +69,99 @@ #include "iwl-csr.h" #include "iwl-prph.h" -#define OTP_DTS_DIODE_DEVIATION 96 /*in words*/ -/* VBG - Voltage Band Gap error data (temperature offset) */ -#define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2) -#define MEAS_VBG_MIN_VAL 2300 -#define MEAS_VBG_MAX_VAL 3000 -#define MEAS_VBG_DEFAULT_VAL 2700 -#define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE) -#define MIN_TEMPERATURE 0 -#define MAX_TEMPERATURE 125 -#define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1) -#define PTAT_DIGITAL_VALUE_MIN_VALUE 0 -#define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF -#define DTS_VREFS_NUM 5 -static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags) -{ - return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >> - DTS_DIODE_REG_FLAGS_VREFS_ID_POS; -} +#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ -#define CALC_VREFS_MIN_DIFF 43 -#define CALC_VREFS_MAX_DIFF 51 -#define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF) -#define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF -#define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23 - -/* - * @digital_value: The diode's digital-value sampled (temperature/voltage) - * @vref_low: The lower voltage-reference (the vref just below the diode's - * sampled digital-value) - * @vref_high: The higher voltage-reference (the vref just above the diode's - * sampled digital-value) - * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref) - * bits[6:2]: Reserved. - * bits[7:7]: Indicates completion of at least 1 successful sample - * since last DTS reset. - */ -struct iwl_mvm_dts_diode_bits { - u8 digital_value; - u8 vref_low; - u8 vref_high; - u8 flags; -} __packed; - -union dts_diode_results { - u32 reg_value; - struct iwl_mvm_dts_diode_bits bits; -} __packed; - -static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm) +static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) { - struct iwl_nvm_section calib_sec; - const __le16 *calib; - u16 vbg; - - /* TODO: move parsing to NVM code */ - calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION]; - calib = (__le16 *)calib_sec.data; + u32 duration = mvm->thermal_throttle.params->ct_kill_duration; - vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]); + if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) + return; - if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL) - vbg = MEAS_VBG_DEFAULT_VAL; + IWL_ERR(mvm, "Enter CT Kill\n"); + iwl_mvm_set_hw_ctkill_state(mvm, true); - return vbg; + /* Don't schedule an exit work if we're in test mode, since + * the temperature will not change unless we manually set it + * again (or disable testing). + */ + if (!mvm->temperature_test) + schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, + round_jiffies_relative(duration * HZ)); } -static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) +static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) { - const u8 *calib; - u8 ptat, pa1, pa2, median; - - /* TODO: move parsing to NVM code */ - calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; - ptat = calib[OTP_DTS_DIODE_DEVIATION * 2]; - pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1]; - pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2]; - - /* get the median: */ - if (ptat > pa1) { - if (ptat > pa2) - median = (pa1 > pa2) ? pa1 : pa2; - else - median = ptat; - } else { - if (pa1 > pa2) - median = (ptat > pa2) ? ptat : pa2; - else - median = pa1; - } + if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) + return; - return ptat - median; + IWL_ERR(mvm, "Exit CT Kill\n"); + iwl_mvm_set_hw_ctkill_state(mvm, false); } -static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value) +static bool iwl_mvm_temp_notif(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) { - /* Calibrate the PTAT digital value, based on PTAT deviation data: */ - s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm); + struct iwl_mvm *mvm = + container_of(notif_wait, struct iwl_mvm, notif_wait); + int *temp = data; + struct iwl_dts_measurement_notif *notif; + int len = iwl_rx_packet_payload_len(pkt); + + if (WARN_ON_ONCE(len != sizeof(*notif))) { + IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); + return true; + } - if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE) - new_val = PTAT_DIGITAL_VALUE_MAX_VALUE; - else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE) - new_val = PTAT_DIGITAL_VALUE_MIN_VALUE; + notif = (void *)pkt->data; - return new_val; -} + *temp = le32_to_cpu(notif->temp); -static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm, - union dts_diode_results *avg_ptat) -{ - u8 vrefs_results[DTS_VREFS_NUM]; - u8 low_vref_index = 0, flags; - u32 reg; - - reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG); - memcpy(vrefs_results, ®, sizeof(reg)); - reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG); - vrefs_results[4] = reg & 0xff; - - if (avg_ptat->bits.digital_value < vrefs_results[0] || - avg_ptat->bits.digital_value > vrefs_results[4]) - return false; - - if (avg_ptat->bits.digital_value > vrefs_results[3]) - low_vref_index = 3; - else if (avg_ptat->bits.digital_value > vrefs_results[2]) - low_vref_index = 2; - else if (avg_ptat->bits.digital_value > vrefs_results[1]) - low_vref_index = 1; - - avg_ptat->bits.vref_low = vrefs_results[low_vref_index]; - avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1]; - flags = avg_ptat->bits.flags; - avg_ptat->bits.flags = - (flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) | - (low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID); - return true; -} + /* shouldn't be negative, but since it's s32, make sure it isn't */ + if (WARN_ON_ONCE(*temp < 0)) + *temp = 0; -/* - * return true it the results are valid, and false otherwise. - */ -static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm, - union dts_diode_results *avg_ptat) -{ - u32 reg; - u8 tmp; - - /* fill the diode value and pass_once with avg-reg results */ - reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG); - reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE; - avg_ptat->reg_value = reg; - - /* calibrate the PTAT digital value */ - tmp = avg_ptat->bits.digital_value; - tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp); - avg_ptat->bits.digital_value = tmp; - - /* - * fill vrefs fields, based on the avgVrefs results - * and the diode value - */ - return dts_get_adjacent_vrefs(mvm, avg_ptat) && - DTS_DIODE_VALID(avg_ptat->bits.flags); + IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp); + return true; } -static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, - u16 volt_band_gap) +static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) { - u32 tmp_result; - u8 vrefs_diff; - /* - * For temperature calculation (at the end, shift right by 23) - * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) } - * (D2-D1) == 43 44 45 46 47 48 49 50 51 - */ - static const u16 calc_lut[CALC_LUT_SIZE] = { - 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828, + struct iwl_dts_measurement_cmd cmd = { + .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), }; - /* - * The diff between the high and low voltage-references is assumed - * to be strictly be in range of [60,68] - */ - vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low; - - if (vrefs_diff < CALC_VREFS_MIN_DIFF || - vrefs_diff > CALC_VREFS_MAX_DIFF) - return TEMPERATURE_ERROR; - - /* calculate the result: */ - tmp_result = - vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9); - tmp_result += avg_ptat.bits.digital_value; - tmp_result -= avg_ptat.bits.vref_high; - - /* multiply by the LUT value (based on the diff) */ - tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET]; - - /* - * Get the BandGap (the voltage refereces source) error data - * (temperature offset) - */ - tmp_result *= volt_band_gap; - - /* - * here, tmp_result value can be up to 32-bits. We want to right-shift - * it *without* sign-extend. - */ - tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET; - - /* - * at this point, tmp_result should be in the range: - * 200 <= tmp_result <= 365 - */ - return (s16)tmp_result - 240; -} - -static s32 check_nic_temperature(struct iwl_mvm *mvm) -{ - u16 volt_band_gap; - union dts_diode_results avg_ptat; - - volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm); - - /* disable DTS */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); - - /* SV initialization */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1); - iwl_write_prph(mvm->trans, DTSC_CFG_MODE, - DTSC_CFG_MODE_PERIODIC); - - /* wait for results */ - msleep(100); - if (!dts_read_ptat_avg_results(mvm, &avg_ptat)) - return TEMPERATURE_ERROR; - - /* disable DTS */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); - - return calculate_nic_temperature(avg_ptat, volt_band_gap); + return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0, + sizeof(cmd), &cmd); } -static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) +static int iwl_mvm_get_temp(struct iwl_mvm *mvm) { - u32 duration = mvm->thermal_throttle.params->ct_kill_duration; + struct iwl_notification_wait wait_temp_notif; + static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; + int ret, temp; - if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) - return; + lockdep_assert_held(&mvm->mutex); - IWL_ERR(mvm, "Enter CT Kill\n"); - iwl_mvm_set_hw_ctkill_state(mvm, true); + iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, + temp_notif, ARRAY_SIZE(temp_notif), + iwl_mvm_temp_notif, &temp); - /* Don't schedule an exit work if we're in test mode, since - * the temperature will not change unless we manually set it - * again (or disable testing). - */ - if (!mvm->temperature_test) - schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, - round_jiffies_relative(duration * HZ)); -} + ret = iwl_mvm_get_temp_cmd(mvm); + if (ret) { + IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret); + iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif); + return ret; + } -static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) -{ - if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) - return; + ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif, + IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT); + if (ret) { + IWL_ERR(mvm, "Getting the temperature timed out\n"); + return ret; + } - IWL_ERR(mvm, "Exit CT Kill\n"); - iwl_mvm_set_hw_ctkill_state(mvm, false); + return temp; } static void check_exit_ctkill(struct work_struct *work) @@ -352,28 +176,36 @@ static void check_exit_ctkill(struct work_struct *work) duration = tt->params->ct_kill_duration; + mutex_lock(&mvm->mutex); + + if (__iwl_mvm_mac_start(mvm)) + goto reschedule; + /* make sure the device is available for direct read/writes */ - if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) { + __iwl_mvm_mac_stop(mvm); goto reschedule; + } - iwl_trans_start_hw(mvm->trans); - temp = check_nic_temperature(mvm); - iwl_trans_stop_device(mvm->trans); + temp = iwl_mvm_get_temp(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); - if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { - IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); + __iwl_mvm_mac_stop(mvm); + + if (temp < 0) goto reschedule; - } + IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); if (temp <= tt->params->ct_kill_exit) { + mutex_unlock(&mvm->mutex); iwl_mvm_exit_ctkill(mvm); return; } reschedule: + mutex_unlock(&mvm->mutex); schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, round_jiffies(duration * HZ)); } diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index ed0919465e0e..c67296efa04d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -213,7 +213,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, if (info->band == IEEE80211_BAND_2GHZ && !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) - rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS; + rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS; else rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index b9d5049e52da..ca68c3ccf633 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -405,6 +405,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 8000 Series */ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index a4fedc4a7448..1aea6b66c594 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -257,6 +257,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @cmd_queue - command queue number * @rx_buf_size_8k: 8 kB RX buffer size * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) + * @scd_set_active: should the transport configure the SCD for HCMD queue * @rx_page_order: page order for receive buffer size * @wd_timeout: queue watchdog timeout (jiffies) * @reg_lock: protect hw register access @@ -306,6 +307,7 @@ struct iwl_trans_pcie { bool rx_buf_size_8k; bool bc_table_dword; + bool scd_set_active; u32 rx_page_order; const char *const *command_names; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 702f47fb16fe..7b7e2f223fb2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -640,7 +640,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); if (reclaim) { - kfree(txq->entries[cmd_index].free_buf); + kzfree(txq->entries[cmd_index].free_buf); txq->entries[cmd_index].free_buf = NULL; } diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 3076e0e9a490..ae99240dcde4 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1171,6 +1171,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->command_names = trans_cfg->command_names; trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; + trans_pcie->scd_set_active = trans_cfg->scd_set_active; /* Initialize NAPI here - it should be before registering to mac80211 * in the opmode but after the HW struct is allocated. @@ -2189,7 +2190,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) trans->hw_rev = (trans->hw_rev & 0xfff0) | - ((trans->hw_rev << 2) & 0xc); + (CSR_HW_REV_STEP(trans->hw_rev << 2)); trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index a6336b4aa3a4..eb8e2984c5e9 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -620,8 +620,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) /* De-alloc array of command/tx buffers */ if (txq_id == trans_pcie->cmd_queue) for (i = 0; i < txq->q.n_window; i++) { - kfree(txq->entries[i].cmd); - kfree(txq->entries[i].free_buf); + kzfree(txq->entries[i].cmd); + kzfree(txq->entries[i].free_buf); } /* De-alloc circular buffer of TFDs */ @@ -1080,7 +1080,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, fifo = cfg->fifo; /* Disable the scheduler prior configuring the cmd queue */ - if (txq_id == trans_pcie->cmd_queue) + if (txq_id == trans_pcie->cmd_queue && + trans_pcie->scd_set_active) iwl_scd_enable_set_active(trans, 0); /* Stop this Tx queue before configuring it */ @@ -1142,7 +1143,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, SCD_QUEUE_STTS_REG_MSK); /* enable the scheduler for this queue (only) */ - if (txq_id == trans_pcie->cmd_queue) + if (txq_id == trans_pcie->cmd_queue && + trans_pcie->scd_set_active) iwl_scd_enable_set_active(trans, BIT(txq_id)); } @@ -1407,7 +1409,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, out_meta->flags = cmd->flags; if (WARN_ON_ONCE(txq->entries[idx].free_buf)) - kfree(txq->entries[idx].free_buf); + kzfree(txq->entries[idx].free_buf); txq->entries[idx].free_buf = dup_buf; trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1326f6121835..babbdc1ce741 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2045,8 +2045,6 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, hw->flags = IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_STATIC_SMPS | - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_WANT_MONITOR_VIF | IEEE80211_HW_QUEUE_CONTROL | @@ -2059,8 +2057,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_CHANNEL_SWITCH; - hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; - hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_STATIC_SMPS | + NL80211_FEATURE_DYNAMIC_SMPS; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 06a2c215ef5e..40057079ffb9 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -183,6 +183,15 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, if (!tbl) return; + spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags); + priv->adapter->rx_locked = true; + if (priv->adapter->rx_processing) { + spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags); + flush_workqueue(priv->adapter->rx_workqueue); + } else { + spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags); + } + start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1); mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); @@ -194,6 +203,11 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, kfree(tbl->rx_reorder_ptr); kfree(tbl); + + spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags); + priv->adapter->rx_locked = false; + spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags); + } /* diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index c4723b0f5757..0dd672954ad1 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1936,13 +1936,6 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); - if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && - atomic_read(&priv->wmm.tx_pkts_queued) >= - MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) { - dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n"); - return -EBUSY; - } - /* Block scan request if scan operation or scan cleanup when interface * is disabled is in process */ @@ -1981,7 +1974,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, user_scan_cfg->chan_list[i].chan_number = chan->hw_value; user_scan_cfg->chan_list[i].radio_type = chan->band; - if (chan->flags & IEEE80211_CHAN_NO_IR) + if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids) user_scan_cfg->chan_list[i].scan_type = MWIFIEX_SCAN_TYPE_PASSIVE; else @@ -1991,6 +1984,11 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, user_scan_cfg->chan_list[i].scan_time = 0; } + if (priv->adapter->scan_chan_gap_enabled && + mwifiex_is_any_intf_active(priv)) + user_scan_cfg->scan_chan_gap = + priv->adapter->scan_chan_gap_time; + ret = mwifiex_scan_networks(priv, user_scan_cfg); kfree(user_scan_cfg); if (ret) { @@ -2915,7 +2913,6 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->features |= NL80211_FEATURE_HT_IBSS | NL80211_FEATURE_INACTIVITY_TIMER | - NL80211_FEATURE_LOW_PRIORITY_SCAN | NL80211_FEATURE_NEED_OBSS_SCAN; /* Reserve space for mwifiex specific private data for BSS */ diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 985f6c2654fb..85597200badc 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1508,6 +1508,7 @@ 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)) { @@ -1612,5 +1613,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, adapter->if_ops.update_mp_end_port(adapter, le16_to_cpu(hw_spec->mp_end_port)); + if (adapter->fw_api_ver == MWIFIEX_FW_V15) + adapter->scan_chan_gap_enabled = true; + return 0; } diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 0e03fe39fc35..e0d00a7f0ec3 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -48,8 +48,8 @@ #define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16 #define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 64 #define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 64 -#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 48 -#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 32 +#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 64 +#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 64 #define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 6a703ea18800..1eb61739071f 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -170,7 +170,8 @@ 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_API_REV (PROPRIETARY_TLV_BASE_ID + 199) +#define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197) +#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -653,6 +654,12 @@ struct mwifiex_ie_types_num_probes { __le16 num_probes; } __packed; +struct mwifiex_ie_types_scan_chan_gap { + struct mwifiex_ie_types_header header; + /* time gap in TUs to be used between two consecutive channels scan */ + __le16 chan_gap; +} __packed; + struct mwifiex_ie_types_wildcard_ssid_params { struct mwifiex_ie_types_header header; u8 max_ssid_length; @@ -1249,6 +1256,7 @@ struct mwifiex_user_scan_cfg { u8 num_ssids; /* Variable number (fixed maximum) of channels to scan up */ struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX]; + u16 scan_chan_gap; } __packed; struct ie_body { diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 80bda8087508..f7c97cf3840b 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -212,6 +212,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME; adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; + adapter->scan_chan_gap_time = MWIFIEX_DEF_SCAN_CHAN_GAP_TIME; adapter->scan_probes = 1; @@ -280,7 +281,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); adapter->arp_filter_size = 0; adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; - adapter->empty_tx_q_cnt = 0; adapter->ext_scan = true; adapter->key_api_major_ver = 0; adapter->key_api_minor_ver = 0; @@ -447,8 +447,11 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) spin_lock_init(&adapter->cmd_free_q_lock); spin_lock_init(&adapter->cmd_pending_q_lock); spin_lock_init(&adapter->scan_pending_q_lock); + spin_lock_init(&adapter->rx_q_lock); + spin_lock_init(&adapter->rx_proc_lock); skb_queue_head_init(&adapter->usb_rx_data_q); + skb_queue_head_init(&adapter->rx_data_q); for (i = 0; i < adapter->priv_num; ++i) { INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); @@ -614,6 +617,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) int ret = -EINPROGRESS; struct mwifiex_private *priv; s32 i; + unsigned long flags; struct sk_buff *skb; /* mwifiex already shutdown */ @@ -648,6 +652,21 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) } } + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + + while ((skb = skb_dequeue(&adapter->rx_data_q))) { + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + + atomic_dec(&adapter->rx_pending); + priv = adapter->priv[rx_info->bss_num]; + if (priv) + priv->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + } + + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + spin_lock(&adapter->mwifiex_lock); if (adapter->if_ops.data_complete) { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index dfa37eadc4db..b522f7c36901 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -28,91 +28,6 @@ const char driver_version[] = "mwifiex " VERSION " (%s) "; static char *cal_data_cfg; module_param(cal_data_cfg, charp, 0); -static void scan_delay_timer_fn(unsigned long data) -{ - struct mwifiex_private *priv = (struct mwifiex_private *)data; - struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node, *tmp_node; - spinlock_t *scan_q_lock = &adapter->scan_pending_q_lock; - unsigned long flags; - - if (adapter->surprise_removed) - return; - - if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT || - !adapter->scan_processing) { - /* - * Abort scan operation by cancelling all pending scan - * commands - */ - spin_lock_irqsave(scan_q_lock, flags); - list_for_each_entry_safe(cmd_node, tmp_node, - &adapter->scan_pending_q, list) { - list_del(&cmd_node->list); - mwifiex_insert_cmd_to_free_q(adapter, cmd_node); - } - spin_unlock_irqrestore(scan_q_lock, flags); - - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->scan_processing = false; - adapter->scan_delay_cnt = 0; - adapter->empty_tx_q_cnt = 0; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - - if (priv->scan_request) { - dev_dbg(adapter->dev, "info: aborting scan\n"); - cfg80211_scan_done(priv->scan_request, 1); - priv->scan_request = NULL; - } else { - priv->scan_aborting = false; - dev_dbg(adapter->dev, "info: scan already aborted\n"); - } - goto done; - } - - if (!atomic_read(&priv->adapter->is_tx_received)) { - adapter->empty_tx_q_cnt++; - if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) { - /* - * No Tx traffic for 200msec. Get scan command from - * scan pending queue and put to cmd pending queue to - * resume scan operation - */ - adapter->scan_delay_cnt = 0; - adapter->empty_tx_q_cnt = 0; - spin_lock_irqsave(scan_q_lock, flags); - - if (list_empty(&adapter->scan_pending_q)) { - spin_unlock_irqrestore(scan_q_lock, flags); - goto done; - } - - cmd_node = list_first_entry(&adapter->scan_pending_q, - struct cmd_ctrl_node, list); - list_del(&cmd_node->list); - spin_unlock_irqrestore(scan_q_lock, flags); - - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, - true); - queue_work(adapter->workqueue, &adapter->main_work); - goto done; - } - } else { - adapter->empty_tx_q_cnt = 0; - } - - /* Delay scan operation further by 20msec */ - mod_timer(&priv->scan_delay_timer, jiffies + - msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); - adapter->scan_delay_cnt++; - -done: - if (atomic_read(&priv->adapter->is_tx_received)) - atomic_set(&priv->adapter->is_tx_received, false); - - return; -} - /* * This function registers the device and performs all the necessary * initializations. @@ -160,10 +75,6 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, adapter->priv[i]->adapter = adapter; adapter->priv_num++; - - setup_timer(&adapter->priv[i]->scan_delay_timer, - scan_delay_timer_fn, - (unsigned long)adapter->priv[i]); } mwifiex_init_lock_list(adapter); @@ -207,7 +118,6 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { mwifiex_free_curr_bcn(adapter->priv[i]); - del_timer_sync(&adapter->priv[i]->scan_delay_timer); kfree(adapter->priv[i]); } } @@ -216,6 +126,42 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) return 0; } +static int mwifiex_process_rx(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + struct sk_buff *skb; + bool delay_main_work = adapter->delay_main_work; + + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + if (adapter->rx_processing || adapter->rx_locked) { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + goto exit_rx_proc; + } else { + adapter->rx_processing = true; + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + } + + /* Check for Rx data */ + while ((skb = skb_dequeue(&adapter->rx_data_q))) { + atomic_dec(&adapter->rx_pending); + if (adapter->delay_main_work && + (atomic_dec_return(&adapter->rx_pending) < + LOW_RX_PENDING)) { + adapter->delay_main_work = false; + queue_work(adapter->rx_workqueue, &adapter->rx_work); + } + mwifiex_handle_rx_packet(adapter, skb); + } + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + adapter->rx_processing = false; + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + + if (delay_main_work) + queue_work(adapter->workqueue, &adapter->main_work); +exit_rx_proc: + return 0; +} + /* * The main process. * @@ -253,6 +199,19 @@ process_start: (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) break; + /* If we process interrupts first, it would increase RX pending + * even further. Avoid this by checking if rx_pending has + * crossed high threshold and schedule rx work queue + * and then process interrupts + */ + if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING) { + adapter->delay_main_work = true; + if (!adapter->rx_processing) + queue_work(adapter->rx_workqueue, + &adapter->rx_work); + break; + } + /* Handle pending interrupt if any */ if (adapter->int_status) { if (adapter->hs_activated) @@ -261,6 +220,9 @@ process_start: adapter->if_ops.process_int_status(adapter); } + if (adapter->rx_work_enabled && adapter->data_received) + queue_work(adapter->rx_workqueue, &adapter->rx_work); + /* Need to wake up the card ? */ if ((adapter->ps_state == PS_STATE_SLEEP) && (adapter->pm_wakeup_card_req && @@ -273,6 +235,7 @@ process_start: } if (IS_CARD_RX_RCVD(adapter)) { + adapter->data_received = false; adapter->pm_wakeup_fw_try = false; if (adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; @@ -284,8 +247,8 @@ process_start: adapter->tx_lock_flag) break; - if ((adapter->scan_processing && - !adapter->scan_delay_cnt) || adapter->data_sent || + if ((!adapter->scan_chan_gap_enabled && + adapter->scan_processing) || adapter->data_sent || mwifiex_wmm_lists_empty(adapter)) { if (adapter->cmd_sent || adapter->curr_cmd || (!is_command_pending(adapter))) @@ -339,7 +302,8 @@ process_start: } } - if ((!adapter->scan_processing || adapter->scan_delay_cnt) && + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { @@ -407,6 +371,12 @@ static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) flush_workqueue(adapter->workqueue); destroy_workqueue(adapter->workqueue); adapter->workqueue = NULL; + + if (adapter->rx_workqueue) { + flush_workqueue(adapter->rx_workqueue); + destroy_workqueue(adapter->rx_workqueue); + adapter->rx_workqueue = NULL; + } } /* @@ -598,9 +568,6 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) atomic_inc(&priv->adapter->tx_pending); mwifiex_wmm_add_buf_txqueue(priv, skb); - if (priv->adapter->scan_delay_cnt) - atomic_set(&priv->adapter->is_tx_received, true); - queue_work(priv->adapter->workqueue, &priv->adapter->main_work); return 0; @@ -824,6 +791,21 @@ int is_command_pending(struct mwifiex_adapter *adapter) } /* + * This is the RX work queue function. + * + * It handles the RX operations. + */ +static void mwifiex_rx_work_queue(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, rx_work); + + if (adapter->surprise_removed) + return; + mwifiex_process_rx(adapter); +} + +/* * This is the main work queue function. * * It handles the main process, which in turn handles the complete @@ -879,6 +861,11 @@ mwifiex_add_card(void *card, struct semaphore *sem, adapter->cmd_wait_q.status = 0; adapter->scan_wait_q_woken = false; + if (num_possible_cpus() > 1) { + adapter->rx_work_enabled = true; + pr_notice("rx work enabled, cpus %d\n", num_possible_cpus()); + } + adapter->workqueue = alloc_workqueue("MWIFIEX_WORK_QUEUE", WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1); @@ -886,6 +873,18 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_kmalloc; INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); + + if (adapter->rx_work_enabled) { + adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE", + WQ_HIGHPRI | + WQ_MEM_RECLAIM | + WQ_UNBOUND, 1); + if (!adapter->rx_workqueue) + goto err_kmalloc; + + INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue); + } + if (adapter->if_ops.iface_work) INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 54399631599a..1a999999b391 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -58,6 +58,9 @@ enum { #define MAX_TX_PENDING 100 #define LOW_TX_PENDING 80 +#define HIGH_RX_PENDING 50 +#define LOW_RX_PENDING 20 + #define MWIFIEX_UPLD_SIZE (2312) #define MAX_EVENT_SIZE 2048 @@ -84,17 +87,12 @@ enum { #define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 110 #define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 30 #define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 30 +#define MWIFIEX_DEF_SCAN_CHAN_GAP_TIME 50 #define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) #define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) -#define MWIFIEX_MAX_SCAN_DELAY_CNT 50 -#define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10 -#define MWIFIEX_SCAN_DELAY_MSEC 20 - -#define MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN 2 - #define RSN_GTK_OUI_OFFSET 2 #define MWIFIEX_OUI_NOT_PRESENT 0 @@ -547,7 +545,6 @@ struct mwifiex_private { u8 nick_name[16]; u16 current_key_index; struct semaphore async_sem; - u8 report_scan_result; struct cfg80211_scan_request *scan_request; u8 cfg_bssid[6]; struct wps wps; @@ -561,7 +558,6 @@ struct mwifiex_private { u16 proberesp_idx; u16 assocresp_idx; u16 rsn_idx; - struct timer_list scan_delay_timer; u8 ap_11n_enabled; u8 ap_11ac_enabled; u32 mgmt_frame_mask; @@ -721,6 +717,12 @@ struct mwifiex_adapter { atomic_t cmd_pending; struct workqueue_struct *workqueue; struct work_struct main_work; + struct workqueue_struct *rx_workqueue; + struct work_struct rx_work; + bool rx_work_enabled; + bool rx_processing; + bool delay_main_work; + bool rx_locked; struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; /* spin lock for init/shutdown */ spinlock_t mwifiex_lock; @@ -761,6 +763,10 @@ struct mwifiex_adapter { struct list_head scan_pending_q; /* spin lock for scan_pending_q */ spinlock_t scan_pending_q_lock; + /* spin lock for RX queue */ + spinlock_t rx_q_lock; + /* spin lock for RX processing routine */ + spinlock_t rx_proc_lock; struct sk_buff_head usb_rx_data_q; u32 scan_processing; u16 region_code; @@ -770,6 +776,7 @@ struct mwifiex_adapter { u16 specific_scan_time; u16 active_scan_time; u16 passive_scan_time; + u16 scan_chan_gap_time; u8 fw_bands; u8 adhoc_start_band; u8 config_bands; @@ -815,8 +822,6 @@ struct mwifiex_adapter { spinlock_t queue_lock; /* lock for tx queues */ u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; u16 max_mgmt_ie_index; - u8 scan_delay_cnt; - u8 empty_tx_q_cnt; const struct firmware *cal_data; struct device_node *dt_node; @@ -828,7 +833,6 @@ struct mwifiex_adapter { u32 usr_dot_11ac_dev_cap_a; u32 usr_dot_11ac_mcs_support; - atomic_t is_tx_received; atomic_t pending_bridged_pkts; struct semaphore *card_sem; bool ext_scan; @@ -839,6 +843,8 @@ struct mwifiex_adapter { struct memory_type_mapping *mem_type_mapping_tbl; u8 num_mem_types; u8 curr_mem_idx; + bool scan_chan_gap_enabled; + struct sk_buff_head rx_data_q; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); @@ -1139,6 +1145,25 @@ mwifiex_11h_get_csa_closed_channel(struct mwifiex_private *priv) return priv->csa_chan; } +static inline u8 mwifiex_is_any_intf_active(struct mwifiex_private *priv) +{ + struct mwifiex_private *priv_num; + int i; + + for (i = 0; i < priv->adapter->priv_num; i++) { + priv_num = priv->adapter->priv[i]; + if (priv_num) { + if ((GET_BSS_ROLE(priv_num) == MWIFIEX_BSS_ROLE_UAP && + priv_num->bss_started) || + (GET_BSS_ROLE(priv_num) == MWIFIEX_BSS_ROLE_STA && + priv_num->media_connected)) + return 1; + } + } + + return 0; +} + int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown); int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); @@ -1274,6 +1299,7 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv); bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv); u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band, u32 pri_chan, u8 chan_bw); +int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index ff0545888dd0..1504b16e248e 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1233,6 +1233,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) struct sk_buff *skb_tmp = NULL; struct mwifiex_pcie_buf_desc *desc; struct mwifiex_pfu_buf_desc *desc2; + unsigned long flags; if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); @@ -1271,12 +1272,29 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) */ pkt_len = *((__le16 *)skb_data->data); rx_len = le16_to_cpu(pkt_len); - skb_put(skb_data, rx_len); - dev_dbg(adapter->dev, - "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", - card->rxbd_rdptr, wrptr, rx_len); - skb_pull(skb_data, INTF_HEADER_LEN); - mwifiex_handle_rx_packet(adapter, skb_data); + if (WARN_ON(rx_len <= INTF_HEADER_LEN || + rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) { + dev_err(adapter->dev, + "Invalid RX len %d, Rd=%#x, Wr=%#x\n", + rx_len, card->rxbd_rdptr, wrptr); + dev_kfree_skb_any(skb_data); + } else { + skb_put(skb_data, rx_len); + dev_dbg(adapter->dev, + "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", + card->rxbd_rdptr, wrptr, rx_len); + skb_pull(skb_data, INTF_HEADER_LEN); + if (adapter->rx_work_enabled) { + spin_lock_irqsave(&adapter->rx_q_lock, flags); + skb_queue_tail(&adapter->rx_data_q, skb_data); + spin_unlock_irqrestore(&adapter->rx_q_lock, + flags); + adapter->data_received = true; + atomic_inc(&adapter->rx_pending); + } else { + mwifiex_handle_rx_packet(adapter, skb_data); + } + } skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); if (!skb_tmp) { @@ -1718,6 +1736,13 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) buffer is released. This is just to make things simpler, we need to find a better method of managing these buffers. */ + } else { + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_EVENT_DONE)) { + dev_warn(adapter->dev, + "Write register failed\n"); + return -1; + } } return 0; diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index a1a8fd3bc1be..200e8b0cb582 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -40,8 +40,8 @@ #define MWIFIEX_TXBD_MASK 0x3F #define MWIFIEX_RXBD_MASK 0x3F -#define MWIFIEX_MAX_EVT_BD 0x04 -#define MWIFIEX_EVTBD_MASK 0x07 +#define MWIFIEX_MAX_EVT_BD 0x08 +#define MWIFIEX_EVTBD_MASK 0x0f /* PCIE INTERNAL REGISTERS */ #define PCIE_SCRATCH_0_REG 0xC10 @@ -69,6 +69,7 @@ #define CPU_INTR_DOOR_BELL BIT(1) #define CPU_INTR_SLEEP_CFM_DONE BIT(2) #define CPU_INTR_RESET BIT(3) +#define CPU_INTR_EVENT_DONE BIT(5) #define HOST_INTR_DNLD_DONE BIT(0) #define HOST_INTR_UPLD_RDY BIT(1) diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 195ef0ca343f..c09ebeee6ddf 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -799,6 +799,7 @@ mwifiex_config_scan(struct mwifiex_private *priv, { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_ie_types_num_probes *num_probes_tlv; + struct mwifiex_ie_types_scan_chan_gap *chan_gap_tlv; struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; struct mwifiex_ie_types_bssid_list *bssid_tlv; u8 *tlv_pos; @@ -939,6 +940,22 @@ mwifiex_config_scan(struct mwifiex_private *priv, else *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; + if (user_scan_in->scan_chan_gap) { + *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; + dev_dbg(adapter->dev, "info: scan: channel gap = %d\n", + user_scan_in->scan_chan_gap); + + chan_gap_tlv = (void *)tlv_pos; + chan_gap_tlv->header.type = + cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP); + chan_gap_tlv->header.len = + cpu_to_le16(sizeof(chan_gap_tlv->chan_gap)); + chan_gap_tlv->chan_gap = + cpu_to_le16((user_scan_in->scan_chan_gap)); + + tlv_pos += sizeof(struct mwifiex_ie_types_scan_chan_gap); + } + /* If the input config or adapter has the number of Probes set, add tlv */ if (num_probes) { @@ -1050,12 +1067,6 @@ mwifiex_config_scan(struct mwifiex_private *priv, *filtered_scan); } - /* - * In associated state we will reduce the number of channels scanned per - * scan command to 1 to avoid any traffic delay/loss. - */ - if (priv->media_connected) - *max_chan_per_scan = 1; } /* @@ -1755,7 +1766,7 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv) static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) { struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node; + struct cmd_ctrl_node *cmd_node, *tmp_node; unsigned long flags; spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); @@ -1768,9 +1779,6 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) if (!adapter->ext_scan) mwifiex_complete_scan(priv); - if (priv->report_scan_result) - priv->report_scan_result = false; - if (priv->scan_request) { dev_dbg(adapter->dev, "info: notifying scan done\n"); cfg80211_scan_done(priv->scan_request, 0); @@ -1779,37 +1787,36 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) priv->scan_aborting = false; dev_dbg(adapter->dev, "info: scan already aborted\n"); } - } else { - if ((priv->scan_aborting && !priv->scan_request) || - priv->scan_block) { - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); - adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT; - mod_timer(&priv->scan_delay_timer, jiffies); - dev_dbg(priv->adapter->dev, - "info: %s: triggerring scan abort\n", __func__); - } else if (!mwifiex_wmm_lists_empty(adapter) && - (priv->scan_request && (priv->scan_request->flags & - NL80211_SCAN_FLAG_LOW_PRIORITY))) { - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); - adapter->scan_delay_cnt = 1; - mod_timer(&priv->scan_delay_timer, jiffies + - msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); - dev_dbg(priv->adapter->dev, - "info: %s: deferring scan\n", __func__); - } else { - /* Get scan command from scan_pending_q and put to - * cmd_pending_q - */ - cmd_node = list_first_entry(&adapter->scan_pending_q, - struct cmd_ctrl_node, list); + } else if ((priv->scan_aborting && !priv->scan_request) || + priv->scan_block) { + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, - true); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + if (priv->scan_request) { + dev_dbg(adapter->dev, "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } else { + priv->scan_aborting = false; + dev_dbg(adapter->dev, "info: scan already aborted\n"); + } + } else { + /* Get scan command from scan_pending_q and put to + * cmd_pending_q + */ + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); } return; @@ -1971,9 +1978,34 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv, /* This function handles the command response of extended scan */ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv) { + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_command *cmd_ptr; + struct cmd_ctrl_node *cmd_node; + unsigned long cmd_flags, scan_flags; + bool complete_scan = false; + dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n"); - mwifiex_complete_scan(priv); + spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_flags); + spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_flags); + if (list_empty(&adapter->scan_pending_q)) { + complete_scan = true; + list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) { + cmd_ptr = (void *)cmd_node->cmd_skb->data; + if (le16_to_cpu(cmd_ptr->command) == + HostCmd_CMD_802_11_SCAN_EXT) { + dev_dbg(priv->adapter->dev, + "Scan pending in command pending list"); + complete_scan = false; + break; + } + } + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_flags); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, cmd_flags); + + if (complete_scan) + mwifiex_complete_scan(priv); return 0; } diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 1770fa3fc1e6..ea8fc587e90f 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -622,22 +622,15 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port) dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap); - if (card->supports_sdio_new_mode && - !(wr_bitmap & reg->data_port_mask)) { + if (!(wr_bitmap & card->mp_data_port_mask)) { adapter->data_sent = true; return -EBUSY; - } else if (!card->supports_sdio_new_mode && - !(wr_bitmap & card->mp_data_port_mask)) { - return -1; } if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port)); *port = card->curr_wr_port; - if (((card->supports_sdio_new_mode) && - (++card->curr_wr_port == card->max_ports)) || - ((!card->supports_sdio_new_mode) && - (++card->curr_wr_port == card->mp_end_port))) + if (++card->curr_wr_port == card->mp_end_port) card->curr_wr_port = reg->start_wr_port; } else { adapter->data_sent = true; @@ -1046,6 +1039,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb, u32 upld_typ) { u8 *cmd_buf; + unsigned long flags; __le16 *curr_ptr = (__le16 *)skb->data; u16 pkt_len = le16_to_cpu(*curr_ptr); @@ -1055,7 +1049,15 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, switch (upld_typ) { case MWIFIEX_TYPE_DATA: dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); - mwifiex_handle_rx_packet(adapter, skb); + if (adapter->rx_work_enabled) { + spin_lock_irqsave(&adapter->rx_q_lock, flags); + skb_queue_tail(&adapter->rx_data_q, skb); + spin_unlock_irqrestore(&adapter->rx_q_lock, flags); + adapter->data_received = true; + atomic_inc(&adapter->rx_pending); + } else { + mwifiex_handle_rx_packet(adapter, skb); + } break; case MWIFIEX_TYPE_CMD: @@ -1527,8 +1529,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, __func__); if (MP_TX_AGGR_IN_PROGRESS(card)) { - if (!mp_tx_aggr_port_limit_reached(card) && - MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { f_precopy_cur_buf = 1; if (!(card->mp_wr_bitmap & @@ -1540,8 +1541,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, /* No room in Aggr buf, send it */ f_send_aggr_buf = 1; - if (mp_tx_aggr_port_limit_reached(card) || - !(card->mp_wr_bitmap & + if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) f_send_cur_buf = 1; else diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 62866b0f0830..4aad44685f8d 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -85,8 +85,6 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->scan_processing = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - if (priv->report_scan_result) - priv->report_scan_result = false; break; case HostCmd_CMD_MAC_CONTROL: diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index b95a29b868d1..92f3eb839866 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -287,10 +287,13 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, return -1; if (mwifiex_band_to_radio_type(bss_desc->bss_band) == - HostCmd_SCAN_RADIO_TYPE_BG) + HostCmd_SCAN_RADIO_TYPE_BG) { config_bands = BAND_B | BAND_G | BAND_GN; - else - config_bands = BAND_A | BAND_AN | BAND_AAC; + } else { + config_bands = BAND_A | BAND_AN; + if (adapter->fw_bands & BAND_AAC) + config_bands |= BAND_AAC; + } if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands)) adapter->config_bands = config_bands; diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 4c5fd953893d..e2949077f5b5 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -871,7 +871,9 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, break; case WLAN_EID_RSN: memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, - sizeof(struct ieee_types_header) + pos[1]); + sizeof(struct ieee_types_header) + + min_t(u8, pos[1], IEEE_MAX_IE_SIZE - + sizeof(struct ieee_types_header))); break; case WLAN_EID_QOS_CAPA: sta_ptr->tdls_cap.qos_info = pos[2]; diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 7be3a4839640..97aeff0edb84 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -696,7 +696,8 @@ static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif, WARN(total, "tx flush timeout, unresponsive firmware"); } -static void p54_set_coverage_class(struct ieee80211_hw *dev, u8 coverage_class) +static void p54_set_coverage_class(struct ieee80211_hw *dev, + s16 coverage_class) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h index d76684eb24d0..39b9a3309cfd 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 000000000000..53261d6f8578 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -0,0 +1,3849 @@ +/****************************************************************************** + * + * 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; + struct rtl_priv *rtlpriv = btcoexist->adapter; + 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; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ============[BT Coexist info]============"); + + if (btcoexist->manual_control) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ===========[Under Manual Control]==========="); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n =========================================="); + } + + if (!board_info->bt_exist) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); + return; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", + ((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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsMode(HsChnl)", + wifi_dot11_chnl, bt_hson, wifi_hs_chnl); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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]); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", + "Wifi rssi/ HS rssi", wifirssi, bt_hs_rssi); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", link, roam, scan); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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"))); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); + + for (i = 0; i < BT_INFO_SRC_8192E_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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]); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "%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]); + } + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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"))); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "SS Type", + coex_dm->cur_sstype); + + /* Sw mechanism */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Sw mechanism]============"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "Rate Mask", + btcoexist->bt_info.ra_mask); + + /* Fw mechanism */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Fw mechanism]============"); + + ps_tdma_case = coex_dm->cur_ps_tdma; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", + coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act); + + /* Hw setting */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Hw setting]============"); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xc04/ 0xd04/ 0x90c", u32tmp[0], u32tmp[1], u32tmp[2]); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0x778", + u8tmp[0]); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0x92c/ 0x930", (u8tmp[0]), u32tmp[0]); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0x40/ 0x4f", u8tmp[0], u8tmp[1]); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0xc50(dig)", + u32tmp[0]); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", + "0x770(hp rx[31:16]/tx[15:0])", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", + "0x774(lp rx[31:16]/tx[15:0])", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); +#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 000000000000..75e1f7d0db06 --- /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 000000000000..c4acd403e5f6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -0,0 +1,3170 @@ +/****************************************************************************** + * + * 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; + struct rtl_priv *rtlpriv = btcoexist->adapter; + 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; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ============[BT Coexist info]============"); + + if (btcoexist->manual_control) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ============[Under Manual Control]=========="); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n =========================================="); + } + if (btcoexist->stop_coex_dm) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ============[Coex is STOPPED]============"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n =========================================="); + } + + if (!board_info->bt_exist) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); + return; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", + ((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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsChnl(HsMode)", + wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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]); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", + "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", link, roam, scan); + + 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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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"))); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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)); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT0) ? "Basic rate" : "EDR rate"); + + for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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]); + } + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if (!btcoexist->manual_control) { + /* Sw mechanism */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Sw mechanism]============"); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/", + "SM[LowPenaltyRA]", coex_dm->cur_low_penalty_ra); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", + "Rate Mask", btcoexist->bt_info.ra_mask); + + /* Fw mechanism */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Fw mechanism]============"); + + pstdmacase = coex_dm->cur_ps_tdma; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d ", + "IgnWlanAct", coex_dm->cur_ignore_wlan_act); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", + "Latest error condition(should be 0)", + coex_dm->error_condition); + } + + /* Hw setting */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Hw setting]============"); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x778/0x6cc/0x880[29:25]", u8tmp[0], u32tmp[0], + (u32tmp[1] & 0x3e000000) >> 25); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x948/ 0x67[5] / 0x765", + u32tmp[0], ((u8tmp[0] & 0x20) >> 5), u8tmp[1]); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(dig)/0x49c(null-drop)", u32tmp[0] & 0xff, u8tmp[0]); + + 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]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "OFDM-CCA/OFDM-FA/CCK-FA", + u32tmp[0] & 0xffff, fa_ofdm, fa_cck); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", coex_sta->high_priority_rx, + coex_sta->high_priority_tx); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, + coex_sta->low_priority_tx); +#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 000000000000..75f8094b7a34 --- /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 d916ab9f3c38..cefe26991421 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,19 +3147,19 @@ 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; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - u8 *cli_buf = btcoexist->cli_buf; + struct rtl_priv *rtlpriv = btcoexist->adapter; u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; u32 u32tmp[4]; bool roam = false, scan = false; @@ -3114,106 +3169,93 @@ 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, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[BT Coexist info]============"); - CL_PRINTF(cli_buf); if (btcoexist->manual_control) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ==========[Under Manual Control]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); return; } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_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_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)", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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 ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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_U1_AP_NUM, &ap_num); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d", + "Wifi rssi/ HS rssi/ AP#", wifi_rssi, bt_hs_rssi, ap_num); 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 ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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 ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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_2ANT_MAX; i++) { if (coex_sta->bt_info_c2h_cnt[i]) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x " "%02x %02x %02x %02x(%d)", glbt_info_src_8723b_2ant[i], @@ -3225,105 +3267,88 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) 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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Sw mechanism]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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) ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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 ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Hw setting]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); - CL_PRINTF(cli_buf); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x778/0x880[29:25]", u8tmp[0], (u32tmp[0]&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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); @@ -3341,29 +3366,25 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) (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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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_2ANT == 1) btc8723b2ant_monitor_bt_ctr(btcoexist); #endif @@ -3371,22 +3392,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 +3424,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 +3434,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 +3444,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 +3485,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 +3541,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 +3550,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 +3591,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 +3628,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 +3657,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 +3694,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 e0ad8e545f82..567f354caf95 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 000000000000..b72e5377bdbc --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -0,0 +1,2970 @@ +/****************************************************************************** + * + * 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; + struct rtl_priv *rtlpriv = btcoexist->adapter; + 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; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ============[BT Coexist info]============"); + + if (btcoexist->manual_control) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ============[Under Manual Control]============"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n =========================================="); + } + if (btcoexist->stop_coex_dm) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ============[Coex is STOPPED]============"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n =========================================="); + } + + if (!board_info->bt_exist) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); + return; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", + ((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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsChnl(HsMode)", + wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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]); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", + (int)wifi_rssi, (int)bt_hs_rssi); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", + link, roam, scan); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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"))); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0) ? + "Basic rate" : "EDR rate"); + + for (i = 0; i < BT_INFO_SRC_8821A_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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]); + } + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if (!btcoexist->manual_control) { + /* Sw mechanism*/ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s", "============[Sw mechanism]============"); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d", "SM[LowPenaltyRA]", + coex_dm->cur_low_penalty_ra); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x ", "Rate Mask", + btcoexist->bt_info.ra_mask); + + /* Fw mechanism*/ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Fw mechanism]============"); + + ps_tdma_case = coex_dm->cur_ps_tdma; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x ", + "Latest error condition(should be 0)", + coex_dm->error_condition); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d ", "IgnWlanAct", + coex_dm->cur_ignore_wlan_act); + } + + /* Hw setting*/ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s", "============[Hw setting]============"); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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]); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc58); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x/ 0x%x", "0x778/ 0xc58[29:25]", + u1_tmp[0], (u4_tmp[0]&0x3e000000) >> 25); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x", "0x8db[6:5]", + ((u1_tmp[0]&0x60)>>5)); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x975); + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", + u4_tmp[0], u1_tmp[0]); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x", "0xc50(dig)", + u4_tmp[0]&0xff); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA", + u4_tmp[0], (u1_tmp[0]<<8) + u1_tmp[1]); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); +#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 000000000000..20e904890fc2 --- /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 000000000000..cf819f02ed23 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -0,0 +1,3879 @@ +/****************************************************************************** + * + * 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; + struct rtl_priv *rtlpriv = btcoexist->adapter; + 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; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n ============[BT Coexist info]============"); + + if (!board_info->bt_exist) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); + return; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + + if (btcoexist->manual_control) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s", "[Action Manual control]!!"); + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", + ((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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsMode(HsChnl)", + wifi_dot_11_chnl, bt_hs_on, wifi_hs_chnl); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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]); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %ld/ %ld", "Wifi rssi/ HS rssi", + wifi_rssi, bt_hs_rssi); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", + link, roam, scan); + + 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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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"))); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + if (stack_info->profile_notified) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + btcoexist->btc_disp_dbg_msg(btcoexist, + BTC_DBG_DISP_BT_LINK_INFO); + } + + bt_info_ext = coex_sta->bt_info_ext; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); + + for (i = 0; i < BT_INFO_SRC_8821A_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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]); + } + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\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"))); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + /* Sw mechanism*/ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Sw mechanism]============"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + /* Fw mechanism*/ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", + "============[Fw mechanism]============"); + + if (!btcoexist->manual_control) { + ps_tdma_case = coex_dm->cur_ps_tdma; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\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); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", + coex_dm->cur_dec_bt_pwr, + coex_dm->cur_ignore_wlan_act); + } + + /* Hw setting*/ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s", "============[Hw setting]============"); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", + coex_dm->bt_rf0x1e_backup); + + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x ", + "0x778 (W_Act)/ 0x6cc (CoTab Sel)", + u1tmp[0], u1tmp[1]); + + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); + u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0x8db(ADC)/0xc5b[29:25](DAC)", + ((u1tmp[0]&0x60)>>5), ((u1tmp[1]&0x3e)>>1)); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)", + u4tmp[0]&0xff, ((u4tmp[0]&0x30000000)>>28)); + + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x40/ 0x4c[24:23]/ 0x974", + u1tmp[0], ((u4tmp[0]&0x01800000)>>23), u4tmp[1]); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u4tmp[0], u1tmp[0]); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa0a); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(DIG)/0xa0a(CCK-TH)", + u4tmp[0], u1tmp[0]); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48); + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); + u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", + "OFDM-FA/ CCK-FA", + u4tmp[0], (u1tmp[0]<<8) + u1tmp[1]); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u4tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8", + u4tmp[0], u4tmp[1], u4tmp[2]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", + "0x770 (hi-pri Rx/Tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", + "0x774(low-pri Rx/Tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + + /* Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang*/ + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x41b); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", + "0x41b (mgntQ hang chk == 0xf)", + u1tmp[0]); + + 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 000000000000..b4cf1f53d510 --- /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 d4bd550f505c..fcf7459b5d66 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c @@ -32,7 +32,6 @@ struct btc_coexist gl_bt_coexist; u32 btc_dbg_type[BTC_MSG_MAX]; -static u8 btc_dbg_buf[100]; /*************************************************** * Debug related function @@ -389,7 +388,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 +416,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 +496,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 +505,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; @@ -652,9 +651,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) btcoexist->btc_get = halbtc_get; btcoexist->btc_set = halbtc_set; - 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 +669,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 +683,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 +708,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 +731,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 +754,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 +779,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 +800,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 +820,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 +836,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 +853,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 +864,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 +884,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 +983,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 049f4c8d98a8..1345545f66bc 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,12 @@ 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 - - -#define CL_SPRINTF snprintf -#define CL_PRINTF(buf) printk("%s", buf) +/* 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 BTC_PRINT(dbgtype, dbgflag, printstr, ...) \ do { \ @@ -123,46 +123,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 +193,6 @@ enum btc_wifi_pnp { BTC_WIFI_PNP_MAX }; - enum btc_get_type { /* type bool */ BTC_GET_BL_HS_OPERATION, @@ -253,6 +221,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 +229,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 +240,6 @@ enum btc_get_type { BTC_GET_MAX }; - enum btc_set_type { /* type bool */ BTC_SET_BL_BT_DISABLE, @@ -283,7 +252,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 +263,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 +329,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 +350,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 +397,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 +443,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; }; @@ -493,7 +480,6 @@ struct btc_coexist { bool initilized; bool stop_coex_dm; bool manual_control; - u8 *cli_buf; struct btc_statistics statistics; u8 pwr_mode_val[10]; @@ -509,7 +495,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 +518,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 0ab94fe4cbbe..b9b0cb7af8ea 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 805b22cc8fc8..ccd5a0f91e3b 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 67d1ee6edcad..74a8ba4b8844 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/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 592125a5f19c..1961b8e28dc1 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 5d534df8d90c..f76c50f5ab80 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 407a7936d364..541b077ae867 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/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 205f4a336583..cd6d0afb6b8f 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; |