Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
authorKalle Valo <kvalo@codeaurora.org>
Wed, 2 Dec 2020 19:46:55 +0000 (21:46 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 2 Dec 2020 19:46:55 +0000 (21:46 +0200)
ath.git patches for v5.11. Major changes:

ath11k

* Fast Initial Link Setup (FILS) discovery and unsolicited broadcast
  probe response support

* qcom,ath11k-calibration-variant Device Tree setting

* cold boot calibration support

* new DFS region: JP

wnc36xx

* enable connection monitoring and keepalive in firmware

ath10k

* firmware IRAM recovery feature

mhi

* merge mhi-ath11k-immutable branch to make MHI API change go smoothly

95 files changed:
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath6kl/testmode.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/cisco/airo.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intersil/hostap/hostap_hw.c
drivers/net/wireless/intersil/hostap/hostap_ioctl.c
drivers/net/wireless/intersil/orinoco/hermes.c
drivers/net/wireless/intersil/orinoco/hermes.h
drivers/net/wireless/intersil/orinoco/hw.c
drivers/net/wireless/intersil/orinoco/orinoco_usb.c
drivers/net/wireless/intersil/prism54/isl_ioctl.c
drivers/net/wireless/marvell/mwifiex/main.c
drivers/net/wireless/marvell/mwifiex/pcie.c
drivers/net/wireless/marvell/mwifiex/pcie.h
drivers/net/wireless/marvell/mwifiex/sdio.h
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
drivers/net/wireless/marvell/mwifiex/sta_event.c
drivers/net/wireless/marvell/mwifiex/uap_cmd.c
drivers/net/wireless/marvell/mwifiex/wmm.c
drivers/net/wireless/mediatek/mt7601u/dma.c
drivers/net/wireless/microchip/wilc1000/cfg80211.c
drivers/net/wireless/microchip/wilc1000/hif.c
drivers/net/wireless/microchip/wilc1000/hif.h
drivers/net/wireless/microchip/wilc1000/netdev.c
drivers/net/wireless/microchip/wilc1000/netdev.h
drivers/net/wireless/microchip/wilc1000/wlan.c
drivers/net/wireless/microchip/wilc1000/wlan.h
drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c
drivers/net/wireless/ralink/rt2x00/rt2800lib.c
drivers/net/wireless/ralink/rt2x00/rt2x00.h
drivers/net/wireless/ray_cs.c
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c
drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c
drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c
drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c
drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/table.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/table.h
drivers/net/wireless/realtek/rtlwifi/usb.c
drivers/net/wireless/realtek/rtw88/coex.c
drivers/net/wireless/realtek/rtw88/coex.h
drivers/net/wireless/realtek/rtw88/debug.c
drivers/net/wireless/realtek/rtw88/debug.h
drivers/net/wireless/realtek/rtw88/fw.c
drivers/net/wireless/realtek/rtw88/fw.h
drivers/net/wireless/realtek/rtw88/mac80211.c
drivers/net/wireless/realtek/rtw88/main.c
drivers/net/wireless/realtek/rtw88/main.h
drivers/net/wireless/realtek/rtw88/phy.c
drivers/net/wireless/realtek/rtw88/ps.c
drivers/net/wireless/realtek/rtw88/ps.h
drivers/net/wireless/realtek/rtw88/reg.h
drivers/net/wireless/realtek/rtw88/rtw8723d.c
drivers/net/wireless/realtek/rtw88/rtw8723d.h
drivers/net/wireless/realtek/rtw88/rtw8821c.c
drivers/net/wireless/realtek/rtw88/rtw8821c.h
drivers/net/wireless/realtek/rtw88/rtw8822b.c
drivers/net/wireless/realtek/rtw88/rtw8822c.c
drivers/net/wireless/realtek/rtw88/wow.c
drivers/net/wireless/rsi/rsi_91x_hal.c
drivers/net/wireless/rsi/rsi_91x_sdio.c
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
drivers/net/wireless/rsi/rsi_91x_usb.c
drivers/net/wireless/rsi/rsi_91x_usb_ops.c
drivers/net/wireless/rsi/rsi_sdio.h
drivers/net/wireless/st/cw1200/bh.c
drivers/net/wireless/st/cw1200/main.c
drivers/net/wireless/st/cw1200/wsm.c
drivers/net/wireless/ti/wl1251/cmd.c
drivers/net/wireless/ti/wl1251/debugfs.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/spi.c
drivers/net/wireless/ti/wlcore/sysfs.c
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zydas/zd1211rw/zd_usb.c

index 5c1af20..9c4e6cf 100644 (file)
@@ -3878,7 +3878,6 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                return ath10k_htt_rx_proc_rx_frag_ind(htt,
                                                      &resp->rx_frag_ind,
                                                      skb);
-               break;
        }
        case HTT_T2H_MSG_TYPE_TEST:
                break;
index f3906db..89c7c4e 100644 (file)
@@ -94,7 +94,6 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
 
                return 0;
 
-               break;
        case ATH6KL_TM_CMD_RX_REPORT:
        default:
                return -EOPNOTSUPP;
index 6609ce1..b66eeb5 100644 (file)
@@ -2308,7 +2308,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
                ath_dbg(ath9k_hw_common(ah), BEACON,
                        "%s: unsupported opmode: %d\n", __func__, ah->opmode);
                return;
-               break;
        }
 
        REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period);
index f9ebb98..ce8c102 100644 (file)
@@ -367,7 +367,7 @@ static int mmc_submit_one(struct mmc_data *md, struct mmc_request *mr,
  * @func: SDIO function
  * @write: direction flag
  * @addr: dongle memory address as source/destination
- * @pkt: skb pointer
+ * @pktlist: skb buffer head pointer
  *
  * This function takes the respbonsibility as the interface function to MMC
  * stack for block data access. It assumes that the skb passed down by the
index a2dbbb9..0ee421f 100644 (file)
@@ -2137,7 +2137,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                                    BRCMF_WSEC_MAX_PSK_LEN);
        else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) {
                /* clean up user-space RSNE */
-               if (brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0)) {
+               err = brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0);
+               if (err) {
                        bphy_err(drvr, "failed to clean up user-space RSNE\n");
                        goto done;
                }
index 430d2cc..bc3f4e4 100644 (file)
@@ -384,6 +384,7 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp)
  * @drvr: driver information object.
  * @event_packet: event packet to process.
  * @packet_len: length of the packet
+ * @gfp: memory allocation flags.
  *
  * If the packet buffer contains a firmware event message it will
  * dispatch the event to a registered handler (using worker).
index 39381cb..45bc502 100644 (file)
@@ -759,6 +759,7 @@ static void brcmf_pcie_bus_console_init(struct brcmf_pciedev_info *devinfo)
 /**
  * brcmf_pcie_bus_console_read - reads firmware messages
  *
+ * @devinfo: pointer to the device data structure
  * @error: specifies if error has occurred (prints messages unconditionally)
  */
 static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo,
@@ -1936,16 +1937,18 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        fwreq = brcmf_pcie_prepare_fw_request(devinfo);
        if (!fwreq) {
                ret = -ENOMEM;
-               goto fail_bus;
+               goto fail_brcmf;
        }
 
        ret = brcmf_fw_get_firmwares(bus->dev, fwreq, brcmf_pcie_setup);
        if (ret < 0) {
                kfree(fwreq);
-               goto fail_bus;
+               goto fail_brcmf;
        }
        return 0;
 
+fail_brcmf:
+       brcmf_free(&devinfo->pdev->dev);
 fail_bus:
        kfree(bus->msgbuf);
        kfree(bus);
index 99987a7..16ed325 100644 (file)
@@ -625,6 +625,10 @@ BRCMF_FW_DEF(4359, "brcmfmac4359-sdio");
 BRCMF_FW_DEF(4373, "brcmfmac4373-sdio");
 BRCMF_FW_DEF(43012, "brcmfmac43012-sdio");
 
+/* firmware config files */
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcm/brcmfmac*-sdio.*.txt");
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcm/brcmfmac*-pcie.*.txt");
+
 static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
        BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
        BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0),
@@ -1340,7 +1344,7 @@ static void brcmf_sdio_free_glom(struct brcmf_sdio *bus)
 static inline u8 brcmf_sdio_getdatoffset(u8 *swheader)
 {
        u32 hdrvalue;
-       hdrvalue = *(u32 *)swheader;
+       hdrvalue = le32_to_cpu(*(__le32 *)swheader);
        return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
 }
 
@@ -1349,7 +1353,7 @@ static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
        u32 hdrvalue;
        u8 ret;
 
-       hdrvalue = *(u32 *)swheader;
+       hdrvalue = le32_to_cpu(*(__le32 *)swheader);
        ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
 
        return (ret == SDPCM_EVENT_CHANNEL);
@@ -3517,6 +3521,7 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
        struct brcmf_sdio *bus = sdiodev->bus;
        struct brcmf_core *core = bus->sdio_core;
        u32 value;
+       __le32 iovar;
        int err;
 
        /* maxctl provided by common layer */
@@ -3537,16 +3542,16 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
         */
        if (core->rev < 12) {
                /* for sdio core rev < 12, disable txgloming */
-               value = 0;
-               err = brcmf_iovar_data_set(dev, "bus:txglom", &value,
-                                          sizeof(u32));
+               iovar = 0;
+               err = brcmf_iovar_data_set(dev, "bus:txglom", &iovar,
+                                          sizeof(iovar));
        } else {
                /* otherwise, set txglomalign */
                value = sdiodev->settings->bus.sdio.sd_sgentry_align;
                /* SDIO ADMA requires at least 32 bit alignment */
-               value = max_t(u32, value, ALIGNMENT);
-               err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
-                                          sizeof(u32));
+               iovar = cpu_to_le32(max_t(u32, value, ALIGNMENT));
+               err = brcmf_iovar_data_set(dev, "bus:txglomalign", &iovar,
+                                          sizeof(iovar));
        }
 
        if (err < 0)
@@ -3555,9 +3560,9 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
        bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
        if (sdiodev->sg_support) {
                bus->txglom = false;
-               value = 1;
+               iovar = cpu_to_le32(1);
                err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
-                                          &value, sizeof(u32));
+                                          &iovar, sizeof(iovar));
                if (err < 0) {
                        /* bus:rxglom is allowed to fail */
                        err = 0;
@@ -4541,6 +4546,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
                brcmf_sdiod_intr_unregister(bus->sdiodev);
 
                brcmf_detach(bus->sdiodev->dev);
+               brcmf_free(bus->sdiodev->dev);
 
                cancel_work_sync(&bus->datawork);
                if (bus->brcmf_wq)
index c9fb4b0..2631eb7 100644 (file)
@@ -942,14 +942,19 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                index = TX_SEQ_TO_INDEX(seq);
                ack_recd = false;
                if (ba_recd) {
+                       int block_acked;
+
                        bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
+                       if (bindex < AMPDU_TX_BA_MAX_WSIZE)
+                               block_acked = isset(bitmap, bindex);
+                       else
+                               block_acked = 0;
                        brcms_dbg_ht(wlc->hw->d11core,
                                     "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n",
                                     tid, seq, start_seq, bindex,
-                                    isset(bitmap, bindex), index);
+                                    block_acked, index);
                        /* if acked then clear bit and free packet */
-                       if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
-                           && isset(bitmap, bindex)) {
+                       if (block_acked) {
                                ini->txretry[index] = 0;
 
                                /*
index 87b9398..ba62bb2 100644 (file)
@@ -1115,7 +1115,8 @@ static int enable_MAC(struct airo_info *ai, int lock);
 static void disable_MAC(struct airo_info *ai, int lock);
 static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
-static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
+static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp,
+                       bool may_sleep);
 static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
 static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
                        int whichbap);
@@ -1130,8 +1131,10 @@ static int PC4500_writerid(struct airo_info*, u16 rid, const void
 static int do_writerid(struct airo_info*, u16 rid, const void *rid_data,
                        int len, int dummy);
 static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
-static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
-static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
+static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket,
+                                bool may_sleep);
+static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket,
+                                 bool may_sleep);
 
 static int mpi_send_packet(struct net_device *dev);
 static void mpi_unmap_card(struct pci_dev *pci);
@@ -1144,7 +1147,6 @@ static int airo_thread(void *data);
 static void timer_func(struct net_device *dev);
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev);
-static void airo_read_wireless_stats(struct airo_info *local);
 #ifdef CISCO_EXT
 static int readrids(struct net_device *dev, aironet_ioctl *comp);
 static int writerids(struct net_device *dev, aironet_ioctl *comp);
@@ -1200,7 +1202,6 @@ struct airo_info {
 #define JOB_MIC        5
 #define JOB_EVENT      6
 #define JOB_AUTOWEP    7
-#define JOB_WSTATS     8
 #define JOB_SCAN_RESULTS  9
        unsigned long jobs;
        int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen,
@@ -1755,7 +1756,7 @@ static int readBSSListRid(struct airo_info *ai, int first,
                if (down_interruptible(&ai->sem))
                        return -ERESTARTSYS;
                ai->list_bss_task = current;
-               issuecommand(ai, &cmd, &rsp);
+               issuecommand(ai, &cmd, &rsp, true);
                up(&ai->sem);
                /* Let the command take effect */
                schedule_timeout_uninterruptible(3 * HZ);
@@ -2098,7 +2099,7 @@ static void get_tx_error(struct airo_info *ai, s32 fid)
        }
 }
 
-static void airo_end_xmit(struct net_device *dev)
+static void airo_end_xmit(struct net_device *dev, bool may_sleep)
 {
        u16 status;
        int i;
@@ -2109,7 +2110,7 @@ static void airo_end_xmit(struct net_device *dev)
 
        clear_bit(JOB_XMIT, &priv->jobs);
        clear_bit(FLAG_PENDING_XMIT, &priv->flags);
-       status = transmit_802_3_packet (priv, fids[fid], skb->data);
+       status = transmit_802_3_packet(priv, fids[fid], skb->data, may_sleep);
        up(&priv->sem);
 
        i = 0;
@@ -2166,11 +2167,11 @@ static netdev_tx_t airo_start_xmit(struct sk_buff *skb,
                set_bit(JOB_XMIT, &priv->jobs);
                wake_up_interruptible(&priv->thr_wait);
        } else
-               airo_end_xmit(dev);
+               airo_end_xmit(dev, false);
        return NETDEV_TX_OK;
 }
 
-static void airo_end_xmit11(struct net_device *dev)
+static void airo_end_xmit11(struct net_device *dev, bool may_sleep)
 {
        u16 status;
        int i;
@@ -2181,7 +2182,7 @@ static void airo_end_xmit11(struct net_device *dev)
 
        clear_bit(JOB_XMIT11, &priv->jobs);
        clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
-       status = transmit_802_11_packet (priv, fids[fid], skb->data);
+       status = transmit_802_11_packet(priv, fids[fid], skb->data, may_sleep);
        up(&priv->sem);
 
        i = MAX_FIDS / 2;
@@ -2245,7 +2246,7 @@ static netdev_tx_t airo_start_xmit11(struct sk_buff *skb,
                set_bit(JOB_XMIT11, &priv->jobs);
                wake_up_interruptible(&priv->thr_wait);
        } else
-               airo_end_xmit11(dev);
+               airo_end_xmit11(dev, false);
        return NETDEV_TX_OK;
 }
 
@@ -2288,18 +2289,14 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev)
        struct airo_info *local =  dev->ml_priv;
 
        if (!test_bit(JOB_STATS, &local->jobs)) {
-               /* Get stats out of the card if available */
-               if (down_trylock(&local->sem) != 0) {
-                       set_bit(JOB_STATS, &local->jobs);
-                       wake_up_interruptible(&local->thr_wait);
-               } else
-                       airo_read_stats(dev);
+               set_bit(JOB_STATS, &local->jobs);
+               wake_up_interruptible(&local->thr_wait);
        }
 
        return &dev->stats;
 }
 
-static void airo_set_promisc(struct airo_info *ai)
+static void airo_set_promisc(struct airo_info *ai, bool may_sleep)
 {
        Cmd cmd;
        Resp rsp;
@@ -2308,7 +2305,7 @@ static void airo_set_promisc(struct airo_info *ai)
        cmd.cmd = CMD_SETMODE;
        clear_bit(JOB_PROMISC, &ai->jobs);
        cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
-       issuecommand(ai, &cmd, &rsp);
+       issuecommand(ai, &cmd, &rsp, may_sleep);
        up(&ai->sem);
 }
 
@@ -2322,7 +2319,7 @@ static void airo_set_multicast_list(struct net_device *dev)
                        set_bit(JOB_PROMISC, &ai->jobs);
                        wake_up_interruptible(&ai->thr_wait);
                } else
-                       airo_set_promisc(ai);
+                       airo_set_promisc(ai, false);
        }
 
        if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
@@ -2482,7 +2479,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
        cmd.parm0 = FID_RX;
        cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
        cmd.parm2 = MPI_MAX_FIDS;
-       rc = issuecommand(ai, &cmd, &rsp);
+       rc = issuecommand(ai, &cmd, &rsp, true);
        if (rc != SUCCESS) {
                airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
                return rc;
@@ -2510,7 +2507,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
        }
        ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
 
-       rc = issuecommand(ai, &cmd, &rsp);
+       rc = issuecommand(ai, &cmd, &rsp, true);
        if (rc != SUCCESS) {
                airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
                return rc;
@@ -2524,7 +2521,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
        cmd.parm0 = RID_RW;
        cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
        cmd.parm2 = 1; /* Magic number... */
-       rc = issuecommand(ai, &cmd, &rsp);
+       rc = issuecommand(ai, &cmd, &rsp, true);
        if (rc != SUCCESS) {
                airo_print_err(ai->dev->name, "Couldn't allocate RID");
                return rc;
@@ -3150,15 +3147,13 @@ static int airo_thread(void *data)
                }
 
                if (test_bit(JOB_XMIT, &ai->jobs))
-                       airo_end_xmit(dev);
+                       airo_end_xmit(dev, true);
                else if (test_bit(JOB_XMIT11, &ai->jobs))
-                       airo_end_xmit11(dev);
+                       airo_end_xmit11(dev, true);
                else if (test_bit(JOB_STATS, &ai->jobs))
                        airo_read_stats(dev);
-               else if (test_bit(JOB_WSTATS, &ai->jobs))
-                       airo_read_wireless_stats(ai);
                else if (test_bit(JOB_PROMISC, &ai->jobs))
-                       airo_set_promisc(ai);
+                       airo_set_promisc(ai, true);
                else if (test_bit(JOB_MIC, &ai->jobs))
                        micinit(ai);
                else if (test_bit(JOB_EVENT, &ai->jobs))
@@ -3281,11 +3276,9 @@ static void airo_handle_link(struct airo_info *ai)
                set_bit(FLAG_UPDATE_UNI, &ai->flags);
                set_bit(FLAG_UPDATE_MULTI, &ai->flags);
 
-               if (down_trylock(&ai->sem) != 0) {
-                       set_bit(JOB_EVENT, &ai->jobs);
-                       wake_up_interruptible(&ai->thr_wait);
-               } else
-                       airo_send_event(ai->dev);
+               set_bit(JOB_EVENT, &ai->jobs);
+               wake_up_interruptible(&ai->thr_wait);
+
                netif_carrier_on(ai->dev);
        } else if (!scan_forceloss) {
                if (auto_wep && !ai->expires) {
@@ -3609,7 +3602,7 @@ static int enable_MAC(struct airo_info *ai, int lock)
        if (!test_bit(FLAG_ENABLED, &ai->flags)) {
                memset(&cmd, 0, sizeof(cmd));
                cmd.cmd = MAC_ENABLE;
-               rc = issuecommand(ai, &cmd, &rsp);
+               rc = issuecommand(ai, &cmd, &rsp, true);
                if (rc == SUCCESS)
                        set_bit(FLAG_ENABLED, &ai->flags);
        } else
@@ -3641,7 +3634,7 @@ static void disable_MAC(struct airo_info *ai, int lock)
                        netif_carrier_off(ai->dev);
                memset(&cmd, 0, sizeof(cmd));
                cmd.cmd = MAC_DISABLE; // disable in case already enabled
-               issuecommand(ai, &cmd, &rsp);
+               issuecommand(ai, &cmd, &rsp, true);
                clear_bit(FLAG_ENABLED, &ai->flags);
        }
        if (lock == 1)
@@ -3844,7 +3837,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
        cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
        if (lock && down_interruptible(&ai->sem))
                return ERROR;
-       if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+       if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
                if (lock)
                        up(&ai->sem);
                return ERROR;
@@ -3854,7 +3847,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
        // Let's figure out if we need to use the AUX port
        if (!test_bit(FLAG_MPI,&ai->flags)) {
                cmd.cmd = CMD_ENABLEAUX;
-               if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+               if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
                        if (lock)
                                up(&ai->sem);
                        airo_print_err(ai->dev->name, "Error checking for AUX port");
@@ -3966,7 +3959,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
        return SUCCESS;
 }
 
-static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp)
+static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp,
+                       bool may_sleep)
 {
         // Im really paranoid about letting it run forever!
        int max_tries = 600000;
@@ -3983,8 +3977,8 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp)
                if ((IN4500(ai, COMMAND)) == pCmd->cmd)
                        // PC4500 didn't notice command, try again
                        OUT4500(ai, COMMAND, pCmd->cmd);
-               if (!in_atomic() && (max_tries & 255) == 0)
-                       schedule();
+               if (may_sleep && (max_tries & 255) == 0)
+                       cond_resched();
        }
 
        if (max_tries == -1) {
@@ -4141,7 +4135,7 @@ static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
        memset(&cmd, 0, sizeof(cmd));
        cmd.cmd = accmd;
        cmd.parm0 = rid;
-       status = issuecommand(ai, &cmd, &rsp);
+       status = issuecommand(ai, &cmd, &rsp, true);
        if (status != 0) return status;
        if ((rsp.status & 0x7F00) != 0) {
                return (accmd << 8) + (rsp.rsp0 & 0xFF);
@@ -4177,7 +4171,7 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
                memcpy_toio(ai->config_desc.card_ram_off,
                        &ai->config_desc.rid_desc, sizeof(Rid));
 
-               rc = issuecommand(ai, &cmd, &rsp);
+               rc = issuecommand(ai, &cmd, &rsp, true);
 
                if (rsp.status & 0x7f00)
                        rc = rsp.rsp0;
@@ -4256,7 +4250,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
                        memcpy(ai->config_desc.virtual_host_addr,
                                pBuf, len);
 
-                       rc = issuecommand(ai, &cmd, &rsp);
+                       rc = issuecommand(ai, &cmd, &rsp, true);
                        if ((rc & 0xff00) != 0) {
                                airo_print_err(ai->dev->name, "%s: Write rid Error %d",
                                                __func__, rc);
@@ -4302,7 +4296,7 @@ static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
        cmd.parm0 = lenPayload;
        if (down_interruptible(&ai->sem))
                return ERROR;
-       if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+       if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
                txFid = ERROR;
                goto done;
        }
@@ -4348,7 +4342,8 @@ done:
 /* In general BAP1 is dedicated to transmiting packets.  However,
    since we need a BAP when accessing RIDs, we also use BAP1 for that.
    Make sure the BAP1 spinlock is held when this is called. */
-static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
+static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket,
+                                bool may_sleep)
 {
        __le16 payloadLen;
        Cmd cmd;
@@ -4386,12 +4381,14 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
        memset(&cmd, 0, sizeof(cmd));
        cmd.cmd = CMD_TRANSMIT;
        cmd.parm0 = txFid;
-       if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
+       if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS)
+               return ERROR;
        if ((rsp.status & 0xFF00) != 0) return ERROR;
        return SUCCESS;
 }
 
-static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
+static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket,
+                                 bool may_sleep)
 {
        __le16 fc, payloadLen;
        Cmd cmd;
@@ -4426,7 +4423,8 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
        memset(&cmd, 0, sizeof(cmd));
        cmd.cmd = CMD_TRANSMIT;
        cmd.parm0 = txFid;
-       if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
+       if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS)
+               return ERROR;
        if ((rsp.status & 0xFF00) != 0) return ERROR;
        return SUCCESS;
 }
@@ -5490,7 +5488,7 @@ static int proc_BSSList_open(struct inode *inode, struct file *file)
                                kfree(file->private_data);
                                return -ERESTARTSYS;
                        }
-                       issuecommand(ai, &cmd, &rsp);
+                       issuecommand(ai, &cmd, &rsp, true);
                        up(&ai->sem);
                        data->readlen = 0;
                        return 0;
@@ -5627,7 +5625,7 @@ static int __maybe_unused airo_pci_suspend(struct device *dev_d)
        netif_device_detach(dev);
        ai->power = PMSG_SUSPEND;
        cmd.cmd = HOSTSLEEP;
-       issuecommand(ai, &cmd, &rsp);
+       issuecommand(ai, &cmd, &rsp, true);
 
        device_wakeup_enable(dev_d);
        return 0;
@@ -5787,7 +5785,7 @@ static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
 }
 
 #define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
-#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50);
+#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50)
 
 /*------------------------------------------------------------------*/
 /*
@@ -5970,7 +5968,7 @@ static int airo_set_wap(struct net_device *dev,
                cmd.cmd = CMD_LOSE_SYNC;
                if (down_interruptible(&local->sem))
                        return -ERESTARTSYS;
-               issuecommand(local, &cmd, &rsp);
+               issuecommand(local, &cmd, &rsp, true);
                up(&local->sem);
        } else {
                memset(APList_rid, 0, sizeof(*APList_rid));
@@ -7268,7 +7266,7 @@ static int airo_set_scan(struct net_device *dev,
        ai->scan_timeout = RUN_AT(3*HZ);
        memset(&cmd, 0, sizeof(cmd));
        cmd.cmd = CMD_LISTBSS;
-       issuecommand(ai, &cmd, &rsp);
+       issuecommand(ai, &cmd, &rsp, true);
        wake = 1;
 
 out:
@@ -7535,7 +7533,7 @@ static int airo_config_commit(struct net_device *dev,
        writeConfigRid(local, 0);
        enable_MAC(local, 0);
        if (test_bit (FLAG_RESET, &local->flags))
-               airo_set_promisc(local);
+               airo_set_promisc(local, true);
        else
                up(&local->sem);
 
@@ -7732,15 +7730,12 @@ static void airo_read_wireless_stats(struct airo_info *local)
        __le32 *vals = stats_rid.vals;
 
        /* Get stats out of the card */
-       clear_bit(JOB_WSTATS, &local->jobs);
-       if (local->power.event) {
-               up(&local->sem);
+       if (local->power.event)
                return;
-       }
+
        readCapabilityRid(local, &cap_rid, 0);
        readStatusRid(local, &status_rid, 0);
        readStatsRid(local, &stats_rid, RID_STATS, 0);
-       up(&local->sem);
 
        /* The status */
        local->wstats.status = le16_to_cpu(status_rid.mode);
@@ -7783,15 +7778,10 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
 {
        struct airo_info *local =  dev->ml_priv;
 
-       if (!test_bit(JOB_WSTATS, &local->jobs)) {
-               /* Get stats out of the card if available */
-               if (down_trylock(&local->sem) != 0) {
-                       set_bit(JOB_WSTATS, &local->jobs);
-                       wake_up_interruptible(&local->thr_wait);
-               } else
-                       airo_read_wireless_stats(local);
+       if (!down_interruptible(&local->sem)) {
+               airo_read_wireless_stats(local);
+               up(&local->sem);
        }
-
        return &local->wstats;
 }
 
index cbdebef..8698ca4 100644 (file)
@@ -1202,13 +1202,11 @@ static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                return iwl_mvm_mac_ctxt_cmd_sta(mvm, vif, action,
                                                force_assoc_off,
                                                bssid_override);
-               break;
        case NL80211_IFTYPE_AP:
                if (!vif->p2p)
                        return iwl_mvm_mac_ctxt_cmd_ap(mvm, vif, action);
                else
                        return iwl_mvm_mac_ctxt_cmd_go(mvm, vif, action);
-               break;
        case NL80211_IFTYPE_MONITOR:
                return iwl_mvm_mac_ctxt_cmd_listener(mvm, vif, action);
        case NL80211_IFTYPE_P2P_DEVICE:
index 22cfb64..9a19046 100644 (file)
@@ -3169,22 +3169,15 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
 
        /* Initialize tasklets for handling hardware IRQ related operations
         * outside hw IRQ handler */
-#define HOSTAP_TASKLET_INIT(q, f, d) \
-do { memset((q), 0, sizeof(*(q))); (q)->func = (void(*)(unsigned long))(f); } \
-while (0)
-       HOSTAP_TASKLET_INIT(&local->bap_tasklet, hostap_bap_tasklet,
-                           (unsigned long) local);
-
-       HOSTAP_TASKLET_INIT(&local->info_tasklet, hostap_info_tasklet,
-                           (unsigned long) local);
+       tasklet_setup(&local->bap_tasklet, hostap_bap_tasklet);
+       tasklet_setup(&local->info_tasklet, hostap_info_tasklet);
        hostap_info_init(local);
 
-       HOSTAP_TASKLET_INIT(&local->rx_tasklet,
-                           hostap_rx_tasklet, (unsigned long) local);
+       tasklet_setup(&local->rx_tasklet, hostap_rx_tasklet);
        skb_queue_head_init(&local->rx_list);
 
-       HOSTAP_TASKLET_INIT(&local->sta_tx_exc_tasklet,
-                           hostap_sta_tx_exc_tasklet, (unsigned long) local);
+       tasklet_setup(&local->sta_tx_exc_tasklet,
+                           hostap_sta_tx_exc_tasklet);
        skb_queue_head_init(&local->sta_tx_exc_list);
 
        INIT_LIST_HEAD(&local->cmd_queue);
index 514c7b0..49766b2 100644 (file)
@@ -44,19 +44,8 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev)
 
        if (local->iw_mode != IW_MODE_MASTER &&
            local->iw_mode != IW_MODE_REPEAT) {
-               int update = 1;
-#ifdef in_atomic
-               /* RID reading might sleep and it must not be called in
-                * interrupt context or while atomic. However, this
-                * function seems to be called while atomic (at least in Linux
-                * 2.5.59). Update signal quality values only if in suitable
-                * context. Otherwise, previous values read from tick timer
-                * will be used. */
-               if (in_atomic())
-                       update = 0;
-#endif /* in_atomic */
-
-               if (update && prism2_update_comms_qual(dev) == 0)
+
+               if (prism2_update_comms_qual(dev) == 0)
                        wstats->qual.updated = IW_QUAL_ALL_UPDATED |
                                IW_QUAL_DBM;
 
index 43790fb..6d4b7f6 100644 (file)
@@ -763,6 +763,7 @@ static const struct hermes_ops hermes_ops_local = {
        .init_cmd_wait = hermes_doicmd_wait,
        .allocate = hermes_allocate,
        .read_ltv = hermes_read_ltv,
+       .read_ltv_pr = hermes_read_ltv,
        .write_ltv = hermes_write_ltv,
        .bap_pread = hermes_bap_pread,
        .bap_pwrite = hermes_bap_pwrite,
index 9f66818..3dc561a 100644 (file)
@@ -386,6 +386,8 @@ struct hermes_ops {
        int (*allocate)(struct hermes *hw, u16 size, u16 *fid);
        int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen,
                        u16 *length, void *buf);
+       int (*read_ltv_pr)(struct hermes *hw, int bap, u16 rid,
+                             unsigned buflen, u16 *length, void *buf);
        int (*write_ltv)(struct hermes *hw, int bap, u16 rid,
                         u16 length, const void *value);
        int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len,
@@ -494,6 +496,8 @@ static inline void hermes_clear_words(struct hermes *hw, int off,
 
 #define HERMES_READ_RECORD(hw, bap, rid, buf) \
        (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
+#define HERMES_READ_RECORD_PR(hw, bap, rid, buf) \
+       (hw->ops->read_ltv_pr((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
 #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
        (hw->ops->write_ltv((hw), (bap), (rid), \
                            HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
@@ -509,6 +513,17 @@ static inline int hermes_read_wordrec(struct hermes *hw, int bap, u16 rid,
        return err;
 }
 
+static inline int hermes_read_wordrec_pr(struct hermes *hw, int bap, u16 rid,
+                                        u16 *word)
+{
+       __le16 rec;
+       int err;
+
+       err = HERMES_READ_RECORD_PR(hw, bap, rid, &rec);
+       *word = le16_to_cpu(rec);
+       return err;
+}
+
 static inline int hermes_write_wordrec(struct hermes *hw, int bap, u16 rid,
                                       u16 word)
 {
index 61af5a2..2c7adb4 100644 (file)
@@ -78,7 +78,7 @@ int determine_fw_capabilities(struct orinoco_private *priv,
        char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2)));
 
        /* Get the hardware version */
-       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+       err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
        if (err) {
                dev_err(dev, "Cannot read hardware identity: error %d\n",
                        err);
@@ -101,7 +101,7 @@ int determine_fw_capabilities(struct orinoco_private *priv,
        priv->firmware_type = determine_firmware_type(&nic_id);
 
        /* Get the firmware version */
-       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
+       err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
        if (err) {
                dev_err(dev, "Cannot read station identity: error %d\n",
                        err);
@@ -177,7 +177,7 @@ int determine_fw_capabilities(struct orinoco_private *priv,
                /* 3Com MAC : 00:50:DA:* */
                memset(tmp, 0, sizeof(tmp));
                /* Get the Symbol firmware version */
-               err = hw->ops->read_ltv(hw, USER_BAP,
+               err = hw->ops->read_ltv_pr(hw, USER_BAP,
                                        HERMES_RID_SECONDARYVERSION_SYMBOL,
                                        SYMBOL_MAX_VER_LEN, NULL, &tmp);
                if (err) {
@@ -286,7 +286,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        u16 reclen;
 
        /* Get the MAC address */
-       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+       err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
                                ETH_ALEN, NULL, dev_addr);
        if (err) {
                dev_warn(dev, "Failed to read MAC address!\n");
@@ -296,7 +296,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        dev_dbg(dev, "MAC address %pM\n", dev_addr);
 
        /* Get the station name */
-       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+       err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
                                sizeof(nickbuf), &reclen, &nickbuf);
        if (err) {
                dev_err(dev, "failed to read station name\n");
@@ -312,7 +312,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
 
        /* Get allowed channels */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+       err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST,
                                  &priv->channel_mask);
        if (err) {
                dev_err(dev, "Failed to read channel list!\n");
@@ -320,13 +320,13 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        }
 
        /* Get initial AP density */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+       err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
                                  &priv->ap_density);
        if (err || priv->ap_density < 1 || priv->ap_density > 3)
                priv->has_sensitivity = 0;
 
        /* Get initial RTS threshold */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+       err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
                                  &priv->rts_thresh);
        if (err) {
                dev_err(dev, "Failed to read RTS threshold!\n");
@@ -335,11 +335,11 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
 
        /* Get initial fragmentation settings */
        if (priv->has_mwo)
-               err = hermes_read_wordrec(hw, USER_BAP,
+               err = hermes_read_wordrec_pr(hw, USER_BAP,
                                          HERMES_RID_CNFMWOROBUST_AGERE,
                                          &priv->mwo_robust);
        else
-               err = hermes_read_wordrec(hw, USER_BAP,
+               err = hermes_read_wordrec_pr(hw, USER_BAP,
                                          HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
                                          &priv->frag_thresh);
        if (err) {
@@ -351,7 +351,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        if (priv->has_pm) {
                priv->pm_on = 0;
                priv->pm_mcast = 1;
-               err = hermes_read_wordrec(hw, USER_BAP,
+               err = hermes_read_wordrec_pr(hw, USER_BAP,
                                          HERMES_RID_CNFMAXSLEEPDURATION,
                                          &priv->pm_period);
                if (err) {
@@ -359,7 +359,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
                                "period!\n");
                        goto out;
                }
-               err = hermes_read_wordrec(hw, USER_BAP,
+               err = hermes_read_wordrec_pr(hw, USER_BAP,
                                          HERMES_RID_CNFPMHOLDOVERDURATION,
                                          &priv->pm_timeout);
                if (err) {
@@ -371,7 +371,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
 
        /* Preamble setup */
        if (priv->has_preamble) {
-               err = hermes_read_wordrec(hw, USER_BAP,
+               err = hermes_read_wordrec_pr(hw, USER_BAP,
                                          HERMES_RID_CNFPREAMBLE_SYMBOL,
                                          &priv->preamble);
                if (err) {
@@ -381,21 +381,21 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        }
 
        /* Retry settings */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
+       err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
                                  &priv->short_retry_limit);
        if (err) {
                dev_err(dev, "Failed to read short retry limit\n");
                goto out;
        }
 
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
+       err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
                                  &priv->long_retry_limit);
        if (err) {
                dev_err(dev, "Failed to read long retry limit\n");
                goto out;
        }
 
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
+       err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
                                  &priv->retry_lifetime);
        if (err) {
                dev_err(dev, "Failed to read max retry lifetime\n");
index b849d27..dd31929 100644 (file)
@@ -665,26 +665,43 @@ static void ezusb_request_in_callback(struct ezusb_priv *upriv,
        }                       /* switch */
 }
 
+typedef void (*ezusb_ctx_wait)(struct ezusb_priv *, struct request_context *);
 
-static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
-                              struct request_context *ctx)
+static void ezusb_req_ctx_wait_compl(struct ezusb_priv *upriv,
+                                    struct request_context *ctx)
 {
        switch (ctx->state) {
        case EZUSB_CTX_QUEUED:
        case EZUSB_CTX_REQ_SUBMITTED:
        case EZUSB_CTX_REQ_COMPLETE:
        case EZUSB_CTX_RESP_RECEIVED:
-               if (in_softirq()) {
-                       /* If we get called from a timer, timeout timers don't
-                        * get the chance to run themselves. So we make sure
-                        * that we don't sleep for ever */
-                       int msecs = DEF_TIMEOUT * (1000 / HZ);
-
-                       while (!try_wait_for_completion(&ctx->done) && msecs--)
-                               udelay(1000);
-               } else {
-                       wait_for_completion(&ctx->done);
-               }
+               wait_for_completion(&ctx->done);
+               break;
+       default:
+               /* Done or failed - nothing to wait for */
+               break;
+       }
+}
+
+static void ezusb_req_ctx_wait_poll(struct ezusb_priv *upriv,
+                                   struct request_context *ctx)
+{
+       int msecs;
+
+       switch (ctx->state) {
+       case EZUSB_CTX_QUEUED:
+       case EZUSB_CTX_REQ_SUBMITTED:
+       case EZUSB_CTX_REQ_COMPLETE:
+       case EZUSB_CTX_RESP_RECEIVED:
+               /* If we get called from a timer or with our lock acquired, then
+                * we can't wait for the completion and have to poll. This won't
+                * happen if the USB controller completes the URB requests in
+                * BH.
+                */
+               msecs = DEF_TIMEOUT * (1000 / HZ);
+
+               while (!try_wait_for_completion(&ctx->done) && msecs--)
+                       udelay(1000);
                break;
        default:
                /* Done or failed - nothing to wait for */
@@ -692,6 +709,12 @@ static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
        }
 }
 
+static void ezusb_req_ctx_wait_skip(struct ezusb_priv *upriv,
+                                   struct request_context *ctx)
+{
+       WARN(1, "Shouldn't be invoked for in_rid\n");
+}
+
 static inline u16 build_crc(struct ezusb_packet *data)
 {
        u16 crc = 0;
@@ -853,14 +876,13 @@ static int ezusb_firmware_download(struct ezusb_priv *upriv,
 static int ezusb_access_ltv(struct ezusb_priv *upriv,
                            struct request_context *ctx,
                            u16 length, const void *data, u16 frame_type,
-                           void *ans_buff, unsigned ans_size, u16 *ans_length)
+                           void *ans_buff, unsigned ans_size, u16 *ans_length,
+                           ezusb_ctx_wait ezusb_ctx_wait_func)
 {
        int req_size;
        int retval = 0;
        enum ezusb_state state;
 
-       BUG_ON(in_irq());
-
        if (!upriv->udev) {
                retval = -ENODEV;
                goto exit;
@@ -885,7 +907,7 @@ static int ezusb_access_ltv(struct ezusb_priv *upriv,
        spin_unlock_bh(&upriv->reply_count_lock);
 
        if (ctx->in_rid)
-               ezusb_req_ctx_wait(upriv, ctx);
+               ezusb_ctx_wait_func(upriv, ctx);
 
        state = ctx->state;
        switch (state) {
@@ -946,8 +968,9 @@ static int ezusb_access_ltv(struct ezusb_priv *upriv,
        return retval;
 }
 
-static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
-                          u16 length, const void *data)
+static int __ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
+                          u16 length, const void *data,
+                          ezusb_ctx_wait ezusb_ctx_wait_func)
 {
        struct ezusb_priv *upriv = hw->priv;
        u16 frame_type;
@@ -973,11 +996,20 @@ static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
                frame_type = EZUSB_FRAME_CONTROL;
 
        return ezusb_access_ltv(upriv, ctx, length, data, frame_type,
-                               NULL, 0, NULL);
+                               NULL, 0, NULL, ezusb_ctx_wait_func);
 }
 
-static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
-                         unsigned bufsize, u16 *length, void *buf)
+static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
+                          u16 length, const void *data)
+{
+       return __ezusb_write_ltv(hw, bap, rid, length, data,
+                                ezusb_req_ctx_wait_poll);
+}
+
+static int __ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
+                           unsigned bufsize, u16 *length, void *buf,
+                           ezusb_ctx_wait ezusb_ctx_wait_func)
+
 {
        struct ezusb_priv *upriv = hw->priv;
        struct request_context *ctx;
@@ -990,34 +1022,33 @@ static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
                return -ENOMEM;
 
        return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL,
-                               buf, bufsize, length);
+                               buf, bufsize, length, ezusb_req_ctx_wait_poll);
 }
 
-static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1,
-                            u16 parm2, struct hermes_response *resp)
+static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
+                           unsigned bufsize, u16 *length, void *buf)
 {
-       struct ezusb_priv *upriv = hw->priv;
-       struct request_context *ctx;
+       return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf,
+                               ezusb_req_ctx_wait_poll);
+}
 
-       __le16 data[4] = {
-               cpu_to_le16(cmd),
-               cpu_to_le16(parm0),
-               cpu_to_le16(parm1),
-               cpu_to_le16(parm2),
-       };
-       netdev_dbg(upriv->dev,
-                  "0x%04X, parm0 0x%04X, parm1 0x%04X, parm2 0x%04X\n", cmd,
-                  parm0, parm1, parm2);
-       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
-       if (!ctx)
-               return -ENOMEM;
+static int ezusb_read_ltv_preempt(struct hermes *hw, int bap, u16 rid,
+                                 unsigned bufsize, u16 *length, void *buf)
+{
+       return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf,
+                               ezusb_req_ctx_wait_compl);
+}
 
-       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
-                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1,
+                            u16 parm2, struct hermes_response *resp)
+{
+       WARN_ON_ONCE(1);
+       return -EINVAL;
 }
 
-static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
-                           struct hermes_response *resp)
+static int __ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
+                           struct hermes_response *resp,
+                           ezusb_ctx_wait ezusb_ctx_wait_func)
 {
        struct ezusb_priv *upriv = hw->priv;
        struct request_context *ctx;
@@ -1034,7 +1065,14 @@ static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
                return -ENOMEM;
 
        return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
-                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL,
+                               ezusb_ctx_wait_func);
+}
+
+static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
+                           struct hermes_response *resp)
+{
+       return __ezusb_docmd_wait(hw, cmd, parm0, resp, ezusb_req_ctx_wait_poll);
 }
 
 static int ezusb_bap_pread(struct hermes *hw, int bap,
@@ -1092,7 +1130,7 @@ static int ezusb_read_pda(struct hermes *hw, __le16 *pda,
 
        return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
                                EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4,
-                               NULL);
+                               NULL, ezusb_req_ctx_wait_compl);
 }
 
 static int ezusb_program_init(struct hermes *hw, u32 entry_point)
@@ -1106,7 +1144,8 @@ static int ezusb_program_init(struct hermes *hw, u32 entry_point)
                return -ENOMEM;
 
        return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
-                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL,
+                               ezusb_req_ctx_wait_compl);
 }
 
 static int ezusb_program_end(struct hermes *hw)
@@ -1119,7 +1158,8 @@ static int ezusb_program_end(struct hermes *hw)
                return -ENOMEM;
 
        return ezusb_access_ltv(upriv, ctx, 0, NULL,
-                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL,
+                               ezusb_req_ctx_wait_compl);
 }
 
 static int ezusb_program_bytes(struct hermes *hw, const char *buf,
@@ -1135,7 +1175,8 @@ static int ezusb_program_bytes(struct hermes *hw, const char *buf,
                return -ENOMEM;
 
        err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
-                              EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+                              EZUSB_FRAME_CONTROL, NULL, 0, NULL,
+                              ezusb_req_ctx_wait_compl);
        if (err)
                return err;
 
@@ -1144,7 +1185,8 @@ static int ezusb_program_bytes(struct hermes *hw, const char *buf,
                return -ENOMEM;
 
        return ezusb_access_ltv(upriv, ctx, len, buf,
-                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL,
+                               ezusb_req_ctx_wait_compl);
 }
 
 static int ezusb_program(struct hermes *hw, const char *buf,
@@ -1223,13 +1265,6 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
        if (skb->len < ETH_HLEN)
                goto drop;
 
-       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
-       if (!ctx)
-               goto busy;
-
-       memset(ctx->buf, 0, BULK_BUF_SIZE);
-       buf = ctx->buf->data;
-
        tx_control = 0;
 
        err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
@@ -1237,6 +1272,13 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
        if (err)
                goto drop;
 
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
+       if (!ctx)
+               goto drop;
+
+       memset(ctx->buf, 0, BULK_BUF_SIZE);
+       buf = ctx->buf->data;
+
        {
                __le16 *tx_cntl = (__le16 *)buf;
                *tx_cntl = cpu_to_le16(tx_control);
@@ -1264,7 +1306,8 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
        tx_size = ALIGN(buf - ctx->buf->data, 2);
 
        err = ezusb_access_ltv(upriv, ctx, tx_size, NULL,
-                              EZUSB_FRAME_DATA, NULL, 0, NULL);
+                              EZUSB_FRAME_DATA, NULL, 0, NULL,
+                              ezusb_req_ctx_wait_skip);
 
        if (err) {
                netif_start_queue(dev);
@@ -1349,7 +1392,6 @@ static int ezusb_init(struct hermes *hw)
        struct ezusb_priv *upriv = hw->priv;
        int retval;
 
-       BUG_ON(in_interrupt());
        if (!upriv)
                return -EINVAL;
 
@@ -1362,14 +1404,16 @@ static int ezusb_init(struct hermes *hw)
        usb_kill_urb(upriv->read_urb);
        ezusb_submit_in_urb(upriv);
 
-       retval = ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1,
-                                HERMES_BYTES_TO_RECLEN(2), "\x10\x00");
+       retval = __ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1,
+                                HERMES_BYTES_TO_RECLEN(2), "\x10\x00",
+                                ezusb_req_ctx_wait_compl);
        if (retval < 0) {
                printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval);
                return retval;
        }
 
-       retval = ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL);
+       retval = __ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL,
+                                   ezusb_req_ctx_wait_compl);
        if (retval < 0) {
                printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval);
                return retval;
@@ -1448,7 +1492,6 @@ static inline void ezusb_delete(struct ezusb_priv *upriv)
        struct list_head *tmp_item;
        unsigned long flags;
 
-       BUG_ON(in_interrupt());
        BUG_ON(!upriv);
 
        mutex_lock(&upriv->mtx);
@@ -1533,6 +1576,7 @@ static const struct hermes_ops ezusb_ops = {
        .init_cmd_wait = ezusb_doicmd_wait,
        .allocate = ezusb_allocate,
        .read_ltv = ezusb_read_ltv,
+       .read_ltv_pr = ezusb_read_ltv_preempt,
        .write_ltv = ezusb_write_ltv,
        .bap_pread = ezusb_bap_pread,
        .read_pda = ezusb_read_pda,
index 2076f44..5e5ceaf 100644 (file)
@@ -54,7 +54,7 @@ static const unsigned char scan_rate_list[] = { 2, 4, 11, 22,
 
 /**
  * prism54_mib_mode_helper - MIB change mode helper function
- * @mib: the &struct islpci_mib object to modify
+ * @priv: the &struct islpci_private object to modify
  * @iw_mode: new mode (%IW_MODE_*)
  *
  *  This is a helper function, hence it does not lock. Make sure
@@ -114,14 +114,13 @@ prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
        return 0;
 }
 
-/**
+/*
  * prism54_mib_init - fill MIB cache with defaults
  *
  *  this function initializes the struct given as @mib with defaults,
  *  of which many are retrieved from the global module parameter
  *  variables.
  */
-
 void
 prism54_mib_init(islpci_private *priv)
 {
index 9ba8a8f..ee52fb8 100644 (file)
@@ -1455,7 +1455,7 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter)
 }
 
 /*
- * This function gets called during PCIe function level reset.
+ * This function can be used for shutting down the adapter SW.
  */
 int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter)
 {
@@ -1471,6 +1471,8 @@ int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter)
        priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
        mwifiex_deauthenticate(priv, NULL);
 
+       mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN);
+
        mwifiex_uninit_sw(adapter);
        adapter->is_up = false;
 
@@ -1481,7 +1483,7 @@ int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter)
 }
 EXPORT_SYMBOL_GPL(mwifiex_shutdown_sw);
 
-/* This function gets called during PCIe function level reset. Required
+/* This function can be used for reinitting the adapter SW. Required
  * code is extracted from mwifiex_add_card()
  */
 int
index 6a10ff0..5f0a61b 100644 (file)
@@ -429,7 +429,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        struct mwifiex_private *priv;
        const struct mwifiex_pcie_card_reg *reg;
        u32 fw_status;
-       int ret;
 
        card = pci_get_drvdata(pdev);
 
@@ -441,7 +440,7 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
 
        reg = card->pcie.reg;
        if (reg)
-               ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
+               mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
        else
                fw_status = -1;
 
@@ -526,6 +525,8 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev)
        clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
        clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
        mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+
+       card->pci_reset_ongoing = true;
 }
 
 /*
@@ -554,6 +555,8 @@ static void mwifiex_pcie_reset_done(struct pci_dev *pdev)
                dev_err(&pdev->dev, "reinit failed: %d\n", ret);
        else
                mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+
+       card->pci_reset_ongoing = false;
 }
 
 static const struct pci_error_handlers mwifiex_pcie_err_handler = {
@@ -3139,12 +3142,23 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter)
        struct pcie_service_card *card = adapter->card;
        struct pci_dev *pdev = card->dev;
        const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
-       int ret;
        u32 fw_status;
 
-       cancel_work_sync(&card->work);
+       /* Perform the cancel_work_sync() only when we're not resetting
+        * the card. It's because that function never returns if we're
+        * in reset path. If we're here when resetting the card, it means
+        * that we failed to reset the card (reset failure path).
+        */
+       if (!card->pci_reset_ongoing) {
+               mwifiex_dbg(adapter, MSG, "performing cancel_work_sync()...\n");
+               cancel_work_sync(&card->work);
+               mwifiex_dbg(adapter, MSG, "cancel_work_sync() done\n");
+       } else {
+               mwifiex_dbg(adapter, MSG,
+                           "skipped cancel_work_sync() because we're in card reset failure path\n");
+       }
 
-       ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
+       mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
        if (fw_status == FIRMWARE_READY_PCIE) {
                mwifiex_dbg(adapter, INFO,
                            "Clearing driver ready signature\n");
index 843d57e..5ed613d 100644 (file)
@@ -242,6 +242,8 @@ struct pcie_service_card {
        struct mwifiex_msix_context share_irq_ctx;
        struct work_struct work;
        unsigned long work_flags;
+
+       bool pci_reset_ongoing;
 };
 
 static inline int
index dec534a..5648512 100644 (file)
@@ -43,8 +43,6 @@
 #define BLOCK_MODE     1
 #define BYTE_MODE      0
 
-#define REG_PORT                       0
-
 #define MWIFIEX_SDIO_IO_PORT_MASK              0xfffff
 
 #define MWIFIEX_SDIO_BYTE_MODE_MASK    0x80000000
index 119ccac..6b5d35d 100644 (file)
@@ -201,6 +201,7 @@ static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
                        mwifiex_dbg(priv->adapter, INFO,
                                    "info: SNMP_RESP: DTIM period=%u\n",
                                    ul_temp);
+                       break;
                default:
                        break;
                }
@@ -1393,6 +1394,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
                break;
        case HostCmd_CMD_TDLS_OPER:
                ret = mwifiex_ret_tdls_oper(priv, resp);
+               break;
        case HostCmd_CMD_MC_POLICY:
                break;
        case HostCmd_CMD_CHAN_REPORT_REQUEST:
index bc79ca4..68c6326 100644 (file)
@@ -99,6 +99,7 @@ static int mwifiex_check_ibss_peer_capabilities(struct mwifiex_private *priv,
                        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
                                sta_ptr->max_amsdu =
                                        MWIFIEX_TX_DATA_BUF_SIZE_4K;
+                               break;
                        default:
                                break;
                        }
index b48a85d..18e8977 100644 (file)
@@ -108,6 +108,7 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
                        if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
                                bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
                                                                CIPHER_AES_CCMP;
+                       break;
                default:
                        break;
                }
index b8f19ca..0b37560 100644 (file)
@@ -1396,6 +1396,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb, 0, ret);
+               break;
        default:
                break;
        }
index 09f931d..5f99054 100644 (file)
@@ -212,9 +212,9 @@ out:
        spin_unlock_irqrestore(&dev->rx_lock, flags);
 }
 
-static void mt7601u_rx_tasklet(unsigned long data)
+static void mt7601u_rx_tasklet(struct tasklet_struct *t)
 {
-       struct mt7601u_dev *dev = (struct mt7601u_dev *) data;
+       struct mt7601u_dev *dev = from_tasklet(dev, t, rx_tasklet);
        struct mt7601u_dma_buf_rx *e;
 
        while ((e = mt7601u_rx_get_pending_entry(dev))) {
@@ -266,9 +266,9 @@ out:
        spin_unlock_irqrestore(&dev->tx_lock, flags);
 }
 
-static void mt7601u_tx_tasklet(unsigned long data)
+static void mt7601u_tx_tasklet(struct tasklet_struct *t)
 {
-       struct mt7601u_dev *dev = (struct mt7601u_dev *) data;
+       struct mt7601u_dev *dev = from_tasklet(dev, t, tx_tasklet);
        struct sk_buff_head skbs;
        unsigned long flags;
 
@@ -507,8 +507,8 @@ int mt7601u_dma_init(struct mt7601u_dev *dev)
 {
        int ret = -ENOMEM;
 
-       tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev);
-       tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev);
+       tasklet_setup(&dev->tx_tasklet, mt7601u_tx_tasklet);
+       tasklet_setup(&dev->rx_tasklet, mt7601u_rx_tasklet);
 
        ret = mt7601u_alloc_tx(dev);
        if (ret)
index c1ac1d8..e3dd205 100644 (file)
@@ -1709,7 +1709,7 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
 {
        struct wilc *wl;
        struct wilc_vif *vif;
-       int ret;
+       int ret, i;
 
        wl = wilc_create_wiphy(dev);
        if (!wl)
@@ -1725,7 +1725,10 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
        wl->io_type = io_type;
        wl->hif_func = ops;
        wl->chip_ps_state = WILC_CHIP_WAKEDUP;
-       INIT_LIST_HEAD(&wl->txq_head.list);
+
+       for (i = 0; i < NQUEUES; i++)
+               INIT_LIST_HEAD(&wl->txq[i].txq_head.list);
+
        INIT_LIST_HEAD(&wl->rxq_head.list);
        INIT_LIST_HEAD(&wl->vif_list);
 
index d025a30..a133736 100644 (file)
@@ -1276,6 +1276,23 @@ int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
        return result;
 }
 
+int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr)
+{
+       struct wid wid;
+       int result;
+
+       wid.id = WID_MAC_ADDR;
+       wid.type = WID_STR;
+       wid.size = ETH_ALEN;
+       wid.val = mac_addr;
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to get mac address\n");
+
+       return result;
+}
+
 int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
                      size_t ies_len)
 {
index db91791..5881191 100644 (file)
@@ -168,6 +168,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
                    u8 cipher_mode);
 int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid);
 int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr);
+int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr);
 int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
                      size_t ies_len);
 int wilc_disconnect(struct wilc_vif *vif);
index 20615c7..2a1fbbd 100644 (file)
@@ -628,6 +628,43 @@ static struct net_device_stats *mac_stats(struct net_device *dev)
        return &vif->netstats;
 }
 
+static int wilc_set_mac_addr(struct net_device *dev, void *p)
+{
+       int result;
+       struct wilc_vif *vif = netdev_priv(dev);
+       struct wilc *wilc = vif->wilc;
+       struct sockaddr *addr = (struct sockaddr *)p;
+       unsigned char mac_addr[ETH_ALEN];
+       struct wilc_vif *tmp_vif;
+       int srcu_idx;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EINVAL;
+
+       srcu_idx = srcu_read_lock(&wilc->srcu);
+       list_for_each_entry_rcu(tmp_vif, &wilc->vif_list, list) {
+               wilc_get_mac_address(tmp_vif, mac_addr);
+               if (ether_addr_equal(addr->sa_data, mac_addr)) {
+                       if (vif != tmp_vif) {
+                               srcu_read_unlock(&wilc->srcu, srcu_idx);
+                               return -EINVAL;
+                       }
+                       srcu_read_unlock(&wilc->srcu, srcu_idx);
+                       return 0;
+               }
+       }
+       srcu_read_unlock(&wilc->srcu, srcu_idx);
+
+       result = wilc_set_mac_address(vif, (u8 *)addr->sa_data);
+       if (result)
+               return result;
+
+       ether_addr_copy(vif->bssid, addr->sa_data);
+       ether_addr_copy(vif->ndev->dev_addr, addr->sa_data);
+
+       return result;
+}
+
 static void wilc_set_multicast_list(struct net_device *dev)
 {
        struct netdev_hw_addr *ha;
@@ -813,6 +850,7 @@ static const struct net_device_ops wilc_netdev_ops = {
        .ndo_init = mac_init_fn,
        .ndo_open = wilc_mac_open,
        .ndo_stop = wilc_mac_close,
+       .ndo_set_mac_address = wilc_set_mac_addr,
        .ndo_start_xmit = wilc_mac_xmit,
        .ndo_get_stats = mac_stats,
        .ndo_set_rx_mode  = wilc_set_multicast_list,
index d0a006b..86209b3 100644 (file)
@@ -197,6 +197,14 @@ struct wilc_vif {
        struct cfg80211_bss *bss;
 };
 
+struct wilc_tx_queue_status {
+       u8 buffer[AC_BUFFER_SIZE];
+       u16 end_index;
+       u16 cnt[NQUEUES];
+       u16 sum;
+       bool initialized;
+};
+
 struct wilc {
        struct wiphy *wiphy;
        const struct wilc_hif_func *hif_func;
@@ -245,9 +253,10 @@ struct wilc {
        u32 rx_buffer_offset;
        u8 *tx_buffer;
 
-       struct txq_entry_t txq_head;
+       struct txq_handle txq[NQUEUES];
        int txq_entries;
 
+       struct wilc_tx_queue_status tx_q_limit;
        struct rxq_entry_t rxq_head;
 
        const struct firmware *firmware;
index 6a82fb2..993ea7c 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/ip.h>
+#include <net/dsfield.h>
 #include "cfg80211.h"
 #include "wlan_cfg.h"
 
@@ -28,33 +29,34 @@ static inline void release_bus(struct wilc *wilc, enum bus_release release)
        mutex_unlock(&wilc->hif_cs);
 }
 
-static void wilc_wlan_txq_remove(struct wilc *wilc, struct txq_entry_t *tqe)
+static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num,
+                                struct txq_entry_t *tqe)
 {
        list_del(&tqe->list);
        wilc->txq_entries -= 1;
+       wilc->txq[q_num].count--;
 }
 
 static struct txq_entry_t *
-wilc_wlan_txq_remove_from_head(struct net_device *dev)
+wilc_wlan_txq_remove_from_head(struct wilc *wilc, u8 q_num)
 {
        struct txq_entry_t *tqe = NULL;
        unsigned long flags;
-       struct wilc_vif *vif = netdev_priv(dev);
-       struct wilc *wilc = vif->wilc;
 
        spin_lock_irqsave(&wilc->txq_spinlock, flags);
 
-       if (!list_empty(&wilc->txq_head.list)) {
-               tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t,
-                                      list);
+       if (!list_empty(&wilc->txq[q_num].txq_head.list)) {
+               tqe = list_first_entry(&wilc->txq[q_num].txq_head.list,
+                                      struct txq_entry_t, list);
                list_del(&tqe->list);
                wilc->txq_entries -= 1;
+               wilc->txq[q_num].count--;
        }
        spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
        return tqe;
 }
 
-static void wilc_wlan_txq_add_to_tail(struct net_device *dev,
+static void wilc_wlan_txq_add_to_tail(struct net_device *dev, u8 q_num,
                                      struct txq_entry_t *tqe)
 {
        unsigned long flags;
@@ -63,15 +65,16 @@ static void wilc_wlan_txq_add_to_tail(struct net_device *dev,
 
        spin_lock_irqsave(&wilc->txq_spinlock, flags);
 
-       list_add_tail(&tqe->list, &wilc->txq_head.list);
+       list_add_tail(&tqe->list, &wilc->txq[q_num].txq_head.list);
        wilc->txq_entries += 1;
+       wilc->txq[q_num].count++;
 
        spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
 
        complete(&wilc->txq_event);
 }
 
-static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif,
+static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, u8 q_num,
                                      struct txq_entry_t *tqe)
 {
        unsigned long flags;
@@ -81,8 +84,9 @@ static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif,
 
        spin_lock_irqsave(&wilc->txq_spinlock, flags);
 
-       list_add(&tqe->list, &wilc->txq_head.list);
+       list_add(&tqe->list, &wilc->txq[q_num].txq_head.list);
        wilc->txq_entries += 1;
+       wilc->txq[q_num].count++;
 
        spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
        mutex_unlock(&wilc->txq_add_to_head_cs);
@@ -212,7 +216,7 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
 
                        tqe = f->pending_acks[i].txqe;
                        if (tqe) {
-                               wilc_wlan_txq_remove(wilc, tqe);
+                               wilc_wlan_txq_remove(wilc, tqe->q_num, tqe);
                                tqe->status = 1;
                                if (tqe->tx_complete_func)
                                        tqe->tx_complete_func(tqe->priv,
@@ -258,18 +262,148 @@ static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
        }
 
        tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
-       if (!tqe)
+       if (!tqe) {
+               complete(&wilc->cfg_event);
                return 0;
+       }
 
        tqe->type = WILC_CFG_PKT;
        tqe->buffer = buffer;
        tqe->buffer_size = buffer_size;
        tqe->tx_complete_func = NULL;
        tqe->priv = NULL;
+       tqe->q_num = AC_VO_Q;
        tqe->ack_idx = NOT_TCP_ACK;
        tqe->vif = vif;
 
-       wilc_wlan_txq_add_to_head(vif, tqe);
+       wilc_wlan_txq_add_to_head(vif, AC_VO_Q, tqe);
+
+       return 1;
+}
+
+static bool is_ac_q_limit(struct wilc *wl, u8 q_num)
+{
+       u8 factors[NQUEUES] = {1, 1, 1, 1};
+       u16 i;
+       unsigned long flags;
+       struct wilc_tx_queue_status *q = &wl->tx_q_limit;
+       u8 end_index;
+       u8 q_limit;
+       bool ret = false;
+
+       spin_lock_irqsave(&wl->txq_spinlock, flags);
+       if (!q->initialized) {
+               for (i = 0; i < AC_BUFFER_SIZE; i++)
+                       q->buffer[i] = i % NQUEUES;
+
+               for (i = 0; i < NQUEUES; i++) {
+                       q->cnt[i] = AC_BUFFER_SIZE * factors[i] / NQUEUES;
+                       q->sum += q->cnt[i];
+               }
+               q->end_index = AC_BUFFER_SIZE - 1;
+               q->initialized = 1;
+       }
+
+       end_index = q->end_index;
+       q->cnt[q->buffer[end_index]] -= factors[q->buffer[end_index]];
+       q->cnt[q_num] += factors[q_num];
+       q->sum += (factors[q_num] - factors[q->buffer[end_index]]);
+
+       q->buffer[end_index] = q_num;
+       if (end_index > 0)
+               q->end_index--;
+       else
+               q->end_index = AC_BUFFER_SIZE - 1;
+
+       if (!q->sum)
+               q_limit = 1;
+       else
+               q_limit = (q->cnt[q_num] * FLOW_CONTROL_UPPER_THRESHOLD / q->sum) + 1;
+
+       if (wl->txq[q_num].count <= q_limit)
+               ret = true;
+
+       spin_unlock_irqrestore(&wl->txq_spinlock, flags);
+
+       return ret;
+}
+
+static inline u8 ac_classify(struct wilc *wilc, struct sk_buff *skb)
+{
+       u8 q_num = AC_BE_Q;
+       u8 dscp;
+
+       switch (skb->protocol) {
+       case htons(ETH_P_IP):
+               dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
+               break;
+       case htons(ETH_P_IPV6):
+               dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc;
+               break;
+       default:
+               return q_num;
+       }
+
+       switch (dscp) {
+       case 0x08:
+       case 0x20:
+       case 0x40:
+               q_num = AC_BK_Q;
+               break;
+       case 0x80:
+       case 0xA0:
+       case 0x28:
+               q_num = AC_VI_Q;
+               break;
+       case 0xC0:
+       case 0xD0:
+       case 0xE0:
+       case 0x88:
+       case 0xB8:
+               q_num = AC_VO_Q;
+               break;
+       }
+
+       return q_num;
+}
+
+static inline int ac_balance(struct wilc *wl, u8 *ratio)
+{
+       u8 i, max_count = 0;
+
+       if (!ratio)
+               return -EINVAL;
+
+       for (i = 0; i < NQUEUES; i++)
+               if (wl->txq[i].fw.count > max_count)
+                       max_count = wl->txq[i].fw.count;
+
+       for (i = 0; i < NQUEUES; i++)
+               ratio[i] = max_count - wl->txq[i].fw.count;
+
+       return 0;
+}
+
+static inline void ac_update_fw_ac_pkt_info(struct wilc *wl, u32 reg)
+{
+       wl->txq[AC_BK_Q].fw.count = FIELD_GET(BK_AC_COUNT_FIELD, reg);
+       wl->txq[AC_BE_Q].fw.count = FIELD_GET(BE_AC_COUNT_FIELD, reg);
+       wl->txq[AC_VI_Q].fw.count = FIELD_GET(VI_AC_COUNT_FIELD, reg);
+       wl->txq[AC_VO_Q].fw.count = FIELD_GET(VO_AC_COUNT_FIELD, reg);
+
+       wl->txq[AC_BK_Q].fw.acm = FIELD_GET(BK_AC_ACM_STAT_FIELD, reg);
+       wl->txq[AC_BE_Q].fw.acm = FIELD_GET(BE_AC_ACM_STAT_FIELD, reg);
+       wl->txq[AC_VI_Q].fw.acm = FIELD_GET(VI_AC_ACM_STAT_FIELD, reg);
+       wl->txq[AC_VO_Q].fw.acm = FIELD_GET(VO_AC_ACM_STAT_FIELD, reg);
+}
+
+static inline u8 ac_change(struct wilc *wilc, u8 *ac)
+{
+       do {
+               if (wilc->txq[*ac].fw.acm == 0)
+                       return 0;
+               (*ac)++;
+       } while (*ac < NQUEUES);
 
        return 1;
 }
@@ -281,16 +415,21 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
        struct txq_entry_t *tqe;
        struct wilc_vif *vif = netdev_priv(dev);
        struct wilc *wilc;
+       u8 q_num;
 
        wilc = vif->wilc;
 
-       if (wilc->quit)
+       if (wilc->quit) {
+               tx_complete_fn(priv, 0);
                return 0;
+       }
 
        tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
 
-       if (!tqe)
+       if (!tqe) {
+               tx_complete_fn(priv, 0);
                return 0;
+       }
        tqe->type = WILC_NET_PKT;
        tqe->buffer = buffer;
        tqe->buffer_size = buffer_size;
@@ -298,10 +437,24 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
        tqe->priv = priv;
        tqe->vif = vif;
 
-       tqe->ack_idx = NOT_TCP_ACK;
-       if (vif->ack_filter.enabled)
-               tcp_process(dev, tqe);
-       wilc_wlan_txq_add_to_tail(dev, tqe);
+       q_num = ac_classify(wilc, priv);
+       tqe->q_num = q_num;
+       if (ac_change(wilc, &q_num)) {
+               tx_complete_fn(priv, 0);
+               kfree(tqe);
+               return 0;
+       }
+
+       if (is_ac_q_limit(wilc, q_num)) {
+               tqe->ack_idx = NOT_TCP_ACK;
+               if (vif->ack_filter.enabled)
+                       tcp_process(dev, tqe);
+               wilc_wlan_txq_add_to_tail(dev, q_num, tqe);
+       } else {
+               tx_complete_fn(priv, 0);
+               kfree(tqe);
+       }
+
        return wilc->txq_entries;
 }
 
@@ -315,34 +468,39 @@ int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
 
        wilc = vif->wilc;
 
-       if (wilc->quit)
+       if (wilc->quit) {
+               tx_complete_fn(priv, 0);
                return 0;
+       }
 
        tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
 
-       if (!tqe)
+       if (!tqe) {
+               tx_complete_fn(priv, 0);
                return 0;
+       }
        tqe->type = WILC_MGMT_PKT;
        tqe->buffer = buffer;
        tqe->buffer_size = buffer_size;
        tqe->tx_complete_func = tx_complete_fn;
        tqe->priv = priv;
+       tqe->q_num = AC_BE_Q;
        tqe->ack_idx = NOT_TCP_ACK;
        tqe->vif = vif;
-       wilc_wlan_txq_add_to_tail(dev, tqe);
+       wilc_wlan_txq_add_to_tail(dev, AC_VO_Q, tqe);
        return 1;
 }
 
-static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
+static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc, u8 q_num)
 {
        struct txq_entry_t *tqe = NULL;
        unsigned long flags;
 
        spin_lock_irqsave(&wilc->txq_spinlock, flags);
 
-       if (!list_empty(&wilc->txq_head.list))
-               tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t,
-                                      list);
+       if (!list_empty(&wilc->txq[q_num].txq_head.list))
+               tqe = list_first_entry(&wilc->txq[q_num].txq_head.list,
+                                      struct txq_entry_t, list);
 
        spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
 
@@ -350,13 +508,14 @@ static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
 }
 
 static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
-                                                 struct txq_entry_t *tqe)
+                                                 struct txq_entry_t *tqe,
+                                                 u8 q_num)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&wilc->txq_spinlock, flags);
 
-       if (!list_is_last(&tqe->list, &wilc->txq_head.list))
+       if (!list_is_last(&tqe->list, &wilc->txq[q_num].txq_head.list))
                tqe = list_next_entry(tqe, list);
        else
                tqe = NULL;
@@ -479,54 +638,92 @@ EXPORT_SYMBOL_GPL(host_sleep_notify);
 int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
 {
        int i, entries = 0;
+       u8 k, ac;
        u32 sum;
        u32 reg;
+       u8 ac_desired_ratio[NQUEUES] = {0, 0, 0, 0};
+       u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
+       u8 *num_pkts_to_add;
+       u8 vmm_entries_ac[WILC_VMM_TBL_SIZE];
        u32 offset = 0;
+       bool max_size_over = 0, ac_exist = 0;
        int vmm_sz = 0;
-       struct txq_entry_t *tqe;
+       struct txq_entry_t *tqe_q[NQUEUES];
        int ret = 0;
        int counter;
        int timeout;
        u32 vmm_table[WILC_VMM_TBL_SIZE];
+       u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0};
        const struct wilc_hif_func *func;
+       int srcu_idx;
        u8 *txb = wilc->tx_buffer;
-       struct net_device *dev;
        struct wilc_vif *vif;
 
        if (wilc->quit)
                goto out_update_cnt;
 
+       if (ac_balance(wilc, ac_desired_ratio))
+               return -EINVAL;
+
        mutex_lock(&wilc->txq_add_to_head_cs);
-       tqe = wilc_wlan_txq_get_first(wilc);
-       if (!tqe)
-               goto out_unlock;
-       dev = tqe->vif->ndev;
-       wilc_wlan_txq_filter_dup_tcp_ack(dev);
+
+       srcu_idx = srcu_read_lock(&wilc->srcu);
+       list_for_each_entry_rcu(vif, &wilc->vif_list, list)
+               wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev);
+       srcu_read_unlock(&wilc->srcu, srcu_idx);
+
+       for (ac = 0; ac < NQUEUES; ac++)
+               tqe_q[ac] = wilc_wlan_txq_get_first(wilc, ac);
+
        i = 0;
        sum = 0;
-       while (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
-               if (tqe->type == WILC_CFG_PKT)
-                       vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
-               else if (tqe->type == WILC_NET_PKT)
-                       vmm_sz = ETH_ETHERNET_HDR_OFFSET;
-               else
-                       vmm_sz = HOST_HDR_OFFSET;
-
-               vmm_sz += tqe->buffer_size;
-               vmm_sz = ALIGN(vmm_sz, 4);
-
-               if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE)
-                       break;
+       max_size_over = 0;
+       num_pkts_to_add = ac_desired_ratio;
+       do {
+               ac_exist = 0;
+               for (ac = 0; (ac < NQUEUES) && (!max_size_over); ac++) {
+                       if (!tqe_q[ac])
+                               continue;
+
+                       vif = tqe_q[ac]->vif;
+                       ac_exist = 1;
+                       for (k = 0; (k < num_pkts_to_add[ac]) &&
+                            (!max_size_over) && tqe_q[ac]; k++) {
+                               if (i >= (WILC_VMM_TBL_SIZE - 1)) {
+                                       max_size_over = 1;
+                                       break;
+                               }
 
-               vmm_table[i] = vmm_sz / 4;
-               if (tqe->type == WILC_CFG_PKT)
-                       vmm_table[i] |= BIT(10);
-               cpu_to_le32s(&vmm_table[i]);
+                               if (tqe_q[ac]->type == WILC_CFG_PKT)
+                                       vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
+                               else if (tqe_q[ac]->type == WILC_NET_PKT)
+                                       vmm_sz = ETH_ETHERNET_HDR_OFFSET;
+                               else
+                                       vmm_sz = HOST_HDR_OFFSET;
 
-               i++;
-               sum += vmm_sz;
-               tqe = wilc_wlan_txq_get_next(wilc, tqe);
-       }
+                               vmm_sz += tqe_q[ac]->buffer_size;
+                               vmm_sz = ALIGN(vmm_sz, 4);
+
+                               if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) {
+                                       max_size_over = 1;
+                                       break;
+                               }
+                               vmm_table[i] = vmm_sz / 4;
+                               if (tqe_q[ac]->type == WILC_CFG_PKT)
+                                       vmm_table[i] |= BIT(10);
+
+                               cpu_to_le32s(&vmm_table[i]);
+                               vmm_entries_ac[i] = ac;
+
+                               i++;
+                               sum += vmm_sz;
+                               tqe_q[ac] = wilc_wlan_txq_get_next(wilc,
+                                                                  tqe_q[ac],
+                                                                  ac);
+                       }
+               }
+               num_pkts_to_add = ac_preserve_ratio;
+       } while (!max_size_over && ac_exist);
 
        if (i == 0)
                goto out_unlock;
@@ -540,8 +737,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
                if (ret)
                        break;
 
-               if ((reg & 0x1) == 0)
+               if ((reg & 0x1) == 0) {
+                       ac_update_fw_ac_pkt_info(wilc, reg);
                        break;
+               }
 
                counter++;
                if (counter > 200) {
@@ -610,11 +809,13 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
        offset = 0;
        i = 0;
        do {
+               struct txq_entry_t *tqe;
                u32 header, buffer_offset;
                char *bssid;
                u8 mgmt_ptk = 0;
 
-               tqe = wilc_wlan_txq_remove_from_head(dev);
+               tqe = wilc_wlan_txq_remove_from_head(wilc, vmm_entries_ac[i]);
+               ac_pkt_num_to_chip[vmm_entries_ac[i]]++;
                if (!tqe)
                        break;
 
@@ -639,8 +840,11 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
                if (tqe->type == WILC_CFG_PKT) {
                        buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
                } else if (tqe->type == WILC_NET_PKT) {
+                       int prio = tqe->q_num;
+
                        bssid = tqe->vif->bssid;
                        buffer_offset = ETH_ETHERNET_HDR_OFFSET;
+                       memcpy(&txb[offset + 4], &prio, sizeof(prio));
                        memcpy(&txb[offset + 8], bssid, 6);
                } else {
                        buffer_offset = HOST_HDR_OFFSET;
@@ -658,6 +862,8 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
                        vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL;
                kfree(tqe);
        } while (--entries);
+       for (i = 0; i < NQUEUES; i++)
+               wilc->txq[i].fw.count += ac_pkt_num_to_chip[i];
 
        acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
 
@@ -956,14 +1162,17 @@ void wilc_wlan_cleanup(struct net_device *dev)
 {
        struct txq_entry_t *tqe;
        struct rxq_entry_t *rqe;
+       u8 ac;
        struct wilc_vif *vif = netdev_priv(dev);
        struct wilc *wilc = vif->wilc;
 
        wilc->quit = 1;
-       while ((tqe = wilc_wlan_txq_remove_from_head(dev))) {
-               if (tqe->tx_complete_func)
-                       tqe->tx_complete_func(tqe->priv, 0);
-               kfree(tqe);
+       for (ac = 0; ac < NQUEUES; ac++) {
+               while ((tqe = wilc_wlan_txq_remove_from_head(wilc, ac))) {
+                       if (tqe->tx_complete_func)
+                               tqe->tx_complete_func(tqe->priv, 0);
+                       kfree(tqe);
+               }
        }
 
        while ((rqe = wilc_wlan_rxq_remove(wilc)))
index 7689569..3d2104f 100644 (file)
 
 #define MODALIAS               "WILC_SPI"
 
+#define NQUEUES                        4
+#define AC_BUFFER_SIZE         1000
+
+#define VO_AC_COUNT_FIELD              GENMASK(31, 25)
+#define VO_AC_ACM_STAT_FIELD           BIT(24)
+#define VI_AC_COUNT_FIELD              GENMASK(23, 17)
+#define VI_AC_ACM_STAT_FIELD           BIT(16)
+#define BE_AC_COUNT_FIELD              GENMASK(15, 9)
+#define BE_AC_ACM_STAT_FIELD           BIT(8)
+#define BK_AC_COUNT_FIELD              GENMASK(7, 3)
+#define BK_AC_ACM_STAT_FIELD           BIT(1)
+
 #define WILC_PKT_HDR_CONFIG_FIELD      BIT(31)
 #define WILC_PKT_HDR_OFFSET_FIELD      GENMASK(30, 22)
 #define WILC_PKT_HDR_TOTAL_LEN_FIELD   GENMASK(21, 11)
  *      Tx/Rx Queue Structure
  *
  ********************************************/
+enum ip_pkt_priority {
+       AC_VO_Q = 0,
+       AC_VI_Q = 1,
+       AC_BE_Q = 2,
+       AC_BK_Q = 3
+};
 
 struct txq_entry_t {
        struct list_head list;
        int type;
+       u8 q_num;
        int ack_idx;
        u8 *buffer;
        int buffer_size;
@@ -308,6 +327,17 @@ struct txq_entry_t {
        void (*tx_complete_func)(void *priv, int status);
 };
 
+struct txq_fw_recv_queue_stat {
+       u8 acm;
+       u8 count;
+};
+
+struct txq_handle {
+       struct txq_entry_t txq_head;
+       u16 count;
+       struct txq_fw_recv_queue_stat fw;
+};
+
 struct rxq_entry_t {
        struct list_head list;
        u8 *buffer;
index 5337e67..0f328ce 100644 (file)
@@ -299,19 +299,19 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        sysctl_bar = qtnf_map_bar(pdev, QTN_SYSCTL_BAR);
        if (IS_ERR(sysctl_bar)) {
                pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR);
-               return ret;
+               return PTR_ERR(sysctl_bar);
        }
 
        dmareg_bar = qtnf_map_bar(pdev, QTN_DMA_BAR);
        if (IS_ERR(dmareg_bar)) {
                pr_err("failed to map BAR%u\n", QTN_DMA_BAR);
-               return ret;
+               return PTR_ERR(dmareg_bar);
        }
 
        epmem_bar = qtnf_map_bar(pdev, QTN_SHMEM_BAR);
        if (IS_ERR(epmem_bar)) {
                pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR);
-               return ret;
+               return PTR_ERR(epmem_bar);
        }
 
        chipid = qtnf_chip_id_get(sysctl_bar);
index fed6d21..5264b0a 100644 (file)
@@ -1228,6 +1228,17 @@ static int rt2800_check_hung(struct data_queue *queue)
        return queue->wd_count > 16;
 }
 
+static void rt2800_update_survey(struct rt2x00_dev *rt2x00dev)
+{
+       struct ieee80211_channel *chan = rt2x00dev->hw->conf.chandef.chan;
+       struct rt2x00_chan_survey *chan_survey =
+                  &rt2x00dev->chan_survey[chan->hw_value];
+
+       chan_survey->time_idle += rt2800_register_read(rt2x00dev, CH_IDLE_STA);
+       chan_survey->time_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA);
+       chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
+}
+
 void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue;
@@ -1237,6 +1248,8 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
        if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
                return;
 
+       rt2800_update_survey(rt2x00dev);
+
        queue_for_each(rt2x00dev, queue) {
                switch (queue->qid) {
                case QID_AC_VO:
@@ -5553,6 +5566,12 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev,
        rt2800_config_lna_gain(rt2x00dev, libconf);
 
        if (flags & IEEE80211_CONF_CHANGE_CHANNEL) {
+               /*
+                * To provide correct survey data for survey-based ACS algorithm
+                * we have to save survey data for current channel before switching.
+                */
+               rt2800_update_survey(rt2x00dev);
+
                rt2800_config_channel(rt2x00dev, libconf->conf,
                                      &libconf->rf, &libconf->channel);
                rt2800_config_txpower(rt2x00dev, libconf->conf->chandef.chan,
@@ -10111,12 +10130,20 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        }
 
        /*
-        * Create channel information array
+        * Create channel information and survey arrays
         */
        info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
+       rt2x00dev->chan_survey =
+               kcalloc(spec->num_channels, sizeof(struct rt2x00_chan_survey),
+                       GFP_KERNEL);
+       if (!rt2x00dev->chan_survey) {
+               kfree(info);
+               return -ENOMEM;
+       }
+
        spec->channels_info = info;
 
        default_power1 = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
@@ -10503,27 +10530,30 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
                      struct survey_info *survey)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct ieee80211_conf *conf = &hw->conf;
-       u32 idle, busy, busy_ext;
+       struct rt2x00_chan_survey *chan_survey =
+                  &rt2x00dev->chan_survey[idx];
+       enum nl80211_band band = NL80211_BAND_2GHZ;
 
-       if (idx != 0)
+       if (idx >= rt2x00dev->bands[band].n_channels) {
+               idx -= rt2x00dev->bands[band].n_channels;
+               band = NL80211_BAND_5GHZ;
+       }
+
+       if (idx >= rt2x00dev->bands[band].n_channels)
                return -ENOENT;
 
-       survey->channel = conf->chandef.chan;
+       if (idx == 0)
+               rt2800_update_survey(rt2x00dev);
 
-       idle = rt2800_register_read(rt2x00dev, CH_IDLE_STA);
-       busy = rt2800_register_read(rt2x00dev, CH_BUSY_STA);
-       busy_ext = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
+       survey->channel = &rt2x00dev->bands[band].channels[idx];
 
-       if (idle || busy) {
-               survey->filled = SURVEY_INFO_TIME |
-                                SURVEY_INFO_TIME_BUSY |
-                                SURVEY_INFO_TIME_EXT_BUSY;
+       survey->filled = SURVEY_INFO_TIME |
+                        SURVEY_INFO_TIME_BUSY |
+                        SURVEY_INFO_TIME_EXT_BUSY;
 
-               survey->time = (idle + busy) / 1000;
-               survey->time_busy = busy / 1000;
-               survey->time_ext_busy = busy_ext / 1000;
-       }
+       survey->time = div_u64(chan_survey->time_idle + chan_survey->time_busy, 1000);
+       survey->time_busy = div_u64(chan_survey->time_busy, 1000);
+       survey->time_ext_busy = div_u64(chan_survey->time_ext_busy, 1000);
 
        if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
                survey->filled |= SURVEY_INFO_IN_USE;
index 780be81..9f6fc40 100644 (file)
@@ -181,6 +181,15 @@ struct rf_channel {
        u32 rf4;
 };
 
+/*
+ * Information structure for channel survey.
+ */
+struct rt2x00_chan_survey {
+       u64 time_idle;
+       u64 time_busy;
+       u64 time_ext_busy;
+};
+
 /*
  * Channel information structure
  */
@@ -752,6 +761,7 @@ struct rt2x00_dev {
         */
        struct ieee80211_hw *hw;
        struct ieee80211_supported_band bands[NUM_NL80211_BANDS];
+       struct rt2x00_chan_survey *chan_survey;
        enum nl80211_band curr_band;
        int curr_freq;
 
index bf3fbd1..590bd97 100644 (file)
@@ -877,10 +877,10 @@ static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev,
        switch (ccsindex = get_free_tx_ccs(local)) {
        case ECCSBUSY:
                pr_debug("ray_hw_xmit tx_ccs table busy\n");
-               /* fall through */
+               fallthrough;
        case ECCSFULL:
                pr_debug("ray_hw_xmit No free tx ccs\n");
-               /* fall through */
+               fallthrough;
        case ECARDGONE:
                netif_stop_queue(dev);
                return XMIT_NO_CCS;
@@ -1272,7 +1272,7 @@ static int ray_set_mode(struct net_device *dev, struct iw_request_info *info,
        switch (wrqu->mode) {
        case IW_MODE_ADHOC:
                card_mode = 0;
-               /* Fall through */
+               fallthrough;
        case IW_MODE_INFRA:
                local->sparm.b5.a_network_type = card_mode;
                break;
index fb57cc8..7a71f06 100644 (file)
@@ -1628,17 +1628,17 @@ static void btc8723b2ant_action_wifi_link_process(struct btc_coexist
 static bool btc8723b2ant_action_wifi_idle_process(struct btc_coexist *btcoexist)
 {
        struct rtl_priv *rtlpriv = btcoexist->adapter;
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1;
        u8 ap_num = 0;
        u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES -
                 coex_dm->switch_thres_offset - coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
                                                        tmp, 0);
        tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
              coex_dm->switch_thres_offset - coex_dm->switch_thres_offset;
-       bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0);
+       btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0);
 
        btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num);
 
@@ -2764,10 +2764,10 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
 /* SCO only or SCO+PAN(HS) */
 static void btc8723b2ant_action_sco(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, bt_rssi_state;
+       u8 bt_rssi_state;
        u32 wifi_bw;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        bt_rssi_state = btc8723b2ant_bt_rssi_state(
                btcoexist, 2, BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
                                               coex_dm->switch_thres_offset,
@@ -2807,12 +2807,12 @@ static void btc8723b2ant_action_sco(struct btc_coexist *btcoexist)
 
 static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, bt_rssi_state;
+       u8 bt_rssi_state;
        u32 wifi_bw;
        u8 tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0);
 
        btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2852,13 +2852,13 @@ 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, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1, bt_rssi_state;
        u32 wifi_bw;
        u8 ap_num = 0;
        u8 tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, 40, 0);
        bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0);
 
@@ -2926,12 +2926,12 @@ static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist)
 
 static void btc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1, bt_rssi_state;
        u32 wifi_bw;
        u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
                                                        tmp, 0);
        tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
@@ -2973,12 +2973,12 @@ static void btc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
 
 static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1, bt_rssi_state;
        u32 wifi_bw;
        u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
                                                        tmp, 0);
        tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
@@ -3025,13 +3025,13 @@ static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist)
 /* PAN(HS) only */
 static void btc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 bt_rssi_state;
        u32 wifi_bw;
        u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
-       wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
                                                        tmp, 0);
        tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
@@ -3063,12 +3063,12 @@ static void btc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist)
 /* PAN(EDR) + A2DP */
 static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1, bt_rssi_state;
        u32 wifi_bw;
        u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
                                                        tmp, 0);
        tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
@@ -3118,12 +3118,12 @@ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
 
 static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1, bt_rssi_state;
        u32 wifi_bw;
        u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
                                                        tmp, 0);
        tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
@@ -3182,12 +3182,12 @@ static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
 /* HID + A2DP + PAN(EDR) */
 static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1, bt_rssi_state;
        u32 wifi_bw;
        u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
                                                        tmp, 0);
        tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
@@ -3241,13 +3241,13 @@ static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
 
 static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1, bt_rssi_state;
        u32 wifi_bw;
        u8 ap_num = 0;
        u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES -
                        coex_dm->switch_thres_offset;
 
-       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2,
                                                        tmp, 0);
        tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES -
index 9f5e85b..a18dffc 100644 (file)
@@ -1901,7 +1901,6 @@ static void btc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
        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;
        bool wifi_under_5g = false;
@@ -1962,8 +1961,7 @@ static void btc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
                btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
        } else {
                if (wifi_connected) {
-                       wifi_rssi_state =
-                               btc8821a1ant_wifi_rssi_state(btcoexist, 1, 2,
+                       btc8821a1ant_wifi_rssi_state(btcoexist, 1, 2,
                                                             30, 0);
                        btc8821a1ant_limited_tx(btcoexist,
                                                NORMAL_EXEC, 1, 1,
index e53789f..447caa4 100644 (file)
@@ -1448,17 +1448,15 @@ static void btc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist)
 static void btc8821a2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
 {
        struct rtl_priv *rtlpriv = btcoexist->adapter;
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
        bool wifi_connected = false;
        bool low_pwr_disable = true;
        bool scan = false, link = false, roam = false;
 
-       wifi_rssi_state =
-               btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
-       wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2,
+       btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2,
                                BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0);
-       bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist,
-               2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0);
+       btc8821a2ant_bt_rssi_state(btcoexist,
+                               2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0);
 
        btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
                           &low_pwr_disable);
@@ -1516,15 +1514,14 @@ static void btc8821a2ant_action_wifi_link_process(struct btc_coexist *btcoexist)
 static bool btc8821a2ant_action_wifi_idle_process(struct btc_coexist *btcoexist)
 {
        struct rtl_priv *rtlpriv = btcoexist->adapter;
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state1;
        u8 ap_num = 0;
 
-       wifi_rssi_state =
-               btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
+       btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
        wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2,
                        BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES - 20, 0);
-       bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist,
-                       2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0);
+       btc8821a2ant_bt_rssi_state(btcoexist,
+                               2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0);
 
        btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num);
 
@@ -2987,11 +2984,11 @@ static void btc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist)
 /* PAN(HS) only */
 static void btc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist)
 {
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state, bt_rssi_state;
        u32 wifi_bw;
 
        wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
-       wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2,
+       btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2,
                                BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0);
        bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist,
                                2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0);
@@ -3274,11 +3271,11 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
 static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
 {
        u32 wifi_bw;
-       u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
+       u8 wifi_rssi_state, bt_rssi_state;
        u8 ap_num = 0;
 
        wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0);
-       wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2,
+       btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2,
                                BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0);
        bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist,
                                3, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 37);
index 2c05369..be4c0e6 100644 (file)
@@ -47,30 +47,17 @@ static bool is_any_client_connect_to_ap(struct btc_coexist *btcoexist)
 {
        struct rtl_priv *rtlpriv = btcoexist->adapter;
        struct rtl_mac *mac = rtl_mac(rtlpriv);
-       struct rtl_sta_info *drv_priv;
-       u8 cnt = 0;
+       bool ret = false;
 
        if (mac->opmode == NL80211_IFTYPE_ADHOC ||
            mac->opmode == NL80211_IFTYPE_MESH_POINT ||
            mac->opmode == NL80211_IFTYPE_AP) {
-               if (in_interrupt() > 0) {
-                       list_for_each_entry(drv_priv, &rtlpriv->entry_list,
-                                           list) {
-                               cnt++;
-                       }
-               } else {
-                       spin_lock_bh(&rtlpriv->locks.entry_list_lock);
-                       list_for_each_entry(drv_priv, &rtlpriv->entry_list,
-                                           list) {
-                               cnt++;
-                       }
-                       spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
-               }
+               spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+               if (!list_empty(&rtlpriv->entry_list))
+                       ret = true;
+               spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
        }
-       if (cnt > 0)
-               return true;
-       else
-               return false;
+       return ret;
 }
 
 static bool halbtc_legacy(struct rtl_priv *adapter)
@@ -253,9 +240,6 @@ bool halbtc_send_bt_mp_operation(struct btc_coexist *btcoexist, u8 op_code,
        rtl_dbg(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
                "btmpinfo wait req_num=%d wait=%ld\n", req_num, wait_ms);
 
-       if (in_interrupt())
-               return false;
-
        if (wait_for_completion_timeout(&btcoexist->bt_mp_comp,
                                        msecs_to_jiffies(wait_ms)) == 0) {
                rtl_dbg(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
index 63f9ea2..bd9160b 100644 (file)
@@ -1226,7 +1226,6 @@ static int _rtl88ee_set_media_status(struct ieee80211_hw *hw,
        default:
                pr_err("Network type %d not support!\n", type);
                return 1;
-               break;
        }
 
        /* MSR_INFRA == Link in infrastructure network;
index 9be032e..12d0b3a 100644 (file)
@@ -1348,7 +1348,7 @@ static bool _rtl88e_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
 
 static u8 _rtl88e_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
 {
-       u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
+       u32 reg_eac, reg_e94, reg_e9c;
        u8 result = 0x00;
 
        rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1c);
@@ -1365,7 +1365,7 @@ static u8 _rtl88e_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
        reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
        reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
        reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
-       reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
+       rtl_get_bbreg(hw, 0xea4, MASKDWORD);
 
        if (!(reg_eac & BIT(28)) &&
            (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
index b9775ee..c948daf 100644 (file)
@@ -674,12 +674,12 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
        u8 fw_queue = QSLT_BEACON;
        __le32 *pdesc = (__le32 *)pdesc8;
 
-       dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data,
-                                           skb->len, DMA_TO_DEVICE);
-
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
        __le16 fc = hdr->frame_control;
 
+       dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data,
+                                           skb->len, DMA_TO_DEVICE);
+
        if (dma_mapping_error(&rtlpci->pdev->dev, mapping)) {
                rtl_dbg(rtlpriv, COMP_SEND, DBG_TRACE,
                        "DMA mapping error\n");
index c063530..4165175 100644 (file)
@@ -527,12 +527,12 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
        u8 fw_queue = QSLT_BEACON;
        __le32 *pdesc = (__le32 *)pdesc8;
 
-       dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data,
-                                           skb->len, DMA_TO_DEVICE);
-
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
        __le16 fc = hdr->frame_control;
 
+       dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data,
+                                           skb->len, DMA_TO_DEVICE);
+
        if (dma_mapping_error(&rtlpci->pdev->dev, mapping)) {
                rtl_dbg(rtlpriv, COMP_SEND, DBG_TRACE,
                        "DMA mapping error\n");
index 2890a49..8d2c6d8 100644 (file)
@@ -113,7 +113,7 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw)
 
 /**
  * writeLLT - LLT table write access
- * @io: io callback
+ * @hw: Pointer to the ieee80211_hw structure.
  * @address: LLT logical address.
  * @data: LLT data content
  *
@@ -145,11 +145,10 @@ bool rtl92c_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
 
 /**
  * rtl92c_init_LLT_table - Init LLT table
- * @io: io callback
- * @boundary:
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @boundary: Page boundary.
  *
  * Realtek hardware access function.
- *
  */
 bool rtl92c_init_llt_table(struct ieee80211_hw *hw, u32 boundary)
 {
index 1ad0cf3..87f959d 100644 (file)
@@ -448,7 +448,7 @@ static void _rtl_fill_usb_tx_desc(__le32 *txdesc)
        set_tx_desc_first_seg(txdesc, 1);
 }
 
-/**
+/*
  *     For HW recovery information
  */
 static void _rtl_tx_desc_checksum(__le32 *txdesc)
index e34d33e..68ec009 100644 (file)
@@ -2566,7 +2566,7 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t)
                }
                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                        "PHY_LCK finish delay for %d ms=2\n", timecount);
-               u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, RFREG_OFFSET_MASK);
+               rtl_get_rfreg(hw, index, RF_SYN_G4, RFREG_OFFSET_MASK);
                if (index == 0 && rtlhal->interfaceindex == 0) {
                        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                                "path-A / 5G LCK\n");
index 8944712..c02813f 100644 (file)
@@ -664,12 +664,14 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
        struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
        u8 fw_queue = QSLT_BEACON;
-       dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data,
-                                           skb->len, DMA_TO_DEVICE);
+
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
        __le16 fc = hdr->frame_control;
        __le32 *pdesc = (__le32 *)pdesc8;
 
+       dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data,
+                                           skb->len, DMA_TO_DEVICE);
+
        if (dma_mapping_error(&rtlpci->pdev->dev, mapping)) {
                rtl_dbg(rtlpriv, COMP_SEND, DBG_TRACE,
                        "DMA mapping error\n");
index a36dc6e..f8a1de6 100644 (file)
@@ -1132,7 +1132,6 @@ static int _rtl8723e_set_media_status(struct ieee80211_hw *hw,
        default:
                pr_err("Network type %d not support!\n", type);
                return 1;
-               break;
        }
 
        /* MSR_INFRA == Link in infrastructure network;
index fa0eed4..fe9b407 100644 (file)
@@ -1147,10 +1147,8 @@ static void _rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw,
 
        const u32 retrycount = 2;
 
-       u32 bbvalue;
-
        if (t == 0) {
-               bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
+               rtl_get_bbreg(hw, 0x800, MASKDWORD);
 
                rtl8723_save_adda_registers(hw, adda_reg,
                                            rtlphy->adda_backup, 16);
index e3ee91b..340b3d6 100644 (file)
@@ -528,12 +528,12 @@ void rtl8723e_tx_fill_cmddesc(struct ieee80211_hw *hw,
        u8 fw_queue = QSLT_BEACON;
        __le32 *pdesc = (__le32 *)pdesc8;
 
-       dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data,
-                                           skb->len, DMA_TO_DEVICE);
-
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
        __le16 fc = hdr->frame_control;
 
+       dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data,
+                                           skb->len, DMA_TO_DEVICE);
+
        if (dma_mapping_error(&rtlpci->pdev->dev, mapping)) {
                rtl_dbg(rtlpriv, COMP_SEND, DBG_TRACE,
                        "DMA mapping error\n");
index f09f55b..2b9313c 100644 (file)
@@ -2178,7 +2178,7 @@ static u8 _get_right_chnl_place_for_iqk(u8 chnl)
 static void _rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
 {
        u8 tmpreg;
-       u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+       u32 rf_a_mode = 0, rf_b_mode = 0;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
        tmpreg = rtl_read_byte(rtlpriv, 0xd03);
@@ -2202,7 +2202,7 @@ static void _rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
                        rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
                                      (rf_b_mode & 0x8FFFF) | 0x10000);
        }
-       lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS);
+       rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS);
 
        rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdfbe0);
        rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, 0x8c0a);
index 559ab78..5a7cd27 100644 (file)
@@ -50,7 +50,6 @@ static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw,
        pstatus->rx_mimo_signalquality[1] = -1;
 
        if (is_cck) {
-               u8 cck_highpwr;
                u8 cck_agc_rpt;
 
                cck_agc_rpt = p_phystrpt->cck_agc_rpt_ofdm_cfosho_a;
@@ -59,8 +58,7 @@ static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw,
                /* (2)PWDB, Average PWDB cacluated by
                 * hardware (for rate adaptive)
                 */
-               cck_highpwr = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2,
-                                                BIT(9));
+               rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BIT(9));
 
                lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
                vga_idx = (cck_agc_rpt & 0x1f);
index f41a764..372d6f8 100644 (file)
@@ -62,7 +62,7 @@ static void rtl8812ae_fixspur(struct ieee80211_hw *hw,
                        rtl_set_bbreg(hw, RRFMOD, 0xC00, 0x2);
                        /* 0x8AC[11:10] = 2'b10*/
 
-               /* <20120914, Kordan> A workarould to resolve
+               /* <20120914, Kordan> A workaround to resolve
                 * 2480Mhz spur by setting ADC clock as 160M. (Asked by Binson)
                 */
                if (band_width == HT_CHANNEL_WIDTH_20 &&
@@ -82,7 +82,7 @@ static void rtl8812ae_fixspur(struct ieee80211_hw *hw,
                        /*0x8C4[30] = 0*/
                }
        } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
-               /* <20120914, Kordan> A workarould to resolve
+               /* <20120914, Kordan> A workaround to resolve
                 * 2480Mhz spur by setting ADC clock as 160M.
                 */
                if (band_width == HT_CHANNEL_WIDTH_20 &&
@@ -594,11 +594,10 @@ void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band)
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        struct rtl_dm *rtldm = rtl_dm(rtlpriv);
        u8 current_band = rtlhal->current_bandtype;
-       u32 txpath, rxpath;
        s8 bb_diff_between_band;
 
-       txpath = rtl8821ae_phy_query_bb_reg(hw, RTXPATH, 0xf0);
-       rxpath = rtl8821ae_phy_query_bb_reg(hw, RCCK_RX, 0x0f000000);
+       rtl8821ae_phy_query_bb_reg(hw, RTXPATH, 0xf0);
+       rtl8821ae_phy_query_bb_reg(hw, RCCK_RX, 0x0f000000);
        rtlhal->current_bandtype = (enum band_type) band;
        /* reconfig BB/RF according to wireless mode */
        if (rtlhal->current_bandtype == BAND_ON_2_4G) {
@@ -1581,7 +1580,7 @@ static void _rtl8821ae_phy_txpower_by_rate_configuration(struct ieee80211_hw *hw
 }
 
 /* string is in decimal */
-static bool _rtl8812ae_get_integer_from_string(char *str, u8 *pint)
+static bool _rtl8812ae_get_integer_from_string(const char *str, u8 *pint)
 {
        u16 i = 0;
        *pint = 0;
@@ -1599,7 +1598,7 @@ static bool _rtl8812ae_get_integer_from_string(char *str, u8 *pint)
        return true;
 }
 
-static bool _rtl8812ae_eq_n_byte(u8 *str1, u8 *str2, u32 num)
+static bool _rtl8812ae_eq_n_byte(const char *str1, const char *str2, u32 num)
 {
        if (num == 0)
                return false;
@@ -1637,10 +1636,11 @@ static s8 _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw,
        return channel_index;
 }
 
-static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregulation,
-                                     u8 *pband, u8 *pbandwidth,
-                                     u8 *prate_section, u8 *prf_path,
-                                     u8 *pchannel, u8 *ppower_limit)
+static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw,
+                                     const char *pregulation,
+                                     const char *pband, const char *pbandwidth,
+                                     const char *prate_section, const char *prf_path,
+                                     const char *pchannel, const char *ppower_limit)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &rtlpriv->phy;
@@ -1648,8 +1648,8 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregul
        u8 channel_index;
        s8 power_limit = 0, prev_power_limit, ret;
 
-       if (!_rtl8812ae_get_integer_from_string((char *)pchannel, &channel) ||
-           !_rtl8812ae_get_integer_from_string((char *)ppower_limit,
+       if (!_rtl8812ae_get_integer_from_string(pchannel, &channel) ||
+           !_rtl8812ae_get_integer_from_string(ppower_limit,
                                                &power_limit)) {
                rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE,
                        "Illegal index of pwr_lmt table [chnl %d][val %d]\n",
@@ -1659,42 +1659,42 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregul
        power_limit = power_limit > MAX_POWER_INDEX ?
                      MAX_POWER_INDEX : power_limit;
 
-       if (_rtl8812ae_eq_n_byte(pregulation, (u8 *)("FCC"), 3))
+       if (_rtl8812ae_eq_n_byte(pregulation, "FCC", 3))
                regulation = 0;
-       else if (_rtl8812ae_eq_n_byte(pregulation, (u8 *)("MKK"), 3))
+       else if (_rtl8812ae_eq_n_byte(pregulation, "MKK", 3))
                regulation = 1;
-       else if (_rtl8812ae_eq_n_byte(pregulation, (u8 *)("ETSI"), 4))
+       else if (_rtl8812ae_eq_n_byte(pregulation, "ETSI", 4))
                regulation = 2;
-       else if (_rtl8812ae_eq_n_byte(pregulation, (u8 *)("WW13"), 4))
+       else if (_rtl8812ae_eq_n_byte(pregulation, "WW13", 4))
                regulation = 3;
 
-       if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("CCK"), 3))
+       if (_rtl8812ae_eq_n_byte(prate_section, "CCK", 3))
                rate_section = 0;
-       else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("OFDM"), 4))
+       else if (_rtl8812ae_eq_n_byte(prate_section, "OFDM", 4))
                rate_section = 1;
-       else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("HT"), 2) &&
-                _rtl8812ae_eq_n_byte(prf_path, (u8 *)("1T"), 2))
+       else if (_rtl8812ae_eq_n_byte(prate_section, "HT", 2) &&
+                _rtl8812ae_eq_n_byte(prf_path, "1T", 2))
                rate_section = 2;
-       else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("HT"), 2) &&
-                _rtl8812ae_eq_n_byte(prf_path, (u8 *)("2T"), 2))
+       else if (_rtl8812ae_eq_n_byte(prate_section, "HT", 2) &&
+                _rtl8812ae_eq_n_byte(prf_path, "2T", 2))
                rate_section = 3;
-       else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("VHT"), 3) &&
-                _rtl8812ae_eq_n_byte(prf_path, (u8 *)("1T"), 2))
+       else if (_rtl8812ae_eq_n_byte(prate_section, "VHT", 3) &&
+                _rtl8812ae_eq_n_byte(prf_path, "1T", 2))
                rate_section = 4;
-       else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("VHT"), 3) &&
-                _rtl8812ae_eq_n_byte(prf_path, (u8 *)("2T"), 2))
+       else if (_rtl8812ae_eq_n_byte(prate_section, "VHT", 3) &&
+                _rtl8812ae_eq_n_byte(prf_path, "2T", 2))
                rate_section = 5;
 
-       if (_rtl8812ae_eq_n_byte(pbandwidth, (u8 *)("20M"), 3))
+       if (_rtl8812ae_eq_n_byte(pbandwidth, "20M", 3))
                bandwidth = 0;
-       else if (_rtl8812ae_eq_n_byte(pbandwidth, (u8 *)("40M"), 3))
+       else if (_rtl8812ae_eq_n_byte(pbandwidth, "40M", 3))
                bandwidth = 1;
-       else if (_rtl8812ae_eq_n_byte(pbandwidth, (u8 *)("80M"), 3))
+       else if (_rtl8812ae_eq_n_byte(pbandwidth, "80M", 3))
                bandwidth = 2;
-       else if (_rtl8812ae_eq_n_byte(pbandwidth, (u8 *)("160M"), 4))
+       else if (_rtl8812ae_eq_n_byte(pbandwidth, "160M", 4))
                bandwidth = 3;
 
-       if (_rtl8812ae_eq_n_byte(pband, (u8 *)("2.4G"), 4)) {
+       if (_rtl8812ae_eq_n_byte(pband, "2.4G", 4)) {
                ret = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw,
                                                               BAND_ON_2_4G,
                                                               channel);
@@ -1718,7 +1718,7 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregul
                        regulation, bandwidth, rate_section, channel_index,
                        rtlphy->txpwr_limit_2_4g[regulation][bandwidth]
                                [rate_section][channel_index][RF90_PATH_A]);
-       } else if (_rtl8812ae_eq_n_byte(pband, (u8 *)("5G"), 2)) {
+       } else if (_rtl8812ae_eq_n_byte(pband, "5G", 2)) {
                ret = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw,
                                                               BAND_ON_5G,
                                                               channel);
@@ -1749,10 +1749,10 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregul
 }
 
 static void _rtl8812ae_phy_config_bb_txpwr_lmt(struct ieee80211_hw *hw,
-                                         u8 *regulation, u8 *band,
-                                         u8 *bandwidth, u8 *rate_section,
-                                         u8 *rf_path, u8 *channel,
-                                         u8 *power_limit)
+                                         const char *regulation, const char *band,
+                                         const char *bandwidth, const char *rate_section,
+                                         const char *rf_path, const char *channel,
+                                         const char *power_limit)
 {
        _rtl8812ae_phy_set_txpower_limit(hw, regulation, band, bandwidth,
                                         rate_section, rf_path, channel,
@@ -1765,7 +1765,7 @@ static void _rtl8821ae_phy_read_and_config_txpwr_lmt(struct ieee80211_hw *hw)
        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
        u32 i = 0;
        u32 array_len;
-       u8 **array;
+       const char **array;
 
        if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
                array_len = RTL8812AE_TXPWR_LMT_ARRAY_LEN;
@@ -1778,13 +1778,13 @@ static void _rtl8821ae_phy_read_and_config_txpwr_lmt(struct ieee80211_hw *hw)
        rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
 
        for (i = 0; i < array_len; i += 7) {
-               u8 *regulation = array[i];
-               u8 *band = array[i+1];
-               u8 *bandwidth = array[i+2];
-               u8 *rate = array[i+3];
-               u8 *rf_path = array[i+4];
-               u8 *chnl = array[i+5];
-               u8 *val = array[i+6];
+               const char *regulation = array[i];
+               const char *band = array[i+1];
+               const char *bandwidth = array[i+2];
+               const char *rate = array[i+3];
+               const char *rf_path = array[i+4];
+               const char *chnl = array[i+5];
+               const char *val = array[i+6];
 
                _rtl8812ae_phy_config_bb_txpwr_lmt(hw, regulation, band,
                                                   bandwidth, rate, rf_path,
@@ -2085,12 +2085,10 @@ bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
                return __rtl8821ae_phy_config_with_headerfile(hw,
                                radioa_array_table_a, radioa_arraylen_a,
                                _rtl8821ae_config_rf_radio_a);
-               break;
        case RF90_PATH_B:
                return __rtl8821ae_phy_config_with_headerfile(hw,
                                radioa_array_table_b, radioa_arraylen_b,
                                _rtl8821ae_config_rf_radio_b);
-               break;
        case RF90_PATH_C:
        case RF90_PATH_D:
                pr_err("switch case %#x not processed\n", rfpath);
@@ -2116,7 +2114,6 @@ bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
                return __rtl8821ae_phy_config_with_headerfile(hw,
                        radioa_array_table, radioa_arraylen,
                        _rtl8821ae_config_rf_radio_a);
-               break;
 
        case RF90_PATH_B:
        case RF90_PATH_C:
@@ -2449,8 +2446,9 @@ static s8 _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw,
        else if (band == BAND_ON_5G)
                channel_temp = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw,
                BAND_ON_5G, channel);
-       else if (band == BAND_ON_BOTH)
+       else if (band == BAND_ON_BOTH) {
                ;/* BAND_ON_BOTH don't care temporarily */
+       }
 
        if (band_temp == -1 || regulation == -1 || bandwidth_temp == -1 ||
                rate_section == -1 || channel_temp == -1) {
index 85093b3..27c8a5d 100644 (file)
@@ -2654,7 +2654,7 @@ u32 RTL8821AE_AGC_TAB_1TARRAYLEN = ARRAY_SIZE(RTL8821AE_AGC_TAB_ARRAY);
 *                           TXPWR_LMT.TXT
 ******************************************************************************/
 
-u8 *RTL8812AE_TXPWR_LMT[] = {
+const char *RTL8812AE_TXPWR_LMT[] = {
        "FCC", "2.4G", "20M", "CCK", "1T", "01", "36",
        "ETSI", "2.4G", "20M", "CCK", "1T", "01", "32",
        "MKK", "2.4G", "20M", "CCK", "1T", "01", "32",
@@ -3223,7 +3223,7 @@ u8 *RTL8812AE_TXPWR_LMT[] = {
 
 u32 RTL8812AE_TXPWR_LMT_ARRAY_LEN = ARRAY_SIZE(RTL8812AE_TXPWR_LMT);
 
-u8 *RTL8821AE_TXPWR_LMT[] = {
+const char *RTL8821AE_TXPWR_LMT[] = {
        "FCC", "2.4G", "20M", "CCK", "1T", "01", "32",
        "ETSI", "2.4G", "20M", "CCK", "1T", "01", "32",
        "MKK", "2.4G", "20M", "CCK", "1T", "01", "32",
index 540159c..76c62b7 100644 (file)
@@ -28,7 +28,7 @@ extern u32 RTL8821AE_AGC_TAB_ARRAY[];
 extern u32 RTL8812AE_AGC_TAB_1TARRAYLEN;
 extern u32 RTL8812AE_AGC_TAB_ARRAY[];
 extern u32 RTL8812AE_TXPWR_LMT_ARRAY_LEN;
-extern u8 *RTL8812AE_TXPWR_LMT[];
+extern const char *RTL8812AE_TXPWR_LMT[];
 extern u32 RTL8821AE_TXPWR_LMT_ARRAY_LEN;
-extern u8 *RTL8821AE_TXPWR_LMT[];
+extern const char *RTL8821AE_TXPWR_LMT[];
 #endif
index 06e073d..d62b87f 100644 (file)
@@ -731,7 +731,6 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
 
 err_out:
        usb_kill_anchored_urbs(&rtlusb->rx_submitted);
-       _rtl_usb_cleanup_rx(hw);
        return err;
 }
 
index aa08fd7..c704c68 100644 (file)
@@ -8,6 +8,7 @@
 #include "ps.h"
 #include "debug.h"
 #include "reg.h"
+#include "phy.h"
 
 static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state,
                                   u8 rssi, u8 rssi_thresh)
@@ -38,7 +39,7 @@ static void rtw_coex_limited_tx(struct rtw_dev *rtwdev,
        struct rtw_chip_info *chip = rtwdev->chip;
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
-       bool wifi_under_b_mode = false;
+       u8 num_of_active_port = 1;
 
        if (!chip->scbd_support)
                return;
@@ -70,17 +71,13 @@ static void rtw_coex_limited_tx(struct rtw_dev *rtwdev,
                /* set queue life time to avoid can't reach tx retry limit
                 * if tx is always broken by GNT_BT
                 */
-               rtw_write8_set(rtwdev, REG_LIFETIME_EN, 0xf);
+               if (num_of_active_port <= 1)
+                       rtw_write8_set(rtwdev, REG_LIFETIME_EN, 0xf);
                rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x0808);
 
                /* auto rate fallback step within 8 retries */
-               if (wifi_under_b_mode) {
-                       rtw_write32(rtwdev, REG_DARFRC, 0x1000000);
-                       rtw_write32(rtwdev, REG_DARFRCH, 0x1010101);
-               } else {
-                       rtw_write32(rtwdev, REG_DARFRC, 0x1000000);
-                       rtw_write32(rtwdev, REG_DARFRCH, 0x4030201);
-               }
+               rtw_write32(rtwdev, REG_DARFRC, 0x1000000);
+               rtw_write32(rtwdev, REG_DARFRCH, 0x4030201);
        } else {
                rtw_write8_clr(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);
                rtw_write8_clr(rtwdev, REG_LIFETIME_EN, 0xf);
@@ -101,39 +98,84 @@ static void rtw_coex_limited_wl(struct rtw_dev *rtwdev)
 {
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_dm *coex_dm = &coex->dm;
-       struct rtw_coex_stat *coex_stat = &coex->stat;
        bool tx_limit = false;
        bool tx_agg_ctrl = false;
 
-       if (coex->under_5g ||
-           coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
-               /* no need to limit tx */
-       } else {
+       if (!coex->under_5g && coex_dm->bt_status != COEX_BTSTATUS_NCON_IDLE) {
                tx_limit = true;
-               if (coex_stat->bt_hid_exist || coex_stat->bt_hfp_exist ||
-                   coex_stat->bt_hid_pair_num > 0)
-                       tx_agg_ctrl = true;
+               tx_agg_ctrl = true;
        }
 
        rtw_coex_limited_tx(rtwdev, tx_limit, tx_agg_ctrl);
 }
 
-static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev)
+static bool rtw_coex_freerun_check(struct rtw_dev *rtwdev)
+{
+       struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_coex_dm *coex_dm = &coex->dm;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
+       struct rtw_efuse *efuse = &rtwdev->efuse;
+       u8 bt_rssi;
+       u8 ant_distance = 10;
+
+       if (coex_stat->bt_disabled)
+               return false;
+
+       if (efuse->share_ant || ant_distance <= 5 || !coex_stat->wl_gl_busy)
+               return false;
+
+       if (ant_distance >= 40 || coex_stat->bt_hid_pair_num >= 2)
+               return true;
+
+       /* ant_distance = 5 ~ 40  */
+       if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]) &&
+           COEX_RSSI_HIGH(coex_dm->bt_rssi_state[0]))
+               return true;
+
+       if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
+               bt_rssi = coex_dm->bt_rssi_state[0];
+       else
+               bt_rssi = coex_dm->bt_rssi_state[1];
+
+       if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
+           COEX_RSSI_HIGH(bt_rssi) &&
+           coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] <= 5)
+               return true;
+
+       return false;
+}
+
+static void rtw_coex_wl_slot_extend(struct rtw_dev *rtwdev, bool enable)
 {
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
        u8 para[6] = {0};
 
-       if (coex->stop_dm)
+       para[0] = COEX_H2C69_WL_LEAKAP;
+       para[1] = PARA1_H2C69_DIS_5MS;
+
+       if (enable)
+               para[1] = PARA1_H2C69_EN_5MS;
+       else
+               coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
+
+       coex_stat->wl_slot_extend = enable;
+       rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
+}
+
+static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev)
+{
+       struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
+
+       if (coex->manual_control || coex->stop_dm)
                return;
 
-       para[0] = COEX_H2C69_WL_LEAKAP;
 
        if (coex_stat->tdma_timer_base == 3 && coex_stat->wl_slot_extend) {
-               para[1] = PARA1_H2C69_DIS_5MS; /* disable 5ms extend */
-               rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
-               coex_stat->wl_slot_extend = false;
-               coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], set h2c 0x69 opcode 12 to turn off 5ms WL slot extend!!\n");
+               rtw_coex_wl_slot_extend(rtwdev, false);
                return;
        }
 
@@ -144,16 +186,20 @@ static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev)
                else
                        coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
 
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], 5ms WL slot extend cnt = %d!!\n",
+                       coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]);
+
                if (coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] == 7) {
-                       para[1] = 0x1; /* disable 5ms extend */
-                       rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
-                       coex_stat->wl_slot_extend = false;
-                       coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], set h2c 0x69 opcode 12 to turn off 5ms WL slot extend!!\n");
+                       rtw_coex_wl_slot_extend(rtwdev, false);
                }
        } else if (!coex_stat->wl_slot_extend && coex_stat->wl_cck_lock) {
-               para[1] = 0x0; /* enable 5ms extend */
-               rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
-               coex_stat->wl_slot_extend = true;
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], set h2c 0x69 opcode 12 to turn on 5ms WL slot extend!!\n");
+
+               rtw_coex_wl_slot_extend(rtwdev, true);
        }
 }
 
@@ -161,11 +207,48 @@ static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev)
 {
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
+       struct rtw_coex_dm *coex_dm = &coex->dm;
 
-       /* TODO: wait for rx_rate_change_notify implement */
-       coex_stat->wl_cck_lock = false;
-       coex_stat->wl_cck_lock_pre = false;
-       coex_stat->wl_cck_lock_ever = false;
+       bool is_cck_lock_rate = false;
+
+       if (coex_dm->bt_status == COEX_BTSTATUS_INQ_PAGE ||
+           coex_stat->bt_setup_link) {
+               coex_stat->wl_cck_lock = false;
+               coex_stat->wl_cck_lock_pre = false;
+               return;
+       }
+
+       if (coex_stat->wl_rx_rate <= COEX_CCK_2 ||
+           coex_stat->wl_rts_rx_rate <= COEX_CCK_2)
+               is_cck_lock_rate = true;
+
+       if (coex_stat->wl_connected && coex_stat->wl_gl_busy &&
+           COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
+           (coex_dm->bt_status == COEX_BTSTATUS_ACL_BUSY ||
+            coex_dm->bt_status == COEX_BTSTATUS_ACL_SCO_BUSY ||
+            coex_dm->bt_status == COEX_BTSTATUS_SCO_BUSY)) {
+               if (is_cck_lock_rate) {
+                       coex_stat->wl_cck_lock = true;
+
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], cck locking...\n");
+
+               } else {
+                       coex_stat->wl_cck_lock = false;
+
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], cck unlock...\n");
+               }
+       } else {
+               coex_stat->wl_cck_lock = false;
+       }
+
+       /* CCK lock identification */
+       if (coex_stat->wl_cck_lock && !coex_stat->wl_cck_lock_pre)
+               ieee80211_queue_delayed_work(rtwdev->hw, &coex->wl_ccklock_work,
+                                            3 * HZ);
+
+       coex_stat->wl_cck_lock_pre = coex_stat->wl_cck_lock;
 }
 
 static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev)
@@ -174,11 +257,12 @@ static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev)
        struct rtw_coex_stat *coex_stat = &coex->stat;
        struct rtw_dm_info *dm_info = &rtwdev->dm_info;
        u32 cnt_cck;
+       bool wl_cck_lock = false;
 
        /* wifi noisy environment identification */
        cnt_cck = dm_info->cck_ok_cnt + dm_info->cck_err_cnt;
 
-       if (!coex_stat->wl_gl_busy) {
+       if (!coex_stat->wl_gl_busy && !wl_cck_lock) {
                if (cnt_cck > 250) {
                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] < 5)
                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY2]++;
@@ -211,6 +295,9 @@ static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev)
                        coex_stat->wl_noisy_level = 1;
                else
                        coex_stat->wl_noisy_level = 0;
+
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], wl_noisy_level = %d\n",
+                       coex_stat->wl_noisy_level);
        }
 }
 
@@ -219,6 +306,8 @@ static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type)
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
        u8 para[2] = {0};
+       u8 times;
+       u16 tbtt_interval = coex_stat->wl_beacon_interval;
 
        if (coex_stat->tdma_timer_base == type)
                return;
@@ -227,13 +316,33 @@ static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type)
 
        para[0] = COEX_H2C69_TDMA_SLOT;
 
-       if (type == 3) /* 4-slot  */
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], tbtt_interval = %d\n",
+               tbtt_interval);
+
+       if (type == TDMA_TIMER_TYPE_4SLOT && tbtt_interval < 120) {
                para[1] = PARA1_H2C69_TDMA_4SLOT; /* 4-slot */
-       else /* 2-slot  */
+       } else if (tbtt_interval < 80 && tbtt_interval > 0) {
+               times = 100 / tbtt_interval;
+               if (100 % tbtt_interval != 0)
+                       times++;
+
+               para[1] = FIELD_PREP(PARA1_H2C69_TBTT_TIMES, times);
+       } else if (tbtt_interval >= 180) {
+               times = tbtt_interval / 100;
+               if (tbtt_interval % 100 <= 80)
+                       times--;
+
+               para[1] = FIELD_PREP(PARA1_H2C69_TBTT_TIMES, times) |
+                         FIELD_PREP(PARA1_H2C69_TBTT_DIV100, 1);
+       } else {
                para[1] = PARA1_H2C69_TDMA_2SLOT;
+       }
 
        rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): h2c_0x69 = 0x%x\n",
+               __func__, para[1]);
+
        /* no 5ms_wl_slot_extend for 4-slot mode  */
        if (coex_stat->tdma_timer_base == 3)
                rtw_coex_wl_ccklock_action(rtwdev);
@@ -307,6 +416,9 @@ static void rtw_coex_check_rfk(struct rtw_dev *rtwdev)
 
        if (coex_rfe->wlg_at_btg && chip->scbd_support &&
            coex_stat->bt_iqk_state != 0xff) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], (Before Ant Setup) Delay by IQK\n");
+
                wait_cnt = COEX_RFK_TIMEOUT / COEX_MIN_DELAY;
                do {
                        /* BT RFK */
@@ -318,6 +430,10 @@ static void rtw_coex_check_rfk(struct rtw_dev *rtwdev)
                        if (!btk && !wlk)
                                break;
 
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], (Before Ant Setup) wlk = %d, btk = %d\n",
+                               wlk, btk);
+
                        mdelay(COEX_MIN_DELAY);
                } while (++cnt < wait_cnt);
 
@@ -334,9 +450,16 @@ static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev)
        if (coex_stat->bt_disabled)
                return;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
        rtw_fw_query_bt_info(rtwdev);
 }
 
+static void rtw_coex_gnt_workaround(struct rtw_dev *rtwdev, bool force, u8 mode)
+{
+       rtw_coex_set_gnt_fix(rtwdev);
+}
+
 static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
 {
        struct rtw_chip_info *chip = rtwdev->chip;
@@ -352,21 +475,23 @@ static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
        }
 
        if (coex_stat->bt_disabled != bt_disabled) {
-               rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: BT state changed (%d) -> (%d)\n",
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], BT state changed (%d) -> (%d)\n",
                        coex_stat->bt_disabled, bt_disabled);
 
                coex_stat->bt_disabled = bt_disabled;
                coex_stat->bt_ble_scan_type = 0;
                coex_dm->cur_bt_lna_lvl = 0;
-       }
 
-       if (!coex_stat->bt_disabled) {
-               coex_stat->bt_reenable = true;
-               ieee80211_queue_delayed_work(rtwdev->hw,
-                                            &coex->bt_reenable_work, 15 * HZ);
-       } else {
-               coex_stat->bt_mailbox_reply = false;
-               coex_stat->bt_reenable = false;
+               if (!coex_stat->bt_disabled) {
+                       coex_stat->bt_reenable = true;
+                       ieee80211_queue_delayed_work(rtwdev->hw,
+                                                    &coex->bt_reenable_work,
+                                                    15 * HZ);
+               } else {
+                       coex_stat->bt_mailbox_reply = false;
+                       coex_stat->bt_reenable = false;
+               }
        }
 }
 
@@ -420,6 +545,12 @@ static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason)
                coex_dm->wl_rssi_state[i] = rssi_state;
        }
 
+       if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 ||
+           coex_stat->wl_hi_pri_task2 || coex_stat->wl_gl_busy)
+               rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, true);
+       else
+               rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);
+
        switch (reason) {
        case COEX_RSN_5GSCANSTART:
        case COEX_RSN_5GSWITCHBAND:
@@ -535,6 +666,23 @@ out:
        return ret;
 }
 
+#define case_BTSTATUS(src) \
+       case COEX_BTSTATUS_##src: return #src
+
+static const char *rtw_coex_get_bt_status_string(u8 bt_status)
+{
+       switch (bt_status) {
+       case_BTSTATUS(NCON_IDLE);
+       case_BTSTATUS(CON_IDLE);
+       case_BTSTATUS(INQ_PAGE);
+       case_BTSTATUS(ACL_BUSY);
+       case_BTSTATUS(SCO_BUSY);
+       case_BTSTATUS(ACL_SCO_BUSY);
+       default:
+               return "Unknown";
+       }
+}
+
 static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
 {
        struct rtw_coex *coex = &rtwdev->coex;
@@ -551,20 +699,11 @@ static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
                rssi_state = coex_dm->bt_rssi_state[i];
                rssi_step = chip->bt_rssi_step[i];
                rssi = coex_stat->bt_rssi;
-               rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
-                                                     rssi, rssi_step);
+               rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state, rssi,
+                                                     rssi_step);
                coex_dm->bt_rssi_state[i] = rssi_state;
        }
 
-       for (i = 0; i < COEX_RSSI_STEP; i++) {
-               rssi_state = coex_dm->wl_rssi_state[i];
-               rssi_step = chip->wl_rssi_step[i];
-               rssi = rtwdev->dm_info.min_rssi;
-               rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
-                                                     rssi, rssi_step);
-               coex_dm->wl_rssi_state[i] = rssi_state;
-       }
-
        if (coex_stat->bt_ble_scan_en &&
            coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE] % 3 == 0) {
                u8 scan_type;
@@ -623,6 +762,7 @@ static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
                coex_dm->bt_status = COEX_BTSTATUS_INQ_PAGE;
        } else if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {
                coex_dm->bt_status = COEX_BTSTATUS_NCON_IDLE;
+               coex_stat->bt_multi_link_remain = false;
        } else if (coex_stat->bt_info_lb2 == COEX_INFO_CONNECTION) {
                coex_dm->bt_status = COEX_BTSTATUS_CON_IDLE;
        } else if ((coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) ||
@@ -639,7 +779,8 @@ static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
 
        coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE]++;
 
-       rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: bt status(%d)\n", coex_dm->bt_status);
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(), %s!!!\n", __func__,
+               rtw_coex_get_bt_status_string(coex_dm->bt_status));
 }
 
 static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
@@ -659,6 +800,8 @@ static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
 
        if (center_chan == 0 || (efuse->share_ant && center_chan <= 14)) {
                link = 0;
+               center_chan = 0;
+               bw = 0;
        } else if (center_chan <= 14) {
                link = 0x1;
 
@@ -682,6 +825,9 @@ static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
        coex_dm->wl_ch_info[2] = bw;
 
        rtw_fw_wl_ch_info(rtwdev, link, center_chan, bw);
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex], %s: para[0:2] = 0x%x 0x%x 0x%x\n", __func__, link,
+               center_chan, bw);
 }
 
 static void rtw_coex_set_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl)
@@ -714,6 +860,8 @@ static void rtw_coex_set_bt_rx_gain(struct rtw_dev *rtwdev, u8 bt_lna_lvl)
        } else {
                rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, false);
        }
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): bt_rx_LNA_level = %d\n",
+               __func__, bt_lna_lvl);
 }
 
 static void rtw_coex_set_rf_para(struct rtw_dev *rtwdev,
@@ -723,7 +871,7 @@ static void rtw_coex_set_rf_para(struct rtw_dev *rtwdev,
        struct rtw_coex_stat *coex_stat = &coex->stat;
        u8 offset = 0;
 
-       if (coex->freerun && coex_stat->wl_noisy_level <= 1)
+       if (coex->freerun && coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] <= 5)
                offset = 3;
 
        rtw_coex_set_wl_tx_power(rtwdev, para.wl_pwr_dec_lvl);
@@ -765,11 +913,13 @@ static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control)
        const struct rtw_hw_reg *btg_reg = chip->btg_reg;
 
        if (wifi_control) {
-               rtw_write32_set(rtwdev, REG_SYS_SDIO_CTRL, BIT_LTE_MUX_CTRL_PATH);
+               rtw_write8_set(rtwdev, REG_SYS_SDIO_CTRL + 3,
+                              BIT_LTE_MUX_CTRL_PATH >> 24);
                if (btg_reg)
                        rtw_write8_set(rtwdev, btg_reg->addr, btg_reg->mask);
        } else {
-               rtw_write32_clr(rtwdev, REG_SYS_SDIO_CTRL, BIT_LTE_MUX_CTRL_PATH);
+               rtw_write8_clr(rtwdev, REG_SYS_SDIO_CTRL + 3,
+                              BIT_LTE_MUX_CTRL_PATH >> 24);
                if (btg_reg)
                        rtw_write8_clr(rtwdev, btg_reg->addr, btg_reg->mask);
        }
@@ -777,52 +927,134 @@ static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control)
 
 static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state)
 {
-       rtw_coex_write_indirect_reg(rtwdev, 0x38, 0xc000, state);
-       rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x0c00, state);
+       rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0xc000, state);
+       rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0c00, state);
 }
 
 static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state)
 {
-       rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x3000, state);
-       rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x0300, state);
+       rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x3000, state);
+       rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state);
+}
+
+static void rtw_btc_wltoggle_table_a(struct rtw_dev *rtwdev, bool force,
+                                    u8 table_case)
+{
+       struct rtw_chip_info *chip = rtwdev->chip;
+       struct rtw_efuse *efuse = &rtwdev->efuse;
+       u8 h2c_para[6] = {0};
+       u32 table_wl = 0x5a5a5a5a;
+
+       h2c_para[0] = COEX_H2C69_TOGGLE_TABLE_A;
+       /* no definition */
+       h2c_para[1] = 0x1;
+
+       if (efuse->share_ant) {
+               if (table_case < chip->table_sant_num)
+                       table_wl = chip->table_sant[table_case].wl;
+       } else {
+               if (table_case < chip->table_nsant_num)
+                       table_wl = chip->table_nsant[table_case].wl;
+       }
+
+       /* tell WL FW WL slot toggle table-A*/
+       h2c_para[2] = (u8)u32_get_bits(table_wl, GENMASK(7, 0));
+       h2c_para[3] = (u8)u32_get_bits(table_wl, GENMASK(15, 8));
+       h2c_para[4] = (u8)u32_get_bits(table_wl, GENMASK(23, 16));
+       h2c_para[5] = (u8)u32_get_bits(table_wl, GENMASK(31, 24));
+
+       rtw_fw_bt_wifi_control(rtwdev, h2c_para[0], &h2c_para[1]);
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n",
+               __func__, h2c_para[0], h2c_para[1], h2c_para[2],
+               h2c_para[3], h2c_para[4], h2c_para[5]);
+}
+
+#define COEX_WL_SLOT_TOGLLE 0x5a5a5aaa
+static void rtw_btc_wltoggle_table_b(struct rtw_dev *rtwdev, bool force,
+                                    u8 interval, u32 table)
+{
+       struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
+       u8 cur_h2c_para[6] = {0};
+       u8 i;
+
+       cur_h2c_para[0] = COEX_H2C69_TOGGLE_TABLE_B;
+       cur_h2c_para[1] = interval;
+       cur_h2c_para[2] = (u8)u32_get_bits(table, GENMASK(7, 0));
+       cur_h2c_para[3] = (u8)u32_get_bits(table, GENMASK(15, 8));
+       cur_h2c_para[4] = (u8)u32_get_bits(table, GENMASK(23, 16));
+       cur_h2c_para[5] = (u8)u32_get_bits(table, GENMASK(31, 24));
+
+       coex_stat->wl_toggle_interval = interval;
+
+       for (i = 0; i <= 5; i++)
+               coex_stat->wl_toggle_para[i] = cur_h2c_para[i];
+
+       rtw_fw_bt_wifi_control(rtwdev, cur_h2c_para[0], &cur_h2c_para[1]);
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n",
+               __func__, cur_h2c_para[0], cur_h2c_para[1], cur_h2c_para[2],
+               cur_h2c_para[3], cur_h2c_para[4], cur_h2c_para[5]);
 }
 
-static void rtw_coex_set_table(struct rtw_dev *rtwdev, u32 table0, u32 table1)
+static void rtw_coex_set_table(struct rtw_dev *rtwdev, bool force, u32 table0,
+                              u32 table1)
 {
-#define DEF_BRK_TABLE_VAL      0xf0ffffff
+#define DEF_BRK_TABLE_VAL 0xf0ffffff
+       struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_coex_dm *coex_dm = &coex->dm;
+
+       /* If last tdma is wl slot toggle, force write table*/
+       if (!force && coex_dm->reason != COEX_RSN_LPS) {
+               if (table0 == rtw_read32(rtwdev, REG_BT_COEX_TABLE0) &&
+                   table1 == rtw_read32(rtwdev, REG_BT_COEX_TABLE1))
+                       return;
+       }
        rtw_write32(rtwdev, REG_BT_COEX_TABLE0, table0);
        rtw_write32(rtwdev, REG_BT_COEX_TABLE1, table1);
        rtw_write32(rtwdev, REG_BT_COEX_BRK_TABLE, DEF_BRK_TABLE_VAL);
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex], %s(): 0x6c0 = %x, 0x6c4 = %x\n", __func__, table0,
+               table1);
 }
 
-static void rtw_coex_table(struct rtw_dev *rtwdev, u8 type)
+static void rtw_coex_table(struct rtw_dev *rtwdev, bool force, u8 type)
 {
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_dm *coex_dm = &coex->dm;
        struct rtw_chip_info *chip = rtwdev->chip;
        struct rtw_efuse *efuse = &rtwdev->efuse;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
 
        coex_dm->cur_table = type;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], Coex_Table - %d\n", type);
+
        if (efuse->share_ant) {
                if (type < chip->table_sant_num)
-                       rtw_coex_set_table(rtwdev,
+                       rtw_coex_set_table(rtwdev, force,
                                           chip->table_sant[type].bt,
                                           chip->table_sant[type].wl);
        } else {
                type = type - 100;
                if (type < chip->table_nsant_num)
-                       rtw_coex_set_table(rtwdev,
+                       rtw_coex_set_table(rtwdev, force,
                                           chip->table_nsant[type].bt,
                                           chip->table_nsant[type].wl);
        }
+       if (coex_stat->wl_slot_toggle_change)
+               rtw_btc_wltoggle_table_a(rtwdev, true, type);
 }
 
 static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable)
 {
        struct rtw_coex *coex = &rtwdev->coex;
 
-       if (coex->stop_dm)
+       if (coex->manual_control || coex->stop_dm)
                return;
 
        rtw_fw_bt_ignore_wlan_action(rtwdev, enable);
@@ -841,15 +1073,18 @@ static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type,
        case COEX_PS_WIFI_NATIVE:
                /* recover to original 32k low power setting */
                coex_stat->wl_force_lps_ctrl = false;
-
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s(): COEX_PS_WIFI_NATIVE\n", __func__);
                rtw_leave_lps(rtwdev);
                break;
        case COEX_PS_LPS_OFF:
                coex_stat->wl_force_lps_ctrl = true;
                if (lps_mode)
-                       rtw_fw_coex_tdma_type(rtwdev, 0x8, 0, 0, 0, 0);
+                       rtw_fw_coex_tdma_type(rtwdev, 0, 0, 0, 0, 0);
 
                rtw_leave_lps(rtwdev);
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s(): COEX_PS_LPS_OFF\n", __func__);
                break;
        default:
                break;
@@ -862,10 +1097,14 @@ static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_dm *coex_dm = &coex->dm;
        struct rtw_chip_info *chip = rtwdev->chip;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
        u8 ps_type = COEX_PS_WIFI_NATIVE;
        bool ap_enable = false;
 
        if (ap_enable && (byte1 & BIT(4) && !(byte1 & BIT(5)))) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): AP mode\n",
+                       __func__);
+
                byte1 &= ~BIT(4);
                byte1 |= BIT(5);
 
@@ -875,12 +1114,20 @@ static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
                ps_type = COEX_PS_WIFI_NATIVE;
                rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
        } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s(): Force LPS (byte1 = 0x%x)\n", __func__,
+                       byte1);
+
                if (chip->pstdma_type == COEX_PSTDMA_FORCE_LPSOFF)
                        ps_type = COEX_PS_LPS_OFF;
                else
                        ps_type = COEX_PS_LPS_ON;
                rtw_coex_power_save_state(rtwdev, ps_type, 0x50, 0x4);
        } else {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s(): native power save (byte1 = 0x%x)\n",
+                       __func__, byte1);
+
                ps_type = COEX_PS_WIFI_NATIVE;
                rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
        }
@@ -892,6 +1139,14 @@ static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
        coex_dm->ps_tdma_para[4] = byte5;
 
        rtw_fw_coex_tdma_type(rtwdev, byte1, byte2, byte3, byte4, byte5);
+
+       if (byte1 & BIT(2)) {
+               coex_stat->wl_slot_toggle = true;
+               coex_stat->wl_slot_toggle_change = false;
+       } else {
+               coex_stat->wl_slot_toggle_change = coex_stat->wl_slot_toggle;
+               coex_stat->wl_slot_toggle = false;
+       }
 }
 
 static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)
@@ -905,26 +1160,24 @@ static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)
        bool turn_on;
        bool wl_busy = false;
 
-       if (tcase & TDMA_4SLOT)/* 4-slot (50ms) mode */
-               rtw_coex_tdma_timer_base(rtwdev, 3);
+       if (tcase & TDMA_4SLOT) /* 4-slot (50ms) mode */
+               rtw_coex_tdma_timer_base(rtwdev, TDMA_TIMER_TYPE_4SLOT);
        else
-               rtw_coex_tdma_timer_base(rtwdev, 0);
+               rtw_coex_tdma_timer_base(rtwdev, TDMA_TIMER_TYPE_2SLOT);
 
        type = (u8)(tcase & 0xff);
 
        turn_on = (type == 0 || type == 100) ? false : true;
 
-       if (!force) {
-               if (turn_on == coex_dm->cur_ps_tdma_on &&
-                   type == coex_dm->cur_ps_tdma) {
-                       return;
-               }
-       }
-
-       /* enable TBTT interrupt */
-       if (turn_on)
-               rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
+       if (!force && turn_on == coex_dm->cur_ps_tdma_on &&
+           type == coex_dm->cur_ps_tdma) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], Skip TDMA because no change TDMA(%s, %d)\n",
+                       (coex_dm->cur_ps_tdma_on ? "on" : "off"),
+                       coex_dm->cur_ps_tdma);
 
+               return;
+       }
        wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
 
        if ((coex_stat->bt_a2dp_exist &&
@@ -934,6 +1187,10 @@ static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)
        else
                rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true);
 
+       /* update pre state */
+       coex_dm->cur_ps_tdma_on = turn_on;
+       coex_dm->cur_ps_tdma = type;
+
        if (efuse->share_ant) {
                if (type < chip->tdma_sant_num)
                        rtw_coex_set_tdma(rtwdev,
@@ -953,17 +1210,16 @@ static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)
                                          chip->tdma_nsant[n].para[4]);
        }
 
-       /* update pre state */
-       coex_dm->cur_ps_tdma_on = turn_on;
-       coex_dm->cur_ps_tdma = type;
 
-       rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: coex tdma type (%d)\n", type);
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], coex tdma type(%s, %d)\n",
+               turn_on ? "on" : "off", type);
 }
 
 static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
 {
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
+       struct rtw_coex_rfe *coex_rfe = &coex->rfe;
        struct rtw_coex_dm *coex_dm = &coex->dm;
        u8 ctrl_type = COEX_SWITCH_CTRL_MAX;
        u8 pos_type = COEX_SWITCH_TO_MAX;
@@ -976,8 +1232,14 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
        /* avoid switch coex_ctrl_owner during BT IQK */
        rtw_coex_check_rfk(rtwdev);
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex],  coex_stat->bt_disabled = 0x%x\n",
+               coex_stat->bt_disabled);
+
        switch (phase) {
        case COEX_SET_ANT_POWERON:
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s() - PHASE_COEX_POWERON\n", __func__);
                /* set path control owner to BT at power-on */
                if (coex_stat->bt_disabled)
                        rtw_coex_coex_ctrl_owner(rtwdev, true);
@@ -988,6 +1250,8 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
                pos_type = COEX_SWITCH_TO_BT;
                break;
        case COEX_SET_ANT_INIT:
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s() - PHASE_COEX_INIT\n", __func__);
                if (coex_stat->bt_disabled) {
                        /* set GNT_BT to SW low */
                        rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);
@@ -1009,10 +1273,12 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
                pos_type = COEX_SWITCH_TO_BT;
                break;
        case COEX_SET_ANT_WONLY:
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s() - PHASE_WLANONLY_INIT\n", __func__);
                /* set GNT_BT to SW Low */
                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);
 
-               /* Set GNT_WL to SW high */
+               /* set GNT_WL to SW high */
                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
 
                /* set path control owner to wl at initial step */
@@ -1022,6 +1288,8 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
                pos_type = COEX_SWITCH_TO_WLG;
                break;
        case COEX_SET_ANT_WOFF:
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s() - PHASE_WLAN_OFF\n", __func__);
                /* set path control owner to BT */
                rtw_coex_coex_ctrl_owner(rtwdev, false);
 
@@ -1029,6 +1297,8 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
                pos_type = COEX_SWITCH_TO_NOCARE;
                break;
        case COEX_SET_ANT_2G:
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s() - PHASE_2G_RUNTIME\n", __func__);
                /* set GNT_BT to PTA */
                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
 
@@ -1042,8 +1312,11 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
                pos_type = COEX_SWITCH_TO_NOCARE;
                break;
        case COEX_SET_ANT_5G:
-               /* set GNT_BT to PTA */
-               rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s() - PHASE_5G_RUNTIME\n", __func__);
+
+               /* set GNT_BT to HW PTA */
+               rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
 
                /* set GNT_WL to SW high */
                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
@@ -1055,8 +1328,11 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
                pos_type = COEX_SWITCH_TO_WLA;
                break;
        case COEX_SET_ANT_2G_FREERUN:
-               /* set GNT_BT to SW high */
-               rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s() - PHASE_2G_FREERUN\n", __func__);
+
+               /* set GNT_BT to HW PTA */
+               rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
 
                /* Set GNT_WL to SW high */
                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
@@ -1068,10 +1344,12 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
                pos_type = COEX_SWITCH_TO_WLG_BT;
                break;
        case COEX_SET_ANT_2G_WLBT:
-               /* set GNT_BT to SW high */
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s() - PHASE_2G_WLBT\n", __func__);
+               /* set GNT_BT to HW PTA */
                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
 
-               /* Set GNT_WL to SW high */
+               /* Set GNT_WL to HW PTA */
                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);
 
                /* set path control owner to wl at runtime step */
@@ -1085,10 +1363,58 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
                return;
        }
 
-       if (ctrl_type < COEX_SWITCH_CTRL_MAX && pos_type < COEX_SWITCH_TO_MAX)
+       if (ctrl_type < COEX_SWITCH_CTRL_MAX && pos_type < COEX_SWITCH_TO_MAX &&
+           coex_rfe->ant_switch_exist)
                rtw_coex_set_ant_switch(rtwdev, ctrl_type, pos_type);
 }
 
+#define case_ALGO(src) \
+       case COEX_ALGO_##src: return #src
+
+static const char *rtw_coex_get_algo_string(u8 algo)
+{
+       switch (algo) {
+       case_ALGO(NOPROFILE);
+       case_ALGO(HFP);
+       case_ALGO(HID);
+       case_ALGO(A2DP);
+       case_ALGO(PAN);
+       case_ALGO(A2DP_HID);
+       case_ALGO(A2DP_PAN);
+       case_ALGO(PAN_HID);
+       case_ALGO(A2DP_PAN_HID);
+       default:
+               return "Unknown";
+       }
+}
+
+#define case_BT_PROFILE(src) \
+       case BPM_##src: return #src
+
+static const char *rtw_coex_get_bt_profile_string(u8 bt_profile)
+{
+       switch (bt_profile) {
+       case_BT_PROFILE(NOPROFILE);
+       case_BT_PROFILE(HFP);
+       case_BT_PROFILE(HID);
+       case_BT_PROFILE(A2DP);
+       case_BT_PROFILE(PAN);
+       case_BT_PROFILE(HID_HFP);
+       case_BT_PROFILE(A2DP_HFP);
+       case_BT_PROFILE(A2DP_HID);
+       case_BT_PROFILE(A2DP_HID_HFP);
+       case_BT_PROFILE(PAN_HFP);
+       case_BT_PROFILE(PAN_HID);
+       case_BT_PROFILE(PAN_HID_HFP);
+       case_BT_PROFILE(PAN_A2DP);
+       case_BT_PROFILE(PAN_A2DP_HFP);
+       case_BT_PROFILE(PAN_A2DP_HID);
+       case_BT_PROFILE(PAN_A2DP_HID_HFP);
+       default:
+               return "Unknown";
+       }
+}
+
 static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev)
 {
        struct rtw_coex *coex = &rtwdev->coex;
@@ -1149,6 +1475,10 @@ static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev)
                break;
        }
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex], BT Profile = %s => Algorithm = %s\n",
+               rtw_coex_get_bt_profile_string(profile_map),
+               rtw_coex_get_algo_string(algorithm));
        return algorithm;
 }
 
@@ -1158,6 +1488,9 @@ static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                table_case = 2;
@@ -1168,8 +1501,7 @@ static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev)
                tdma_case = 100;
        }
 
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1181,13 +1513,16 @@ static void rtw_coex_action_freerun(struct rtw_dev *rtwdev)
        struct rtw_efuse *efuse = &rtwdev->efuse;
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 level = 0;
+       bool bt_afh_loss = true;
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
 
        if (efuse->share_ant)
                return;
 
        coex->freerun = true;
 
-       if (coex_stat->wl_connected)
+       if (bt_afh_loss)
                rtw_coex_update_wl_ch_info(rtwdev, COEX_MEDIA_CONNECT);
 
        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);
@@ -1211,41 +1546,49 @@ static void rtw_coex_action_freerun(struct rtw_dev *rtwdev)
        else
                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[level]);
 
-       rtw_coex_table(rtwdev, 100);
+       rtw_coex_table(rtwdev, false, 100);
        rtw_coex_tdma(rtwdev, false, 100);
 }
 
-static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev)
+static void rtw_coex_action_rf4ce(struct rtw_dev *rtwdev)
 {
        struct rtw_efuse *efuse = &rtwdev->efuse;
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
-               table_case = 2;
-               tdma_case = 0;
+               table_case = 9;
+               tdma_case = 16;
        } else {
                /* Non-Shared-Ant */
                table_case = 100;
                tdma_case = 100;
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
-static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)
+static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev)
 {
        struct rtw_efuse *efuse = &rtwdev->efuse;
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
-               table_case = 1;
+               table_case = 2;
                tdma_case = 0;
        } else {
                /* Non-Shared-Ant */
@@ -1253,9 +1596,45 @@ static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)
                tdma_case = 100;
        }
 
+       rtw_coex_table(rtwdev, false, table_case);
+       rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)
+{
+       struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
+       struct rtw_efuse *efuse = &rtwdev->efuse;
+       struct rtw_chip_info *chip = rtwdev->chip;
+       u8 table_case, tdma_case;
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+
+       if (efuse->share_ant) { /* Shared-Ant */
+               if (coex_stat->wl_gl_busy) {
+                       table_case = 26;
+                       if (coex_stat->bt_hid_exist &&
+                           coex_stat->bt_profile_num == 1) {
+                               tdma_case = 20;
+                       } else {
+                               tdma_case = 20;
+                       }
+               } else {
+                       table_case = 1;
+                       tdma_case = 0;
+               }
+       } else { /* Non-Shared-Ant */
+               if (coex_stat->wl_gl_busy)
+                       table_case = 115;
+               else
+                       table_case = 100;
+               tdma_case = 100;
+       }
+
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1269,10 +1648,14 @@ static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
        struct rtw_coex_rfe *coex_rfe = &coex->rfe;
        u8 table_case = 0xff, tdma_case = 0xff;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (coex_rfe->ant_switch_with_bt &&
            coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
                if (efuse->share_ant &&
-                   COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) {
+                   COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
+                   coex_stat->wl_gl_busy) {
                        table_case = 0;
                        tdma_case = 0;
                } else if (!efuse->share_ant) {
@@ -1283,9 +1666,7 @@ static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
 
        if (table_case != 0xff && tdma_case != 0xff) {
                rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);
-               rtw_coex_table(rtwdev, table_case);
-               rtw_coex_tdma(rtwdev, false, tdma_case);
-               return;
+               goto exit;
        }
 
        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
@@ -1296,8 +1677,12 @@ static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
                        table_case = 10;
                        tdma_case = 3;
                } else if (coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
-                       table_case = 6;
-                       tdma_case = 7;
+                       table_case = 11;
+
+                       if (coex_stat->lo_pri_rx + coex_stat->lo_pri_tx > 250)
+                               tdma_case = 17;
+                       else
+                               tdma_case = 7;
                } else {
                        table_case = 12;
                        tdma_case = 7;
@@ -1308,7 +1693,7 @@ static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
                        table_case = 112;
                        tdma_case = 104;
                } else if ((coex_stat->bt_ble_scan_type & 0x2) &&
-                           coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
+                          coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
                        table_case = 114;
                        tdma_case = 103;
                } else {
@@ -1317,8 +1702,8 @@ static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
                }
        }
 
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+exit:
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1332,6 +1717,10 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
        u8 table_case, tdma_case;
        u32 slot_type = 0;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 ||
            coex_stat->wl_hi_pri_task2)
                wl_hi_pri = true;
@@ -1339,7 +1728,10 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
        if (efuse->share_ant) {
                /* Shared-Ant */
                if (wl_hi_pri) {
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], bt inq/page +  wifi hi-pri task\n");
                        table_case = 15;
+
                        if (coex_stat->bt_profile_num > 0)
                                tdma_case = 10;
                        else if (coex_stat->wl_hi_pri_task1)
@@ -1349,6 +1741,8 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
                        else
                                tdma_case = 9;
                } else if (coex_stat->wl_gl_busy) {
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], bt inq/page + wifi busy\n");
                        if (coex_stat->bt_profile_num == 0) {
                                table_case = 12;
                                tdma_case = 18;
@@ -1363,43 +1757,53 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
                                tdma_case = 26;
                        }
                } else if (coex_stat->wl_connected) {
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], bt inq/page + wifi connected\n");
                        table_case = 9;
                        tdma_case = 27;
                } else {
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], bt inq/page + wifi not-connected\n");
                        table_case = 1;
                        tdma_case = 0;
                }
        } else {
                /* Non_Shared-Ant */
                if (wl_hi_pri) {
-                       table_case = 113;
-                       if (coex_stat->bt_a2dp_exist &&
-                           !coex_stat->bt_pan_exist)
-                               tdma_case = 111;
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], bt inq/page +  wifi hi-pri task\n");
+                       table_case = 114;
+
+                       if (coex_stat->bt_profile_num > 0)
+                               tdma_case = 110;
                        else if (coex_stat->wl_hi_pri_task1)
                                tdma_case = 106;
                        else if (!coex_stat->bt_page)
                                tdma_case = 108;
                        else
                                tdma_case = 109;
-               } else if (coex_stat->wl_gl_busy) {
+               }  else if (coex_stat->wl_gl_busy) {
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], bt inq/page + wifi busy\n");
                        table_case = 114;
                        tdma_case = 121;
                } else if (coex_stat->wl_connected) {
-                       table_case = 100;
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], bt inq/page +  wifi connected\n");
+                       table_case = 101;
                        tdma_case = 100;
                } else {
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], bt inq/page +  wifi not-connected\n");
                        table_case = 101;
                        tdma_case = 100;
                }
        }
 
-       rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: wifi hi(%d), bt page(%d)\n",
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], wifi hi(%d), bt page(%d)\n",
                wl_hi_pri, coex_stat->bt_page);
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
 }
 
@@ -1411,6 +1815,10 @@ static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                if (coex_stat->bt_multi_link) {
@@ -1431,9 +1839,7 @@ static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
                }
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1444,62 +1850,80 @@ static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)
        struct rtw_efuse *efuse = &rtwdev->efuse;
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
-       u32 wl_bw;
+       u32 slot_type = 0;
+       bool bt_multi_link_remain = false, is_toggle_table = false;
 
-       wl_bw = rtwdev->hal.current_band_width;
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
 
        if (efuse->share_ant) {
                /* Shared-Ant */
                if (coex_stat->bt_ble_exist) {
                        /* RCU */
-                       if (!coex_stat->wl_gl_busy)
-                               table_case = 14;
-                       else
-                               table_case = 15;
-
-                       if (coex_stat->bt_a2dp_active || wl_bw == 0)
-                               tdma_case = 18;
-                       else if (coex_stat->wl_gl_busy)
-                               tdma_case = 8;
-                       else
-                               tdma_case = 4;
+                       if (coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] > 5) {
+                               table_case = 26;
+                               tdma_case = 2;
+                       } else {
+                               table_case = 27;
+                               tdma_case = 9;
+                       }
                } else {
-                       if (coex_stat->bt_a2dp_active || wl_bw == 0) {
-                               table_case = 8;
-                               tdma_case = 4;
+                       /* Legacy HID  */
+                       if (coex_stat->bt_profile_num == 1 &&
+                           (coex_stat->bt_multi_link ||
+                           (coex_stat->lo_pri_rx +
+                            coex_stat->lo_pri_tx > 360) ||
+                            coex_stat->bt_slave ||
+                            bt_multi_link_remain)) {
+                               slot_type = TDMA_4SLOT;
+                               table_case = 12;
+                               tdma_case = 20;
+                       } else if (coex_stat->bt_a2dp_active) {
+                               table_case = 9;
+                               tdma_case = 18;
+                       } else if (coex_stat->bt_418_hid_exist &&
+                                  coex_stat->wl_gl_busy) {
+                               is_toggle_table = true;
+                               slot_type = TDMA_4SLOT;
+                               table_case = 9;
+                               tdma_case = 24;
+                       } else if (coex_stat->bt_ble_hid_exist &&
+                                  coex_stat->wl_gl_busy) {
+                               table_case = 32;
+                               tdma_case = 9;
                        } else {
-                               /* for 4/18 HID */
-                               if (coex_stat->bt_418_hid_exist &&
-                                   coex_stat->wl_gl_busy)
-                                       table_case = 12;
-                               else
-                                       table_case = 10;
-                               tdma_case = 4;
+                               table_case = 9;
+                               tdma_case = 9;
                        }
                }
        } else {
                /* Non-Shared-Ant */
-               if (coex_stat->bt_a2dp_active) {
-                       table_case = 113;
-                       tdma_case = 118;
-               } else if (coex_stat->bt_ble_exist) {
+               if (coex_stat->bt_ble_exist) {
                        /* BLE */
+                       if (coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] > 5) {
+                               table_case = 121;
+                               tdma_case = 102;
+                       } else {
+                               table_case = 122;
+                               tdma_case = 109;
+                       }
+               } else if (coex_stat->bt_a2dp_active) {
                        table_case = 113;
-
-                       if (coex_stat->wl_gl_busy)
-                               tdma_case = 106;
-                       else
-                               tdma_case = 104;
+                       tdma_case = 118;
                } else {
                        table_case = 113;
                        tdma_case = 104;
                }
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
-       rtw_coex_tdma(rtwdev, false, tdma_case);
+       rtw_coex_table(rtwdev, false, table_case);
+       if (is_toggle_table) {
+               rtw_btc_wltoggle_table_a(rtwdev, true, table_case);
+               rtw_btc_wltoggle_table_b(rtwdev, false, 1, COEX_WL_SLOT_TOGLLE);
+       }
+
+       rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
 }
 
 static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)
@@ -1512,19 +1936,24 @@ static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)
        u8 table_case, tdma_case;
        u32 slot_type = 0;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
+       slot_type = TDMA_4SLOT;
+
        if (efuse->share_ant) {
                /* Shared-Ant */
-               slot_type = TDMA_4SLOT;
-
                if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)
-                       table_case = 10;
+                       table_case = 12;
                else
                        table_case = 9;
 
-               if (coex_stat->wl_gl_busy)
-                       tdma_case = 13;
-               else
+               if (coex_stat->wl_connecting || !coex_stat->wl_gl_busy)
                        tdma_case = 14;
+               else
+                       tdma_case = 13;
        } else {
                /* Non-Shared-Ant */
                table_case = 112;
@@ -1535,9 +1964,7 @@ static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)
                        tdma_case = 113;
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
 }
 
@@ -1550,6 +1977,11 @@ static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev)
        u8 table_case, tdma_case;
        bool ap_enable = false;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) { /* Shared-Ant */
                if (ap_enable) {
                        table_case = 2;
@@ -1571,9 +2003,7 @@ static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev)
                }
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1585,6 +2015,10 @@ static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)
@@ -1595,7 +2029,7 @@ static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)
                if (coex_stat->wl_gl_busy)
                        tdma_case = 17;
                else
-                       tdma_case = 19;
+                       tdma_case = 20;
        } else {
                /* Non-Shared-Ant */
                table_case = 112;
@@ -1606,9 +2040,7 @@ static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)
                        tdma_case = 119;
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1619,22 +2051,34 @@ static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev)
        struct rtw_coex_dm *coex_dm = &coex->dm;
        struct rtw_efuse *efuse = &rtwdev->efuse;
        struct rtw_chip_info *chip = rtwdev->chip;
-       u8 table_case, tdma_case;
+       u8 table_case, tdma_case, interval;
        u32 slot_type = 0;
+       bool is_toggle_table = false;
+
+       slot_type = TDMA_4SLOT;
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
 
        if (efuse->share_ant) {
                /* Shared-Ant */
-               slot_type = TDMA_4SLOT;
-
-               if (coex_stat->bt_ble_exist)
-                       table_case = 26;
-               else
+               if (coex_stat->bt_ble_exist) {
+                       table_case = 26; /* for RCU */
+               } else if (coex_stat->bt_418_hid_exist) {
                        table_case = 9;
-
-               if (coex_stat->wl_gl_busy) {
-                       tdma_case = 13;
+                       interval = 1;
                } else {
+                       table_case = 9;
+               }
+
+               if (coex_stat->wl_connecting || !coex_stat->wl_gl_busy) {
                        tdma_case = 14;
+               } else if (coex_stat->bt_418_hid_exist) {
+                       is_toggle_table = true;
+                       tdma_case = 23;
+               } else {
+                       tdma_case = 13;
                }
        } else {
                /* Non-Shared-Ant */
@@ -1649,9 +2093,11 @@ static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev)
                        tdma_case = 113;
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
+       if (is_toggle_table) {
+               rtw_btc_wltoggle_table_a(rtwdev, true, table_case);
+               rtw_btc_wltoggle_table_b(rtwdev, false, interval, COEX_WL_SLOT_TOGLLE);
+       }
        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
 }
 
@@ -1662,19 +2108,37 @@ static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev)
        struct rtw_efuse *efuse = &rtwdev->efuse;
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
+       bool wl_cpt_test = false, bt_cpt_test = false;
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
 
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
        if (efuse->share_ant) {
                /* Shared-Ant */
-               if (coex_stat->wl_gl_busy &&
-                   coex_stat->wl_noisy_level == 0)
-                       table_case = 14;
-               else
-                       table_case = 10;
+               if (wl_cpt_test) {
+                       if (coex_stat->wl_gl_busy) {
+                               table_case = 20;
+                               tdma_case = 17;
+                       } else {
+                               table_case = 10;
+                               tdma_case = 15;
+                       }
+               } else if (bt_cpt_test) {
+                       table_case = 26;
+                       tdma_case = 26;
+               } else {
+                       if (coex_stat->wl_gl_busy &&
+                           coex_stat->wl_noisy_level == 0)
+                               table_case = 14;
+                       else
+                               table_case = 10;
 
-               if (coex_stat->wl_gl_busy)
-                       tdma_case = 15;
-               else
-                       tdma_case = 20;
+                       if (coex_stat->wl_gl_busy)
+                               tdma_case = 15;
+                       else
+                               tdma_case = 20;
+               }
        } else {
                /* Non-Shared-Ant */
                table_case = 112;
@@ -1685,9 +2149,12 @@ static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev)
                        tdma_case = 120;
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       if (wl_cpt_test)
+               rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[1]);
+       else
+               rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1699,6 +2166,11 @@ static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                table_case = 9;
@@ -1717,9 +2189,7 @@ static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev)
                        tdma_case = 119;
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1731,6 +2201,10 @@ static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                table_case = 10;
@@ -1749,9 +2223,7 @@ static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)
                        tdma_case = 120;
        }
 
-       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1761,6 +2233,11 @@ static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
+       rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
 
        if (efuse->share_ant) {
@@ -1773,9 +2250,7 @@ static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
                tdma_case = 100;
        }
 
-       rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1785,6 +2260,10 @@ static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                table_case = 2;
@@ -1795,9 +2274,7 @@ static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev)
                tdma_case = 100;
        }
 
-       rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1811,6 +2288,11 @@ static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
        if (coex->under_5g)
                return;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                table_case = 28;
@@ -1821,9 +2303,7 @@ static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
                tdma_case = 100;
        }
 
-       rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1836,8 +2316,11 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
        u8 table_case, tdma_case;
        u32 slot_type = 0;
 
-       if (efuse->share_ant) {
-               /* Shared-Ant */
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
+       if (efuse->share_ant) { /* Shared-Ant */
                if (coex_stat->bt_a2dp_exist) {
                        slot_type = TDMA_4SLOT;
                        table_case = 9;
@@ -1846,9 +2329,9 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
                        table_case = 9;
                        tdma_case = 7;
                }
-       } else {
-               /* Non-Shared-Ant */
+       } else { /* Non-Shared-Ant */
                if (coex_stat->bt_a2dp_exist) {
+                       slot_type = TDMA_4SLOT;
                        table_case = 112;
                        tdma_case = 111;
                } else {
@@ -1857,9 +2340,7 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
                }
        }
 
-       rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
 }
 
@@ -1869,6 +2350,10 @@ static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        u8 table_case, tdma_case;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                table_case = 1;
@@ -1879,9 +2364,7 @@ static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev)
                tdma_case = 100;
        }
 
-       rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
-       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
-       rtw_coex_table(rtwdev, table_case);
+       rtw_coex_table(rtwdev, false, table_case);
        rtw_coex_tdma(rtwdev, false, tdma_case);
 }
 
@@ -1889,17 +2372,9 @@ static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)
 {
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
-       struct rtw_coex_dm *coex_dm = &coex->dm;
-       struct rtw_efuse *efuse = &rtwdev->efuse;
        u8 algorithm;
 
-       /* Non-Shared-Ant */
-       if (!efuse->share_ant && coex_stat->wl_gl_busy &&
-           COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
-           COEX_RSSI_HIGH(coex_dm->bt_rssi_state[0])) {
-               rtw_coex_action_freerun(rtwdev);
-               return;
-       }
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
 
        algorithm = rtw_coex_algorithm(rtwdev);
 
@@ -1908,10 +2383,15 @@ static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)
                rtw_coex_action_bt_hfp(rtwdev);
                break;
        case COEX_ALGO_HID:
-               rtw_coex_action_bt_hid(rtwdev);
+               if (rtw_coex_freerun_check(rtwdev))
+                       rtw_coex_action_freerun(rtwdev);
+               else
+                       rtw_coex_action_bt_hid(rtwdev);
                break;
        case COEX_ALGO_A2DP:
-               if (coex_stat->bt_a2dp_sink)
+               if (rtw_coex_freerun_check(rtwdev))
+                       rtw_coex_action_freerun(rtwdev);
+               else if (coex_stat->bt_a2dp_sink)
                        rtw_coex_action_bt_a2dpsink(rtwdev);
                else
                        rtw_coex_action_bt_a2dp(rtwdev);
@@ -1920,7 +2400,10 @@ static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)
                rtw_coex_action_bt_pan(rtwdev);
                break;
        case COEX_ALGO_A2DP_HID:
-               rtw_coex_action_bt_a2dp_hid(rtwdev);
+               if (rtw_coex_freerun_check(rtwdev))
+                       rtw_coex_action_freerun(rtwdev);
+               else
+                       rtw_coex_action_bt_a2dp_hid(rtwdev);
                break;
        case COEX_ALGO_A2DP_PAN:
                rtw_coex_action_bt_a2dp_pan(rtwdev);
@@ -1943,6 +2426,7 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_dm *coex_dm = &coex->dm;
        struct rtw_coex_stat *coex_stat = &coex->stat;
+       bool rf4ce_en = false;
 
        lockdep_assert_held(&rtwdev->mutex);
 
@@ -1951,20 +2435,38 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
 
        coex_dm->reason = reason;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): reason = %d\n", __func__,
+               reason);
+
        /* update wifi_link_info_ext variable */
        rtw_coex_update_wl_link_info(rtwdev, reason);
 
        rtw_coex_monitor_bt_enable(rtwdev);
 
-       if (coex->stop_dm)
+       if (coex->manual_control) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], return for Manual CTRL!!\n");
+               return;
+       }
+
+       if (coex->stop_dm) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], return for Stop Coex DM!!\n");
                return;
+       }
 
-       if (coex_stat->wl_under_ips)
+       if (coex_stat->wl_under_ips) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], return for wifi is under IPS!!\n");
                return;
+       }
 
        if (coex->freeze && coex_dm->reason == COEX_RSN_BTINFO &&
-           !coex_stat->bt_setup_link)
+           !coex_stat->bt_setup_link) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], return for coex_freeze!!\n");
                return;
+       }
 
        coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++;
        coex->freerun = false;
@@ -1976,10 +2478,16 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
                goto exit;
        }
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], WiFi is single-port 2G!!\n");
        coex_stat->wl_coex_mode = COEX_WLINK_2G1PORT;
-       rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
+
        if (coex_stat->bt_disabled) {
-               rtw_coex_action_wl_only(rtwdev);
+               if (coex_stat->wl_connected && rf4ce_en)
+                       rtw_coex_action_rf4ce(rtwdev);
+               else if (!coex_stat->wl_connected)
+                       rtw_coex_action_wl_not_connected(rtwdev);
+               else
+                       rtw_coex_action_wl_only(rtwdev);
                goto exit;
        }
 
@@ -2010,18 +2518,21 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
                goto exit;
        }
 
-       if (coex_stat->wl_linkscan_proc) {
+       if (coex_stat->wl_linkscan_proc && !coex->freerun) {
                rtw_coex_action_wl_linkscan(rtwdev);
                goto exit;
        }
 
-       if (coex_stat->wl_connected)
+       if (coex_stat->wl_connected) {
                rtw_coex_action_wl_connected(rtwdev);
-       else
+               goto exit;
+       } else {
                rtw_coex_action_wl_not_connected(rtwdev);
+               goto exit;
+       }
 
 exit:
-       rtw_coex_set_gnt_fix(rtwdev);
+       rtw_coex_gnt_workaround(rtwdev, false, coex_stat->wl_coex_mode);
        rtw_coex_limited_wl(rtwdev);
 }
 
@@ -2048,14 +2559,26 @@ static void rtw_coex_init_coex_var(struct rtw_dev *rtwdev)
                coex_dm->wl_rssi_state[i] = COEX_RSSI_STATE_LOW;
 
        coex_stat->wl_coex_mode = COEX_WLINK_MAX;
+       coex_stat->wl_rx_rate = DESC_RATE5_5M;
+       coex_stat->wl_rts_rx_rate = DESC_RATE5_5M;
 }
 
 static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
 {
        struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
 
        rtw_coex_init_coex_var(rtwdev);
+
+       coex_stat->kt_ver = u8_get_bits(rtw_read8(rtwdev, 0xf1), GENMASK(7, 4));
+
        rtw_coex_monitor_bt_enable(rtwdev);
+       rtw_coex_wl_slot_extend(rtwdev, coex_stat->wl_slot_extend);
+
+       rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
+
        rtw_coex_set_rfe_type(rtwdev);
        rtw_coex_set_init(rtwdev);
 
@@ -2073,21 +2596,24 @@ static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);
                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);
                coex->stop_dm = true;
+
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): RF Off\n",
+                       __func__);
        } else if (wifi_only) {
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WONLY);
-               rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN,
+               rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF,
                                    true);
                coex->stop_dm = true;
        } else {
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_INIT);
-               rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN,
+               rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF,
                                    true);
                coex->stop_dm = false;
                coex->freeze = true;
        }
 
        /* PTA parameter */
-       rtw_coex_table(rtwdev, 0);
+       rtw_coex_table(rtwdev, true, 1);
        rtw_coex_tdma(rtwdev, true, 0);
        rtw_coex_query_bt_info(rtwdev);
 }
@@ -2095,12 +2621,16 @@ static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
 void rtw_coex_power_on_setting(struct rtw_dev *rtwdev)
 {
        struct rtw_coex *coex = &rtwdev->coex;
+       u8 table_case = 1;
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
 
        coex->stop_dm = true;
        coex->wl_rf_off = false;
 
        /* enable BB, we can write 0x948 */
-       rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1));
+       rtw_write8_set(rtwdev, REG_SYS_FUNC_EN,
+                      BIT_FEN_BB_GLB_RST | BIT_FEN_BB_RSTB);
 
        rtw_coex_monitor_bt_enable(rtwdev);
        rtw_coex_set_rfe_type(rtwdev);
@@ -2108,8 +2638,10 @@ void rtw_coex_power_on_setting(struct rtw_dev *rtwdev)
        /* set antenna path to BT */
        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_POWERON);
 
+       rtw_coex_table(rtwdev, true, table_case);
        /* red x issue */
        rtw_write8(rtwdev, 0xff1a, 0x0);
+       rtw_coex_set_gnt_debug(rtwdev);
 }
 
 void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
@@ -2122,10 +2654,12 @@ void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type)
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
 
-       if (coex->stop_dm)
+       if (coex->manual_control || coex->stop_dm)
                return;
 
        if (type == COEX_IPS_ENTER) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], IPS ENTER notify\n");
+
                coex_stat->wl_under_ips = true;
 
                /* for lps off */
@@ -2134,11 +2668,11 @@ void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type)
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);
                rtw_coex_action_coex_all_off(rtwdev);
        } else if (type == COEX_IPS_LEAVE) {
-               rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], IPS LEAVE notify\n");
 
+               rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
                /* run init hw config (exclude wifi only) */
                __rtw_coex_init_hw_config(rtwdev, false);
-               /* sw all off */
 
                coex_stat->wl_under_ips = false;
        }
@@ -2149,10 +2683,12 @@ void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type)
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
 
-       if (coex->stop_dm)
+       if (coex->manual_control || coex->stop_dm)
                return;
 
        if (type == COEX_LPS_ENABLE) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], LPS ENABLE notify\n");
+
                coex_stat->wl_under_lps = true;
 
                if (coex_stat->wl_force_lps_ctrl) {
@@ -2161,10 +2697,13 @@ void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type)
                } else {
                        /* for native ps */
                        rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false);
+                       rtw_coex_write_scbd(rtwdev, COEX_SCBD_WLBUSY, false);
 
                        rtw_coex_run_coex(rtwdev, COEX_RSN_LPS);
                }
        } else if (type == COEX_LPS_DISABLE) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], LPS DISABLE notify\n");
+
                coex_stat->wl_under_lps = false;
 
                /* for lps off */
@@ -2172,6 +2711,8 @@ void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type)
 
                if (!coex_stat->wl_force_lps_ctrl)
                        rtw_coex_query_bt_info(rtwdev);
+
+               rtw_coex_run_coex(rtwdev, COEX_RSN_LPS);
        }
 }
 
@@ -2180,25 +2721,34 @@ void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type)
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
 
-       if (coex->stop_dm)
+       if (coex->manual_control || coex->stop_dm)
                return;
 
        coex->freeze = false;
-
-       if (type != COEX_SCAN_FINISH)
-               rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN |
-                                   COEX_SCBD_ONOFF, true);
+       rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
 
        if (type == COEX_SCAN_START_5G) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], SCAN START notify (5G)\n");
+
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
                rtw_coex_run_coex(rtwdev, COEX_RSN_5GSCANSTART);
        } else if ((type == COEX_SCAN_START_2G) || (type == COEX_SCAN_START)) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], SCAN START notify (2G)\n");
+
                coex_stat->wl_hi_pri_task2 = true;
 
                /* Force antenna setup for no scan result issue */
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
                rtw_coex_run_coex(rtwdev, COEX_RSN_2GSCANSTART);
        } else {
+               coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] = 30; /* To do */
+
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n",
+                       coex_stat->cnt_wl[COEX_CNT_WL_SCANAP]);
+
                coex_stat->wl_hi_pri_task2 = false;
                rtw_coex_run_coex(rtwdev, COEX_RSN_SCANFINISH);
        }
@@ -2208,9 +2758,20 @@ void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type)
 {
        struct rtw_coex *coex = &rtwdev->coex;
 
-       if (coex->stop_dm)
+       if (coex->manual_control || coex->stop_dm)
                return;
 
+       if (type == COEX_SWITCH_TO_5G) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): TO_5G\n",
+                       __func__);
+       } else if (type == COEX_SWITCH_TO_24G_NOFORSCAN) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], %s(): TO_24G_NOFORSCAN\n", __func__);
+       } else {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): TO_2G\n",
+                       __func__);
+       }
+
        if (type == COEX_SWITCH_TO_5G)
                rtw_coex_run_coex(rtwdev, COEX_RSN_5GSWITCHBAND);
        else if (type == COEX_SWITCH_TO_24G_NOFORSCAN)
@@ -2224,22 +2785,33 @@ void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type)
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
 
-       if (coex->stop_dm)
+       if (coex->manual_control || coex->stop_dm)
                return;
 
-       rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN |
-                           COEX_SCBD_ONOFF, true);
+       rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
 
        if (type == COEX_ASSOCIATE_5G_START) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G start\n",
+                       __func__);
+
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
                rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONSTART);
        } else if (type == COEX_ASSOCIATE_5G_FINISH) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G finish\n",
+                       __func__);
+
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
                rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONFINISH);
        } else if (type == COEX_ASSOCIATE_START) {
                coex_stat->wl_hi_pri_task1 = true;
+               coex_stat->wl_connecting = true;
                coex_stat->cnt_wl[COEX_CNT_WL_CONNPKT] = 2;
+               coex_stat->wl_connecting = true;
+               ieee80211_queue_delayed_work(rtwdev->hw,
+                                            &coex->wl_connecting_work, 2 * HZ);
 
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G start\n",
+                       __func__);
                /* Force antenna setup for no scan result issue */
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
 
@@ -2254,7 +2826,10 @@ void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type)
        } else {
                coex_stat->wl_hi_pri_task1 = false;
                coex->freeze = false;
+               coex_stat->wl_connecting = false;
 
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G finish\n",
+                       __func__);
                rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONFINISH);
        }
 }
@@ -2263,17 +2838,22 @@ void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type)
 {
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
-       u8 para[6] = {0};
 
-       if (coex->stop_dm)
+       if (coex->manual_control || coex->stop_dm)
                return;
 
        if (type == COEX_MEDIA_CONNECT_5G) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G\n", __func__);
+
                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
 
                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
                rtw_coex_run_coex(rtwdev, COEX_RSN_5GMEDIA);
        } else if (type == COEX_MEDIA_CONNECT) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G\n", __func__);
+
+               coex_stat->wl_connecting = false;
+
                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
 
                /* Force antenna setup for no scan result issue */
@@ -2281,18 +2861,11 @@ void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type)
 
                /* Set CCK Rx high Pri */
                rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 1);
-
-               /* always enable 5ms extend if connect */
-               para[0] = COEX_H2C69_WL_LEAKAP;
-               para[1] = PARA1_H2C69_EN_5MS; /* enable 5ms extend */
-               rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
-               coex_stat->wl_slot_extend = true;
                rtw_coex_run_coex(rtwdev, COEX_RSN_2GMEDIA);
        } else {
-               rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false);
-
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): disconnect!!\n",
+                       __func__);
                rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 0);
-
                rtw_coex_run_coex(rtwdev, COEX_RSN_MEDIADISCON);
        }
 
@@ -2304,25 +2877,35 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
        struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_coex_stat *coex_stat = &coex->stat;
        struct rtw_chip_info *chip = rtwdev->chip;
-       unsigned long bt_relink_time;
+       struct rtw_coex_dm *coex_dm = &coex->dm;
+       u32 bt_relink_time;
        u8 i, rsp_source = 0, type;
        bool inq_page = false;
 
        rsp_source = buf[0] & 0xf;
        if (rsp_source >= COEX_BTINFO_SRC_MAX)
-               rsp_source = COEX_BTINFO_SRC_WL_FW;
+               return;
+       coex_stat->cnt_bt_info_c2h[rsp_source]++;
 
        if (rsp_source == COEX_BTINFO_SRC_BT_IQK) {
                coex_stat->bt_iqk_state = buf[1];
-               if (coex_stat->bt_iqk_state == 1)
+               if (coex_stat->bt_iqk_state == 0)
                        coex_stat->cnt_bt[COEX_CNT_BT_IQK]++;
                else if (coex_stat->bt_iqk_state == 2)
                        coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]++;
 
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], BT IQK by bt_info, data0 = 0x%02x\n",
+                       buf[1]);
+
                return;
        }
 
        if (rsp_source == COEX_BTINFO_SRC_BT_SCBD) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], BT Scoreboard change notify by WL FW c2h, 0xaa = 0x%02x, 0xab = 0x%02x\n",
+                       buf[1], buf[2]);
+
                rtw_coex_monitor_bt_enable(rtwdev);
                if (coex_stat->bt_disabled != coex_stat->bt_disabled_pre) {
                        coex_stat->bt_disabled_pre = coex_stat->bt_disabled;
@@ -2331,6 +2914,24 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                return;
        }
 
+       if (rsp_source == COEX_BTINFO_SRC_H2C60) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], H2C 0x60 content replied by WL FW: H2C_0x60 = [%02x %02x %02x %02x %02x]\n",
+                       buf[1], buf[2], buf[3], buf[4], buf[5]);
+
+               for (i = 1; i <= COEX_WL_TDMA_PARA_LENGTH; i++)
+                       coex_dm->fw_tdma_para[i - 1] = buf[i];
+               return;
+       }
+
+       if (rsp_source == COEX_BTINFO_SRC_WL_FW) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], bt_info reply by WL FW\n");
+
+               rtw_coex_update_bt_link_info(rtwdev);
+               return;
+       }
+
        if (rsp_source == COEX_BTINFO_SRC_BT_RSP ||
            rsp_source == COEX_BTINFO_SRC_BT_ACT) {
                if (coex_stat->bt_disabled) {
@@ -2339,30 +2940,36 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                        ieee80211_queue_delayed_work(rtwdev->hw,
                                                     &coex->bt_reenable_work,
                                                     15 * HZ);
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], BT enable detected by bt_info\n");
                }
        }
 
-       for (i = 0; i < length; i++) {
-               if (i < COEX_BTINFO_LENGTH_MAX)
-                       coex_stat->bt_info_c2h[rsp_source][i] = buf[i];
-               else
-                       break;
-       }
+       if (length != COEX_BTINFO_LENGTH) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], Bt_info length = %d invalid!!\n", length);
 
-       if (rsp_source == COEX_BTINFO_SRC_WL_FW) {
-               rtw_coex_update_bt_link_info(rtwdev);
-               rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
                return;
        }
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex], Bt_info[%d], len=%d, data=[%02x %02x %02x %02x %02x %02x]\n",
+               buf[0], length, buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+       for (i = 0; i < COEX_BTINFO_LENGTH; i++)
+               coex_stat->bt_info_c2h[rsp_source][i] = buf[i];
+
        /* get the same info from bt, skip it */
        if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 &&
            coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 &&
            coex_stat->bt_info_c2h[rsp_source][3] == coex_stat->bt_info_hb0 &&
            coex_stat->bt_info_c2h[rsp_source][4] == coex_stat->bt_info_hb1 &&
            coex_stat->bt_info_c2h[rsp_source][5] == coex_stat->bt_info_hb2 &&
-           coex_stat->bt_info_c2h[rsp_source][6] == coex_stat->bt_info_hb3)
+           coex_stat->bt_info_c2h[rsp_source][6] == coex_stat->bt_info_hb3) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], Return because Btinfo duplicate!!\n");
                return;
+       }
 
        coex_stat->bt_info_lb2 = coex_stat->bt_info_c2h[rsp_source][1];
        coex_stat->bt_info_lb3 = coex_stat->bt_info_c2h[rsp_source][2];
@@ -2388,6 +2995,40 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                                                     4 * HZ);
        }
        coex_stat->bt_acl_busy = ((coex_stat->bt_info_lb2 & BIT(3)) == BIT(3));
+       if (chip->ble_hid_profile_support) {
+               if (coex_stat->bt_info_lb2 & BIT(5)) {
+                       if (coex_stat->bt_info_hb1 & BIT(0)) {
+                               /*BLE HID*/
+                               coex_stat->bt_ble_hid_exist = true;
+                       } else {
+                               coex_stat->bt_ble_hid_exist = false;
+                       }
+                       coex_stat->bt_ble_exist = false;
+               } else if (coex_stat->bt_info_hb1 & BIT(0)) {
+                       /*RCU*/
+                       coex_stat->bt_ble_hid_exist = false;
+                       coex_stat->bt_ble_exist = true;
+               } else {
+                       coex_stat->bt_ble_hid_exist = false;
+                       coex_stat->bt_ble_exist = false;
+               }
+       } else {
+               if (coex_stat->bt_info_hb1 & BIT(0)) {
+                       if (coex_stat->bt_hid_slot == 1 &&
+                           coex_stat->hi_pri_rx + 100 < coex_stat->hi_pri_tx &&
+                           coex_stat->hi_pri_rx < 100) {
+                               coex_stat->bt_ble_hid_exist = true;
+                               coex_stat->bt_ble_exist = false;
+                       } else {
+                               coex_stat->bt_ble_hid_exist = false;
+                               coex_stat->bt_ble_exist = true;
+                       }
+               } else {
+                       coex_stat->bt_ble_hid_exist = false;
+                       coex_stat->bt_ble_exist = false;
+               }
+       }
+
        coex_stat->cnt_bt[COEX_CNT_BT_RETRY] = coex_stat->bt_info_lb3 & 0xf;
        if (coex_stat->cnt_bt[COEX_CNT_BT_RETRY] >= 1)
                coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]++;
@@ -2398,22 +3039,13 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                coex_stat->cnt_bt[COEX_CNT_BT_INQ]++;
 
        coex_stat->bt_page = ((coex_stat->bt_info_lb3 & BIT(7)) == BIT(7));
-       if (coex_stat->bt_page) {
+       if (coex_stat->bt_page)
                coex_stat->cnt_bt[COEX_CNT_BT_PAGE]++;
-               if (coex_stat->wl_linkscan_proc ||
-                   coex_stat->wl_hi_pri_task1 ||
-                   coex_stat->wl_hi_pri_task2 || coex_stat->wl_gl_busy)
-                       rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, true);
-               else
-                       rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);
-       } else {
-               rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);
-       }
 
        /* unit: % (value-100 to translate to unit: dBm in coex info) */
        if (chip->bt_rssi_type == COEX_BTRSSI_RATIO) {
                coex_stat->bt_rssi = coex_stat->bt_info_hb0 * 2 + 10;
-       } else { /* original unit: dbm -> unit: % ->  value-100 in coex info */
+       } else {
                if (coex_stat->bt_info_hb0 <= 127)
                        coex_stat->bt_rssi = 100;
                else if (256 - coex_stat->bt_info_hb0 <= 100)
@@ -2422,7 +3054,6 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                        coex_stat->bt_rssi = 0;
        }
 
-       coex_stat->bt_ble_exist = ((coex_stat->bt_info_hb1 & BIT(0)) == BIT(0));
        if (coex_stat->bt_info_hb1 & BIT(1))
                coex_stat->cnt_bt[COEX_CNT_BT_REINIT]++;
 
@@ -2432,11 +3063,14 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                if (coex_stat->bt_reenable)
                        bt_relink_time = 6 * HZ;
                else
-                       bt_relink_time = 2 * HZ;
+                       bt_relink_time = 1 * HZ;
 
                ieee80211_queue_delayed_work(rtwdev->hw,
                                             &coex->bt_relink_work,
                                             bt_relink_time);
+
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], Re-Link start in BT info!!\n");
        }
 
        if (coex_stat->bt_info_hb1 & BIT(3))
@@ -2448,8 +3082,21 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH]++;
 
        coex_stat->bt_multi_link = ((coex_stat->bt_info_hb1 & BIT(7)) == BIT(7));
+       /* for multi_link = 0 but bt pkt remain exist */
+       /* Use PS-TDMA to protect WL RX */
+       if (!coex_stat->bt_multi_link && coex_stat->bt_multi_link_pre) {
+               coex_stat->bt_multi_link_remain = true;
+               ieee80211_queue_delayed_work(rtwdev->hw,
+                                            &coex->bt_multi_link_remain_work,
+                                            3 * HZ);
+       }
+       coex_stat->bt_multi_link_pre = coex_stat->bt_multi_link;
+
        /* resend wifi info to bt, it is reset and lost the info */
-       if ((coex_stat->bt_info_hb1 & BIT(1))) {
+       if (coex_stat->bt_info_hb1 & BIT(1)) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], BT Re-init, send wifi BW & Chnl to BT!!\n");
+
                if (coex_stat->wl_connected)
                        type = COEX_MEDIA_CONNECT;
                else
@@ -2459,8 +3106,11 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
 
        /* if ignore_wlan_act && not set_up_link */
        if ((coex_stat->bt_info_hb1 & BIT(3)) &&
-           (!(coex_stat->bt_info_hb1 & BIT(2))))
+           (!(coex_stat->bt_info_hb1 & BIT(2)))) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX,
+                       "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n");
                rtw_coex_ignore_wlan_act(rtwdev, false);
+       }
 
        coex_stat->bt_opp_exist = ((coex_stat->bt_info_hb2 & BIT(0)) == BIT(0));
        if (coex_stat->bt_info_hb2 & BIT(1))
@@ -2472,7 +3122,7 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
        coex_stat->bt_hid_pair_num = (coex_stat->bt_info_hb2 & 0xc0) >> 6;
        if (coex_stat->bt_hid_pair_num > 0 && coex_stat->bt_hid_slot >= 2)
                coex_stat->bt_418_hid_exist = true;
-       else if (coex_stat->bt_hid_pair_num == 0)
+       else if (coex_stat->bt_hid_pair_num == 0 || coex_stat->bt_hid_slot == 1)
                coex_stat->bt_418_hid_exist = false;
 
        if ((coex_stat->bt_info_lb2 & 0x49) == 0x49)
@@ -2493,6 +3143,9 @@ void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
        u8 val;
        int i;
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex], WiFi Fw Dbg info = %8ph (len = %d)\n",
+               buf, length);
        if (WARN(length < 8, "invalid wl info c2h length\n"))
                return;
 
@@ -2504,7 +3157,7 @@ void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                if (buf[i] >= val)
                        coex_stat->wl_fw_dbg_info[i] = buf[i] - val;
                else
-                       coex_stat->wl_fw_dbg_info[i] = val - buf[i];
+                       coex_stat->wl_fw_dbg_info[i] = 255 - val + buf[i];
 
                coex_stat->wl_fw_dbg_info_pre[i] = buf[i];
        }
@@ -2514,13 +3167,8 @@ void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
        rtw_coex_wl_ccklock_detect(rtwdev);
 }
 
-void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev)
+void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type)
 {
-       struct rtw_coex *coex = &rtwdev->coex;
-
-       if (coex->stop_dm)
-               return;
-
        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
 }
 
@@ -2585,6 +3233,41 @@ void rtw_coex_bt_remain_work(struct work_struct *work)
        mutex_unlock(&rtwdev->mutex);
 }
 
+void rtw_coex_wl_connecting_work(struct work_struct *work)
+{
+       struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
+                                             coex.wl_connecting_work.work);
+       struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
+
+       mutex_lock(&rtwdev->mutex);
+       coex_stat->wl_connecting = false;
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], WL connecting stop!!\n");
+       rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
+       mutex_unlock(&rtwdev->mutex);
+}
+
+void rtw_coex_bt_multi_link_remain_work(struct work_struct *work)
+{
+       struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
+               coex.bt_multi_link_remain_work.work);
+       struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
+
+       mutex_lock(&rtwdev->mutex);
+       coex_stat->bt_multi_link_remain = false;
+       mutex_unlock(&rtwdev->mutex);
+}
+
+void rtw_coex_wl_ccklock_work(struct work_struct *work)
+{
+       struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
+                                             coex.wl_ccklock_work.work);
+       struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
+
+       mutex_lock(&rtwdev->mutex);
+       coex_stat->wl_cck_lock = false;
+       mutex_unlock(&rtwdev->mutex);
+}
+
 #ifdef CONFIG_RTW88_DEBUGFS
 #define INFO_SIZE      80
 
@@ -2628,6 +3311,81 @@ static const char *rtw_coex_get_reason_string(u8 reason)
        }
 }
 
+static u8 rtw_coex_get_table_index(struct rtw_dev *rtwdev, u32 wl_reg_6c0,
+                                  u32 wl_reg_6c4)
+{
+       struct rtw_chip_info *chip = rtwdev->chip;
+       struct rtw_efuse *efuse = &rtwdev->efuse;
+       u8 ans = 0xFF;
+       u8 n, i;
+       u32 load_bt_val;
+       u32 load_wl_val;
+       bool share_ant = efuse->share_ant;
+
+       if (share_ant)
+               n = chip->table_sant_num;
+       else
+               n = chip->table_nsant_num;
+
+       for (i = 0; i < n; i++) {
+               if (share_ant) {
+                       load_bt_val = chip->table_sant[i].bt;
+                       load_wl_val = chip->table_sant[i].wl;
+               } else {
+                       load_bt_val = chip->table_nsant[i].bt;
+                       load_wl_val = chip->table_nsant[i].wl;
+               }
+
+               if (wl_reg_6c0 == load_bt_val &&
+                   wl_reg_6c4 == load_wl_val) {
+                       ans = i;
+                       if (!share_ant)
+                               ans += 100;
+                       break;
+               }
+       }
+
+       return ans;
+}
+
+static u8 rtw_coex_get_tdma_index(struct rtw_dev *rtwdev, u8 *tdma_para)
+{
+       struct rtw_efuse *efuse = &rtwdev->efuse;
+       struct rtw_chip_info *chip = rtwdev->chip;
+       u8 ans = 0xFF;
+       u8 n, i, j;
+       u8 load_cur_tab_val;
+       bool valid = false;
+       bool share_ant = efuse->share_ant;
+
+       if (share_ant)
+               n = chip->tdma_sant_num;
+       else
+               n = chip->tdma_nsant_num;
+
+       for (i = 0; i < n; i++) {
+               valid = false;
+               for (j = 0; j < 5; j++) {
+                       if (share_ant)
+                               load_cur_tab_val = chip->tdma_sant[i].para[j];
+                       else
+                               load_cur_tab_val = chip->tdma_nsant[i].para[j];
+
+                       if (*(tdma_para + j) != load_cur_tab_val)
+                               break;
+
+                       if (j == 4)
+                               valid = true;
+               }
+               if (valid) {
+                       ans = i;
+                       break;
+               }
+       }
+
+       return ans;
+}
+
 static int rtw_coex_addr_info(struct rtw_dev *rtwdev,
                              const struct rtw_reg_domain *reg,
                              char addr_info[], int n)
@@ -2873,6 +3631,19 @@ static void rtw_coex_vif_stat_iter(void *data, u8 *mac,
                                &sta_iter_data);
 }
 
+#define case_WLINK(src) \
+       case COEX_WLINK_##src: return #src
+
+static const char *rtw_coex_get_wl_coex_mode(u8 coex_wl_link_mode)
+{
+       switch (coex_wl_link_mode) {
+       case_WLINK(2G1PORT);
+       case_WLINK(5G);
+       default:
+               return "Unknown";
+       }
+}
+
 void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
 {
        struct rtw_chip_info *chip = rtwdev->chip;
@@ -2894,14 +3665,23 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
 
        score_board_BW = rtw_coex_read_scbd(rtwdev);
        score_board_WB = coex_stat->score_board;
-       wl_reg_6c0 = rtw_read32(rtwdev, 0x6c0);
-       wl_reg_6c4 = rtw_read32(rtwdev, 0x6c4);
-       wl_reg_6c8 = rtw_read32(rtwdev, 0x6c8);
-       wl_reg_6cc = rtw_read32(rtwdev, 0x6cc);
-       wl_reg_778 = rtw_read32(rtwdev, 0x778);
-       bt_hi_pri = rtw_read32(rtwdev, 0x770);
-       bt_lo_pri = rtw_read32(rtwdev, 0x774);
-       rtw_write8(rtwdev, 0x76e, 0xc);
+       wl_reg_6c0 = rtw_read32(rtwdev, REG_BT_COEX_TABLE0);
+       wl_reg_6c4 = rtw_read32(rtwdev, REG_BT_COEX_TABLE1);
+       wl_reg_6c8 = rtw_read32(rtwdev, REG_BT_COEX_BRK_TABLE);
+       wl_reg_6cc = rtw_read32(rtwdev, REG_BT_COEX_TABLE_H);
+       wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL);
+
+       bt_hi_pri = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS);
+       bt_lo_pri = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS_1);
+       rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL,
+                  BIT_R_GRANTALL_WLMASK | BIT_STATIS_BT_EN);
+
+       coex_stat->hi_pri_tx = FIELD_GET(MASKLWORD, bt_hi_pri);
+       coex_stat->hi_pri_rx = FIELD_GET(MASKHWORD, bt_hi_pri);
+
+       coex_stat->lo_pri_tx = FIELD_GET(MASKLWORD, bt_lo_pri);
+       coex_stat->lo_pri_rx = FIELD_GET(MASKHWORD, bt_lo_pri);
+
        sys_lte = rtw_read8(rtwdev, 0x73);
        lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38);
        bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54);
@@ -2919,9 +3699,24 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
                        coex_stat->bt_mailbox_reply = true;
        }
 
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
        seq_printf(m, "**********************************************\n");
        seq_printf(m, "\t\tBT Coexist info %x\n", chip->id);
        seq_printf(m, "**********************************************\n");
+
+       if (coex->manual_control) {
+               seq_puts(m, "============[Under Manual Control]============\n");
+               seq_puts(m, "==========================================\n");
+
+       } else if (coex->stop_dm) {
+               seq_puts(m, "============[Coex is STOPPED]============\n");
+               seq_puts(m, "==========================================\n");
+
+       } else if (coex->freeze) {
+               seq_puts(m, "============[coex_freeze]============\n");
+               seq_puts(m, "==========================================\n");
+       }
+
        seq_printf(m, "%-40s = %s/ %d\n",
                   "Mech/ RFE",
                   efuse->share_ant ? "Shared" : "Non-Shared",
@@ -2938,15 +3733,17 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
                   coex_stat->bt_slave ? "Slave" : "Master",
                   coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH],
                   coex_dm->ignore_wl_act);
-       seq_printf(m, "%-40s = %u.%u/ 0x%x/ %c\n",
-                  "WL FW/ BT FW/ KT",
+       seq_printf(m, "%-40s = %u.%u/ 0x%x/ 0x%x/ %c\n",
+                  "WL FW/ BT FW/ BT FW Desired/ KT",
                   fw->version, fw->sub_version,
-                  coex_stat->patch_ver, coex_stat->kt_ver + 65);
+                  coex_stat->patch_ver,
+                  chip->wl_fw_desired_ver, coex_stat->kt_ver + 65);
        seq_printf(m, "%-40s = %u/ %u/ %u/ ch-(%u)\n",
                   "AFH Map",
                   coex_dm->wl_ch_info[0], coex_dm->wl_ch_info[1],
                   coex_dm->wl_ch_info[2], hal->current_channel);
 
+       rtw_debugfs_get_simple_phy_info(m);
        seq_printf(m, "**********************************************\n");
        seq_printf(m, "\t\tBT Status\n");
        seq_printf(m, "**********************************************\n");
@@ -2965,6 +3762,7 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
                   coex_stat->bt_hid_exist ?
                   (coex_stat->bt_ble_exist ? "HID(RCU)," :
                    coex_stat->bt_hid_slot >= 2 ? "HID(4/18)" :
+                   coex_stat->bt_ble_hid_exist ? "HID(BLE)" :
                    "HID(2/18),") : "",
                   coex_stat->bt_pan_exist ? coex_stat->bt_opp_exist ?
                   "OPP," : "PAN," : "",
@@ -2989,8 +3787,8 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
                   score_board_WB, score_board_BW);
        seq_printf(m, "%-40s = %u/%u, %u/%u\n",
                   "Hi-Pri TX/RX, Lo-Pri TX/RX",
-                  bt_hi_pri & 0xffff, bt_hi_pri >> 16,
-                  bt_lo_pri & 0xffff, bt_lo_pri >> 16);
+                  coex_stat->hi_pri_tx, coex_stat->hi_pri_rx,
+                  coex_stat->lo_pri_tx, coex_stat->lo_pri_rx);
        for (i = 0; i < COEX_BTINFO_SRC_BT_IQK; i++)
                seq_printf(m, "%-40s = %7ph\n",
                           rtw_coex_get_bt_info_src_string(i),
@@ -3015,20 +3813,45 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
        vif_iter_data.file = m;
        rtw_iterate_vifs_atomic(rtwdev, rtw_coex_vif_stat_iter, &vif_iter_data);
 
-       seq_printf(m, "**********************************************\n");
-       seq_printf(m, "\t\tMechanism\n");
-       seq_printf(m, "**********************************************\n");
-       seq_printf(m, "%-40s = %5ph (case-%d)\n",
-                  "TDMA",
-                  coex_dm->ps_tdma_para, coex_dm->cur_ps_tdma);
-       seq_printf(m, "%-40s = %d\n",
-                  "Timer base", coex_stat->tdma_timer_base);
-       seq_printf(m, "%-40s = %d/ 0x%08x/ 0x%08x/ 0x%08x\n",
+       if (coex->manual_control) {
+               seq_printf(m, "**********************************************\n");
+               seq_printf(m, "\t\tMechanism (Under Manual)\n");
+               seq_printf(m, "**********************************************\n");
+               seq_printf(m, "%-40s = %5ph (%d)\n",
+                          "TDMA Now",
+                          coex_dm->fw_tdma_para,
+                          rtw_coex_get_tdma_index(rtwdev,
+                                                  &coex_dm->fw_tdma_para[0]));
+       } else {
+               seq_printf(m, "**********************************************\n");
+               seq_printf(m, "\t\tMechanism\n");
+               seq_printf(m, "**********************************************\n");
+               seq_printf(m, "%-40s = %5ph (case-%d)\n",
+                          "TDMA",
+                          coex_dm->ps_tdma_para, coex_dm->cur_ps_tdma);
+       }
+       seq_printf(m, "%-40s = %s/ %s/ %d\n",
+                  "Coex Mode/Free Run/Timer base",
+                  rtw_coex_get_wl_coex_mode(coex_stat->wl_coex_mode),
+                  coex->freerun ? "Yes" : "No",
+                  coex_stat->tdma_timer_base);
+       seq_printf(m, "%-40s = %d(%d)/ 0x%08x/ 0x%08x/ 0x%08x\n",
                   "Table/ 0x6c0/ 0x6c4/ 0x6c8",
-                  coex_dm->cur_table, wl_reg_6c0, wl_reg_6c4, wl_reg_6c8);
-       seq_printf(m, "%-40s = 0x%08x/ 0x%08x/ reason (%s)\n",
-                  "0x778/ 0x6cc/ Reason",
-                  wl_reg_778, wl_reg_6cc, rtw_coex_get_reason_string(reason));
+                  coex_dm->cur_table,
+                  rtw_coex_get_table_index(rtwdev, wl_reg_6c0, wl_reg_6c4),
+                  wl_reg_6c0, wl_reg_6c4, wl_reg_6c8);
+       seq_printf(m, "%-40s = 0x%08x/ 0x%08x/ %d/ reason (%s)\n",
+                  "0x778/ 0x6cc/ Run Count/ Reason",
+                  wl_reg_778, wl_reg_6cc,
+                  coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN],
+                  rtw_coex_get_reason_string(reason));
+       seq_printf(m, "%-40s = %3ph\n",
+                  "AFH Map to BT",
+                  coex_dm->wl_ch_info);
+       seq_printf(m, "%-40s = %s/ %d\n",
+                  "AntDiv/ BtCtrlLPS/ g_busy",
+                  coex_stat->wl_force_lps_ctrl ? "On" : "Off",
+                  coex_stat->wl_gl_busy);
        seq_printf(m, "%-40s = %u/ %u/ %u/ %u/ %u\n",
                   "Null All/ Retry/ Ack/ BT Empty/ BT Late",
                   coex_stat->wl_fw_dbg_info[1], coex_stat->wl_fw_dbg_info[2],
@@ -3040,6 +3863,12 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
                   coex_stat->wl_fw_dbg_info[7],
                   coex_stat->wl_slot_extend ? "Yes" : "No",
                   coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]);
+       seq_printf(m, "%-40s = %d/ %d/ %s/ %d\n",
+                  "WL_TxPw/ BT_TxPw/ WL_Rx/ BT_LNA_Lvl",
+                  coex_dm->cur_wl_pwr_lvl,
+                  coex_dm->cur_bt_pwr_lvl,
+                  coex_dm->cur_wl_rx_low_gain_en ? "On" : "Off",
+                  coex_dm->cur_bt_lna_lvl);
 
        seq_printf(m, "**********************************************\n");
        seq_printf(m, "\t\tHW setting\n");
@@ -3074,5 +3903,22 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
                   coex_stat->wl_noisy_level);
 
        rtw_coex_set_coexinfo_hw(rtwdev, m);
+       seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n",
+                  "EVM A/ EVM B/ SNR A/ SNR B",
+                  -dm_info->rx_evm_dbm[RF_PATH_A],
+                  -dm_info->rx_evm_dbm[RF_PATH_B],
+                  -dm_info->rx_snr[RF_PATH_A],
+                  -dm_info->rx_snr[RF_PATH_B]);
+       seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n",
+                  "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA",
+                  dm_info->cck_cca_cnt, dm_info->cck_fa_cnt,
+                  dm_info->ofdm_cca_cnt, dm_info->ofdm_fa_cnt);
+       seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n", "CRC OK CCK/11g/11n/11ac",
+                  dm_info->cck_ok_cnt, dm_info->ofdm_ok_cnt,
+                  dm_info->ht_ok_cnt, dm_info->vht_ok_cnt);
+       seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n", "CRC Err CCK/11g/11n/11ac",
+                  dm_info->cck_err_cnt, dm_info->ofdm_err_cnt,
+                  dm_info->ht_err_cnt, dm_info->vht_err_cnt);
+
 }
 #endif /* CONFIG_RTW88_DEBUGFS */
index 44720fd..8ab9852 100644 (file)
@@ -5,12 +5,7 @@
 #ifndef __RTW_COEX_H__
 #define __RTW_COEX_H__
 
-/* BT profile map bit definition */
-#define BPM_HFP                BIT(0)
-#define BPM_HID                BIT(1)
-#define BPM_A2DP               BIT(2)
-#define BPM_PAN                BIT(3)
-
+#define COEX_CCK_2     0x1
 #define COEX_RESP_ACK_BY_WL_FW 0x1
 #define COEX_REQUEST_TIMEOUT   msecs_to_jiffies(10)
 
 #define COEX_H2C69_TDMA_SLOT   0xb
 #define PARA1_H2C69_TDMA_4SLOT 0xc1
 #define PARA1_H2C69_TDMA_2SLOT 0x1
+#define PARA1_H2C69_TBTT_TIMES GENMASK(5, 0)
+#define PARA1_H2C69_TBTT_DIV100        BIT(7)
+
+#define COEX_H2C69_TOGGLE_TABLE_A 0xd
+#define COEX_H2C69_TOGGLE_TABLE_B 0x7
 
 #define TDMA_4SLOT     BIT(8)
 
+#define TDMA_TIMER_TYPE_2SLOT 0
+#define TDMA_TIMER_TYPE_4SLOT 3
+
 #define COEX_RSSI_STEP         4
+
 #define COEX_RSSI_HIGH(rssi) \
        ({ typeof(rssi) __rssi__ = rssi; \
           (__rssi__ == COEX_RSSI_STATE_HIGH || \
@@ -146,6 +150,25 @@ enum coex_algorithm {
        COEX_ALGO_MAX
 };
 
+enum coex_bt_profile {
+       BPM_NOPROFILE           = 0,
+       BPM_HFP                 = BIT(0),
+       BPM_HID                 = BIT(1),
+       BPM_A2DP                = BIT(2),
+       BPM_PAN                 = BIT(3),
+       BPM_HID_HFP             = BPM_HID | BPM_HFP,
+       BPM_A2DP_HFP            = BPM_A2DP | BPM_HFP,
+       BPM_A2DP_HID            = BPM_A2DP | BPM_HID,
+       BPM_A2DP_HID_HFP        = BPM_A2DP | BPM_HID | BPM_HFP,
+       BPM_PAN_HFP             = BPM_PAN | BPM_HFP,
+       BPM_PAN_HID             = BPM_PAN | BPM_HID,
+       BPM_PAN_HID_HFP         = BPM_PAN | BPM_HID | BPM_HFP,
+       BPM_PAN_A2DP            = BPM_PAN | BPM_A2DP,
+       BPM_PAN_A2DP_HFP        = BPM_PAN | BPM_A2DP | BPM_HFP,
+       BPM_PAN_A2DP_HID        = BPM_PAN | BPM_A2DP | BPM_HID,
+       BPM_PAN_A2DP_HID_HFP    = BPM_PAN | BPM_A2DP | BPM_HID | BPM_HFP,
+};
+
 enum coex_wl_link_mode {
        COEX_WLINK_2G1PORT      = 0x0,
        COEX_WLINK_5G           = 0x3,
@@ -365,19 +388,21 @@ void rtw_coex_bt_reenable_work(struct work_struct *work);
 void rtw_coex_defreeze_work(struct work_struct *work);
 void rtw_coex_wl_remain_work(struct work_struct *work);
 void rtw_coex_bt_remain_work(struct work_struct *work);
+void rtw_coex_wl_connecting_work(struct work_struct *work);
+void rtw_coex_bt_multi_link_remain_work(struct work_struct *work);
+void rtw_coex_wl_ccklock_work(struct work_struct *work);
 
 void rtw_coex_power_on_setting(struct rtw_dev *rtwdev);
 void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only);
 void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type);
 void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type);
 void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type);
-void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 action);
-void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 status);
-void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 len);
+void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type);
+void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type);
+void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
 void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
 void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type);
-void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev);
-
+void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type);
 void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m);
 
 #endif
index 3852c4f..3344ac9 100644 (file)
@@ -617,6 +617,29 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v)
        return 0;
 }
 
+void rtw_debugfs_get_simple_phy_info(struct seq_file *m)
+{
+       struct rtw_debugfs_priv *debugfs_priv = m->private;
+       struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
+       struct rtw_hal *hal = &rtwdev->hal;
+       struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+       struct rtw_traffic_stats *stats = &rtwdev->stats;
+
+       seq_printf(m, "%-40s = %ddBm/ %d\n", "RSSI/ STA Channel",
+                  dm_info->rssi[RF_PATH_A] - 100, hal->current_channel);
+
+       seq_printf(m, "TP {Tx, Rx} = {%u, %u}Mbps\n",
+                  stats->tx_throughput, stats->rx_throughput);
+
+       seq_puts(m, "[Tx Rate] = ");
+       rtw_print_rate(m, dm_info->tx_rate);
+       seq_printf(m, "(0x%x)\n", dm_info->tx_rate);
+
+       seq_puts(m, "[Rx Rate] = ");
+       rtw_print_rate(m, dm_info->curr_rx_rate);
+       seq_printf(m, "(0x%x)\n", dm_info->curr_rx_rate);
+}
+
 static int rtw_debugfs_get_phy_info(struct seq_file *m, void *v)
 {
        struct rtw_debugfs_priv *debugfs_priv = m->private;
@@ -775,7 +798,7 @@ static ssize_t rtw_debugfs_set_coex_enable(struct file *filp,
        }
 
        mutex_lock(&rtwdev->mutex);
-       coex->stop_dm = enable == 0;
+       coex->manual_control = enable == 0;
        mutex_unlock(&rtwdev->mutex);
 
        return count;
@@ -788,7 +811,7 @@ static int rtw_debugfs_get_coex_enable(struct seq_file *m, void *v)
        struct rtw_coex *coex = &rtwdev->coex;
 
        seq_printf(m, "coex mechanism %s\n",
-                  coex->stop_dm ? "disabled" : "enabled");
+                  coex->manual_control ? "disabled" : "enabled");
 
        return 0;
 }
index a0f36f2..e16e0da 100644 (file)
@@ -26,6 +26,7 @@ enum rtw_debug_mask {
 #ifdef CONFIG_RTW88_DEBUGFS
 
 void rtw_debugfs_init(struct rtw_dev *rtwdev);
+void rtw_debugfs_get_simple_phy_info(struct seq_file *m);
 
 #else
 
index 042015b..3cd4675 100644 (file)
@@ -13,6 +13,7 @@
 #include "debug.h"
 #include "util.h"
 #include "wow.h"
+#include "ps.h"
 
 static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev,
                                      struct sk_buff *skb)
@@ -183,6 +184,9 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
        case C2H_BT_MP_INFO:
                rtw_coex_info_response(rtwdev, skb);
                break;
+       case C2H_WLAN_RFON:
+               complete(&rtwdev->lps_leave_check);
+               break;
        default:
                /* pass offset for further operation */
                *((u32 *)skb->cb) = pkt_offset;
@@ -628,7 +632,7 @@ void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable)
 
        SET_NLO_FUN_EN(h2c_pkt, enable);
        if (enable) {
-               if (rtw_fw_lps_deep_mode)
+               if (rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE)
                        SET_NLO_PS_32K(h2c_pkt, enable);
                SET_NLO_IGNORE_SECURITY(h2c_pkt, enable);
                SET_NLO_LOC_NLO_INFO(h2c_pkt, loc_nlo);
index 0864454..39c905c 100644 (file)
@@ -31,6 +31,7 @@ enum rtw_c2h_cmd_id {
        C2H_RA_RPT = 0x0c,
        C2H_HW_FEATURE_REPORT = 0x19,
        C2H_WLAN_INFO = 0x27,
+       C2H_WLAN_RFON = 0x32,
        C2H_HW_FEATURE_DUMP = 0xfd,
        C2H_HALMAC = 0xff,
 };
@@ -72,6 +73,14 @@ enum rtw_fw_rf_type {
        FW_RF_MAX_TYPE = 0xF,
 };
 
+enum rtw_fw_feature {
+       FW_FEATURE_SIG = BIT(0),
+       FW_FEATURE_LPS_C2H = BIT(1),
+       FW_FEATURE_LCLK = BIT(2),
+       FW_FEATURE_PG = BIT(3),
+       FW_FEATURE_MAX = BIT(31),
+};
+
 struct rtw_coex_info_req {
        u8 seq;
        u8 op_code;
@@ -177,7 +186,7 @@ struct rtw_fw_hdr {
        u8 subversion;
        u8 subindex;
        __le32 rsvd;            /* 0x08 */
-       __le32 rsvd2;           /* 0x0C */
+       __le32 feature;         /* 0x0C */
        u8 month;               /* 0x10 */
        u8 day;
        u8 hour;
index c92fba2..1f1b639 100644 (file)
@@ -351,6 +351,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct rtw_dev *rtwdev = hw->priv;
        struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+       struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
        u32 config = 0;
 
        mutex_lock(&rtwdev->mutex);
@@ -381,6 +383,11 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
                config |= PORT_SET_BSSID;
        }
 
+       if (changed & BSS_CHANGED_BEACON_INT) {
+               if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)
+                       coex_stat->wl_beacon_interval = conf->beacon_int;
+       }
+
        if (changed & BSS_CHANGED_BEACON)
                rtw_fw_download_rsvd_page(rtwdev);
 
@@ -519,7 +526,7 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        }
 
        /* download new cam settings for PG to backup */
-       if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
+       if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)
                rtw_fw_download_rsvd_page(rtwdev);
 
 out:
index 565efd8..47969a6 100644 (file)
 #include "debug.h"
 #include "bf.h"
 
-unsigned int rtw_fw_lps_deep_mode;
-EXPORT_SYMBOL(rtw_fw_lps_deep_mode);
+bool rtw_disable_lps_deep_mode;
+EXPORT_SYMBOL(rtw_disable_lps_deep_mode);
 bool rtw_bf_support = true;
 unsigned int rtw_debug_mask;
 EXPORT_SYMBOL(rtw_debug_mask);
 
-module_param_named(lps_deep_mode, rtw_fw_lps_deep_mode, uint, 0644);
+module_param_named(disable_lps_deep, rtw_disable_lps_deep_mode, bool, 0644);
 module_param_named(support_bf, rtw_bf_support, bool, 0644);
 module_param_named(debug_mask, rtw_debug_mask, uint, 0644);
 
-MODULE_PARM_DESC(lps_deep_mode, "Deeper PS mode. If 0, deep PS is disabled");
+MODULE_PARM_DESC(disable_lps_deep, "Set Y to disable Deep PS");
 MODULE_PARM_DESC(support_bf, "Set Y to enable beamformee support");
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
 
@@ -196,7 +196,7 @@ static void rtw_watch_dog_work(struct work_struct *work)
                clear_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
 
        if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags))
-               rtw_coex_wl_status_change_notify(rtwdev);
+               rtw_coex_wl_status_change_notify(rtwdev, 0);
 
        if (stats->tx_cnt > RTW_LPS_THRESHOLD ||
            stats->rx_cnt > RTW_LPS_THRESHOLD)
@@ -1023,6 +1023,26 @@ static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev)
        return 0;
 }
 
+static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev,
+                                                      struct rtw_fw_state *fw)
+{
+       struct rtw_chip_info *chip = rtwdev->chip;
+
+       if (rtw_disable_lps_deep_mode || !chip->lps_deep_mode_supported ||
+           !fw->feature)
+               return LPS_DEEP_MODE_NONE;
+
+       if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_PG)) &&
+           (fw->feature & FW_FEATURE_PG))
+               return LPS_DEEP_MODE_PG;
+
+       if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_LCLK)) &&
+           (fw->feature & FW_FEATURE_LCLK))
+               return LPS_DEEP_MODE_LCLK;
+
+       return LPS_DEEP_MODE_NONE;
+}
+
 static int rtw_power_on(struct rtw_dev *rtwdev)
 {
        struct rtw_chip_info *chip = rtwdev->chip;
@@ -1097,6 +1117,9 @@ int rtw_core_start(struct rtw_dev *rtwdev)
 
        rtw_sec_enable_sec_engine(rtwdev);
 
+       rtwdev->lps_conf.deep_mode = rtw_update_lps_deep_mode(rtwdev, &rtwdev->fw);
+       rtwdev->lps_conf.wow_deep_mode = rtw_update_lps_deep_mode(rtwdev, &rtwdev->wow_fw);
+
        /* rcr reset after powered on */
        rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr);
 
@@ -1130,6 +1153,9 @@ void rtw_core_stop(struct rtw_dev *rtwdev)
        cancel_delayed_work_sync(&coex->defreeze_work);
        cancel_delayed_work_sync(&coex->wl_remain_work);
        cancel_delayed_work_sync(&coex->bt_remain_work);
+       cancel_delayed_work_sync(&coex->wl_connecting_work);
+       cancel_delayed_work_sync(&coex->bt_multi_link_remain_work);
+       cancel_delayed_work_sync(&coex->wl_ccklock_work);
 
        mutex_lock(&rtwdev->mutex);
 
@@ -1259,6 +1285,17 @@ static void rtw_unset_supported_band(struct ieee80211_hw *hw,
        kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
 }
 
+static void __update_firmware_feature(struct rtw_dev *rtwdev,
+                                     struct rtw_fw_state *fw)
+{
+       u32 feature;
+       const struct rtw_fw_hdr *fw_hdr =
+                               (const struct rtw_fw_hdr *)fw->firmware->data;
+
+       feature = le32_to_cpu(fw_hdr->feature);
+       fw->feature = feature & FW_FEATURE_SIG ? feature : 0;
+}
+
 static void __update_firmware_info(struct rtw_dev *rtwdev,
                                   struct rtw_fw_state *fw)
 {
@@ -1269,6 +1306,8 @@ static void __update_firmware_info(struct rtw_dev *rtwdev,
        fw->version = le16_to_cpu(fw_hdr->version);
        fw->sub_version = fw_hdr->subversion;
        fw->sub_index = fw_hdr->subindex;
+
+       __update_firmware_feature(rtwdev, fw);
 }
 
 static void __update_firmware_info_legacy(struct rtw_dev *rtwdev,
@@ -1622,6 +1661,10 @@ int rtw_core_init(struct rtw_dev *rtwdev)
        INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work);
        INIT_DELAYED_WORK(&coex->wl_remain_work, rtw_coex_wl_remain_work);
        INIT_DELAYED_WORK(&coex->bt_remain_work, rtw_coex_bt_remain_work);
+       INIT_DELAYED_WORK(&coex->wl_connecting_work, rtw_coex_wl_connecting_work);
+       INIT_DELAYED_WORK(&coex->bt_multi_link_remain_work,
+                         rtw_coex_bt_multi_link_remain_work);
+       INIT_DELAYED_WORK(&coex->wl_ccklock_work, rtw_coex_wl_ccklock_work);
        INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work);
        INIT_WORK(&rtwdev->fw_recovery_work, rtw_fw_recovery_work);
        INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work);
@@ -1639,14 +1682,11 @@ int rtw_core_init(struct rtw_dev *rtwdev)
        mutex_init(&rtwdev->hal.tx_power_mutex);
 
        init_waitqueue_head(&rtwdev->coex.wait);
+       init_completion(&rtwdev->lps_leave_check);
 
        rtwdev->sec.total_cam_num = 32;
        rtwdev->hal.current_channel = 1;
        set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map);
-       if (!(BIT(rtw_fw_lps_deep_mode) & chip->lps_deep_mode_supported))
-               rtwdev->lps_conf.deep_mode = LPS_DEEP_MODE_NONE;
-       else
-               rtwdev->lps_conf.deep_mode = rtw_fw_lps_deep_mode;
 
        rtw_stats_init(rtwdev);
 
@@ -1671,6 +1711,7 @@ int rtw_core_init(struct rtw_dev *rtwdev)
                        return ret;
                }
        }
+
        return 0;
 }
 EXPORT_SYMBOL(rtw_core_init);
index ffb02e6..9a318df 100644 (file)
@@ -37,7 +37,7 @@
 #define RTW_TP_SHIFT                   18 /* bytes/2s --> Mbps */
 
 extern bool rtw_bf_support;
-extern unsigned int rtw_fw_lps_deep_mode;
+extern bool rtw_disable_lps_deep_mode;
 extern unsigned int rtw_debug_mask;
 extern const struct ieee80211_ops rtw_ops;
 
@@ -664,6 +664,7 @@ enum rtw_pwr_state {
 struct rtw_lps_conf {
        enum rtw_lps_mode mode;
        enum rtw_lps_deep_mode deep_mode;
+       enum rtw_lps_deep_mode wow_deep_mode;
        enum rtw_pwr_state state;
        u8 awake_interval;
        u8 rlbm;
@@ -1173,6 +1174,7 @@ struct rtw_chip_info {
        u8 bt_desired_ver;
        bool scbd_support;
        bool new_scbd10_def; /* true: fix 2M(8822c) */
+       bool ble_hid_profile_support;
        u8 pstdma_type; /* 0: LPSoff, 1:LPSon */
        u8 bt_rssi_type;
        u8 ant_isolation;
@@ -1197,6 +1199,7 @@ struct rtw_chip_info {
        const struct coex_5g_afh_map *afh_5g;
        const struct rtw_hw_reg *btg_reg;
        const struct rtw_reg_domain *coex_info_hw_regs;
+       u32 wl_fw_desired_ver;
 };
 
 enum rtw_coex_bt_state_cnt {
@@ -1218,6 +1221,7 @@ enum rtw_coex_bt_state_cnt {
 };
 
 enum rtw_coex_wl_state_cnt {
+       COEX_CNT_WL_SCANAP,
        COEX_CNT_WL_CONNPKT,
        COEX_CNT_WL_COEXRUN,
        COEX_CNT_WL_NOISY0,
@@ -1240,6 +1244,8 @@ struct rtw_coex_rfe {
        bool wlg_at_btg;
 };
 
+#define COEX_WL_TDMA_PARA_LENGTH       5
+
 struct rtw_coex_dm {
        bool cur_ps_tdma_on;
        bool cur_wl_rx_low_gain_en;
@@ -1259,6 +1265,7 @@ struct rtw_coex_dm {
        u32 cur_ant_pos_type;
        u32 cur_switch_status;
        u32 setting_tdma;
+       u8 fw_tdma_para[COEX_WL_TDMA_PARA_LENGTH];
 };
 
 #define COEX_BTINFO_SRC_WL_FW  0x0
@@ -1266,7 +1273,8 @@ struct rtw_coex_dm {
 #define COEX_BTINFO_SRC_BT_ACT 0x2
 #define COEX_BTINFO_SRC_BT_IQK 0x3
 #define COEX_BTINFO_SRC_BT_SCBD        0x4
-#define COEX_BTINFO_SRC_MAX    0x5
+#define COEX_BTINFO_SRC_H2C60  0x5
+#define COEX_BTINFO_SRC_MAX    0x6
 
 #define COEX_INFO_FTP          BIT(7)
 #define COEX_INFO_A2DP         BIT(6)
@@ -1277,6 +1285,7 @@ struct rtw_coex_dm {
 #define COEX_INFO_SCO_ESCO     BIT(1)
 #define COEX_INFO_CONNECTION   BIT(0)
 #define COEX_BTINFO_LENGTH_MAX 10
+#define COEX_BTINFO_LENGTH     7
 
 struct rtw_coex_stat {
        bool bt_disabled;
@@ -1298,6 +1307,8 @@ struct rtw_coex_stat {
        bool bt_fix_2M;
        bool bt_setup_link;
        bool bt_multi_link;
+       bool bt_multi_link_pre;
+       bool bt_multi_link_remain;
        bool bt_a2dp_sink;
        bool bt_a2dp_active;
        bool bt_reenable;
@@ -1305,6 +1316,7 @@ struct rtw_coex_stat {
        bool bt_init_scan;
        bool bt_slave;
        bool bt_418_hid_exist;
+       bool bt_ble_hid_exist;
        bool bt_mailbox_reply;
 
        bool wl_under_lps;
@@ -1322,9 +1334,16 @@ struct rtw_coex_stat {
        bool wl_cck_lock;
        bool wl_cck_lock_pre;
        bool wl_cck_lock_ever;
+       bool wl_connecting;
+       bool wl_slot_toggle;
+       bool wl_slot_toggle_change; /* if toggle to no-toggle */
 
        u32 bt_supported_version;
        u32 bt_supported_feature;
+       u32 hi_pri_tx;
+       u32 hi_pri_rx;
+       u32 lo_pri_tx;
+       u32 lo_pri_rx;
        u32 patch_ver;
        u16 bt_reg_vendor_ae;
        u16 bt_reg_vendor_ac;
@@ -1346,13 +1365,21 @@ struct rtw_coex_stat {
        u8 bt_a2dp_bitpool;
        u8 bt_iqk_state;
 
+       u16 wl_beacon_interval;
        u8 wl_noisy_level;
        u8 wl_fw_dbg_info[10];
        u8 wl_fw_dbg_info_pre[10];
+       u8 wl_rx_rate;
+       u8 wl_tx_rate;
+       u8 wl_rts_rx_rate;
        u8 wl_coex_mode;
+       u8 wl_iot_peer;
        u8 ampdu_max_time;
        u8 wl_tput_dir;
 
+       u8 wl_toggle_para[6];
+       u8 wl_toggle_interval;
+
        u16 score_board;
        u16 retry_limit;
 
@@ -1362,6 +1389,9 @@ struct rtw_coex_stat {
        /* counters to record wifi states */
        u32 cnt_wl[COEX_CNT_WL_MAX];
 
+       /* counters to record bt c2h data */
+       u32 cnt_bt_info_c2h[COEX_BTINFO_SRC_MAX];
+
        u32 darfrc;
        u32 darfrch;
 };
@@ -1377,6 +1407,7 @@ struct rtw_coex {
        bool freeze;
        bool freerun;
        bool wl_rf_off;
+       bool manual_control;
 
        struct rtw_coex_stat stat;
        struct rtw_coex_dm dm;
@@ -1387,6 +1418,10 @@ struct rtw_coex {
        struct delayed_work defreeze_work;
        struct delayed_work wl_remain_work;
        struct delayed_work bt_remain_work;
+       struct delayed_work wl_connecting_work;
+       struct delayed_work bt_multi_link_remain_work;
+       struct delayed_work wl_ccklock_work;
+
 };
 
 #define DPK_RF_REG_NUM 7
@@ -1633,6 +1668,7 @@ struct rtw_fw_state {
        u8 sub_index;
        u16 h2c_version;
        u8 prev_dump_seq;
+       u32 feature;
 };
 
 struct rtw_hal {
@@ -1739,6 +1775,7 @@ struct rtw_dev {
        /* lps power state & handler work */
        struct rtw_lps_conf lps_conf;
        bool ps_enabled;
+       struct completion lps_leave_check;
 
        struct dentry *debugfs;
 
index 5cd9cc4..d44960c 100644 (file)
@@ -541,6 +541,12 @@ static void rtw_phy_cck_pd(struct rtw_dev *rtwdev)
        else
                dm_info->cck_fa_avg = (dm_info->cck_fa_avg * 3 + cck_fa) >> 2;
 
+       rtw_dbg(rtwdev, RTW_DBG_PHY, "IGI=0x%x, rssi_min=%d, cck_fa=%d\n",
+               dm_info->igi_history[0], dm_info->min_rssi,
+               dm_info->fa_history[0]);
+       rtw_dbg(rtwdev, RTW_DBG_PHY, "cck_fa_avg=%d, cck_pd_default=%d\n",
+               dm_info->cck_fa_avg, dm_info->cck_pd_default);
+
        level = rtw_phy_cck_pd_lv(rtwdev);
 
        if (level >= CCK_PD_LV_MAX)
index 7a189a9..3bead34 100644 (file)
@@ -68,48 +68,39 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
 void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
 {
        u8 request, confirm, polling;
-       u8 polling_cnt;
-       u8 retry_cnt = 0;
-
-       for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) {
-               request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
-               confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
-
-               /* toggle to request power mode, others remain 0 */
-               request ^= request | BIT_RPWM_TOGGLE;
-               if (!enter) {
-                       request |= POWER_MODE_ACK;
-               } else {
-                       request |= POWER_MODE_LCLK;
-                       if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
-                               request |= POWER_MODE_PG;
-               }
-
-               rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
-
-               if (enter)
-                       return;
-
-               /* check confirm power mode has left power save state */
-               for (polling_cnt = 0; polling_cnt < 50; polling_cnt++) {
-                       polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
-                       if ((polling ^ confirm) & BIT_RPWM_TOGGLE)
-                               return;
-                       udelay(100);
-               }
-
-               /* in case of fw/hw missed the request, retry */
-               rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n",
-                        retry_cnt);
+       int ret;
+
+       request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
+       confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
+
+       /* toggle to request power mode, others remain 0 */
+       request ^= request | BIT_RPWM_TOGGLE;
+       if (enter) {
+               request |= POWER_MODE_LCLK;
+               if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)
+                       request |= POWER_MODE_PG;
        }
+       /* Each request require an ack from firmware */
+       request |= POWER_MODE_ACK;
 
-       /* Hit here means that driver failed to change hardware power mode to
-        * active state after retry 3 times. If the power state is locked at
-        * Deep sleep, most of the hardware circuits is not working, even
-        * register read/write. It should be treated as fatal error and
-        * requires an entire analysis about the firmware/hardware
-        */
-       WARN(1, "Hardware power state locked\n");
+       rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
+
+       /* Check firmware get the power requset and ack via cpwm register */
+       ret = read_poll_timeout_atomic(rtw_read8, polling,
+                                      (polling ^ confirm) & BIT_RPWM_TOGGLE,
+                                      100, 15000, true, rtwdev,
+                                      rtwdev->hci.cpwm_addr);
+       if (ret) {
+               /* Hit here means that driver failed to get an ack from firmware.
+                * The reason could be that hardware is locked at Deep sleep,
+                * so most of the hardware circuits are not working, even
+                * register read/write; or firmware is locked in some state and
+                * cannot get the request. It should be treated as fatal error
+                * and requires an entire analysis about the firmware/hardware.
+                */
+               WARN(1, "firmware failed to ack driver for %s Deep Power mode\n",
+                    enter ? "entering" : "leaving");
+       }
 }
 EXPORT_SYMBOL(rtw_power_mode_change);
 
@@ -118,7 +109,7 @@ static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
        rtw_hci_deep_ps(rtwdev, false);
 }
 
-static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
+static int __rtw_fw_leave_lps_check_reg(struct rtw_dev *rtwdev)
 {
        int i;
 
@@ -136,12 +127,53 @@ static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
         */
        for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
                if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
-                       return;
+                       return 0;
                msleep(20);
        }
 
-       rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0);
-       rtw_warn(rtwdev, "firmware failed to restore hardware setting\n");
+       return -EBUSY;
+}
+
+static  int __rtw_fw_leave_lps_check_c2h(struct rtw_dev *rtwdev)
+{
+       if (wait_for_completion_timeout(&rtwdev->lps_leave_check,
+                                       LEAVE_LPS_TIMEOUT))
+               return 0;
+       return -EBUSY;
+}
+
+static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev)
+{
+       bool ret = false;
+       struct rtw_fw_state *fw;
+
+       if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
+               fw = &rtwdev->wow_fw;
+       else
+               fw = &rtwdev->fw;
+
+       if (fw->feature & FW_FEATURE_LPS_C2H)
+               ret = __rtw_fw_leave_lps_check_c2h(rtwdev);
+       else
+               ret = __rtw_fw_leave_lps_check_reg(rtwdev);
+
+       if (ret) {
+               rtw_write32_clr(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN);
+               rtw_warn(rtwdev, "firmware failed to leave lps state\n");
+       }
+}
+
+static void rtw_fw_leave_lps_check_prepare(struct rtw_dev *rtwdev)
+{
+       struct rtw_fw_state *fw;
+
+       if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
+               fw = &rtwdev->wow_fw;
+       else
+               fw = &rtwdev->fw;
+
+       if (fw->feature & FW_FEATURE_LPS_C2H)
+               reinit_completion(&rtwdev->lps_leave_check);
 }
 
 static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
@@ -154,17 +186,26 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
        conf->smart_ps = 0;
 
        rtw_hci_link_ps(rtwdev, false);
+       rtw_fw_leave_lps_check_prepare(rtwdev);
        rtw_fw_set_pwr_mode(rtwdev);
-       rtw_fw_leave_lps_state_check(rtwdev);
+       rtw_fw_leave_lps_check(rtwdev);
 
        clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
 
        rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
 }
 
+enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev)
+{
+       if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
+               return rtwdev->lps_conf.wow_deep_mode;
+       else
+               return rtwdev->lps_conf.deep_mode;
+}
+
 static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
 {
-       if (rtwdev->lps_conf.deep_mode == LPS_DEEP_MODE_NONE)
+       if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_NONE)
                return;
 
        if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) {
@@ -173,7 +214,7 @@ static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
                return;
        }
 
-       if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
+       if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)
                rtw_fw_set_pg_info(rtwdev);
 
        rtw_hci_deep_ps(rtwdev, true);
index 19afcec..7819391 100644 (file)
@@ -12,6 +12,7 @@
 #define POWER_MODE_LCLK                BIT(0)
 
 #define LEAVE_LPS_TRY_CNT      5
+#define LEAVE_LPS_TIMEOUT      msecs_to_jiffies(100)
 
 int rtw_enter_ips(struct rtw_dev *rtwdev);
 int rtw_leave_ips(struct rtw_dev *rtwdev);
@@ -20,5 +21,5 @@ void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter);
 void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id);
 void rtw_leave_lps(struct rtw_dev *rtwdev);
 void rtw_leave_lps_deep(struct rtw_dev *rtwdev);
-
+enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev);
 #endif
index 86b94c0..cf9a3b6 100644 (file)
@@ -60,7 +60,7 @@
 #define REG_GPIO_MUXCFG                0x0040
 #define BIT_FSPI_EN            BIT(19)
 #define BIT_EN_SIC             BIT(12)
-#define BIT_BT_AOD_GPIO3       BIT(9)
+
 #define BIT_PO_BT_PTA_PINS     BIT(9)
 #define BIT_BT_PTA_EN          BIT(5)
 #define BIT_WLRFE_4_5_EN       BIT(2)
 #define REG_BT_COEX_TABLE_H3   0x06CF
 #define REG_BBPSF_CTRL         0x06DC
 
-#define REG_BT_COEX_V2         0x0763
-#define BIT_GNT_BT_POLARITY    BIT(4)
+#define REG_BT_COEX_V2         0x0762
+#define BIT_GNT_BT_POLARITY    BIT(12)
 #define BIT_LTE_COEX_EN                BIT(7)
+#define REG_BT_COEX_ENH_INTR_CTRL      0x76E
+#define BIT_R_GRANTALL_WLMASK  BIT(3)
+#define BIT_STATIS_BT_EN       BIT(2)
+#define REG_BT_ACT_STATISTICS  0x0770
+#define REG_BT_ACT_STATISTICS_1        0x0774
 #define REG_BT_STAT_CTRL       0x0778
 #define REG_BT_TDMA_TIME       0x0790
+#define BIT_MASK_SAMPLE_RATE   GENMASK(5, 0)
 #define REG_LTR_IDLE_LATENCY   0x0798
 #define REG_LTR_ACTIVE_LATENCY 0x079C
 #define REG_LTR_CTRL_BASIC     0x07A4
 #define REG_2ND_CCA_CTRL       0x0976
 
 #define REG_CCK0_FAREPORT      0xa2c
+#define BIT_CCK0_2RX           BIT(18)
+#define BIT_CCK0_MRC           BIT(22)
 
 #define REG_DIS_DPD            0x0a70
 #define DIS_DPD_MASK           GENMASK(9, 0)
 #define REG_ANAPAR     0x1c30
 #define BIT_ANAPAR_BTPS        BIT(22)
 #define REG_RSTB_SEL   0x1c38
+#define BIT_DAC_OFF_ENABLE     BIT(4)
+#define BIT_PI_IGNORE_GNT_BT   BIT(3)
+#define BIT_NOMASK_TXBT_ENABLE BIT(3)
 
 #define REG_HRCV_MSG   0x1cf
 
index 3ddd170..9268ea8 100644 (file)
@@ -192,6 +192,7 @@ static void rtw8723d_phy_set_param(struct rtw_dev *rtwdev)
        rtw_write32(rtwdev, REG_LTR_CTRL_BASIC + 4, WLAN_LTR_CTRL2);
 
        rtw_phy_init(rtwdev);
+       rtwdev->dm_info.cck_pd_default = rtw_read8(rtwdev, REG_CSRATIO) & 0x1f;
 
        rtw_write16_set(rtwdev, REG_TXDMA_OFFSET_CHK, BIT_DROP_DATA_EN);
 
@@ -1498,6 +1499,34 @@ out:
        rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] finished\n");
 }
 
+static void rtw8723d_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
+{
+       struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+       u8 pd[CCK_PD_LV_MAX] = {3, 7, 13, 13, 13};
+       u8 cck_n_rx;
+
+       rtw_dbg(rtwdev, RTW_DBG_PHY, "lv: (%d) -> (%d)\n",
+               dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A], new_lvl);
+
+       if (dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] == new_lvl)
+               return;
+
+       cck_n_rx = (rtw_read8_mask(rtwdev, REG_CCK0_FAREPORT, BIT_CCK0_2RX) &&
+                   rtw_read8_mask(rtwdev, REG_CCK0_FAREPORT, BIT_CCK0_MRC)) ? 2 : 1;
+       rtw_dbg(rtwdev, RTW_DBG_PHY,
+               "is_linked=%d, lv=%d, n_rx=%d, cs_ratio=0x%x, pd_th=0x%x, cck_fa_avg=%d\n",
+               rtw_is_assoc(rtwdev), new_lvl, cck_n_rx,
+               dm_info->cck_pd_default + new_lvl * 2,
+               pd[new_lvl], dm_info->cck_fa_avg);
+
+       dm_info->cck_fa_avg = CCK_FA_AVG_RESET;
+
+       dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] = new_lvl;
+       rtw_write32_mask(rtwdev, REG_PWRTH, 0x3f0000, pd[new_lvl]);
+       rtw_write32_mask(rtwdev, REG_PWRTH2, 0x1f0000,
+                        dm_info->cck_pd_default + new_lvl * 2);
+}
+
 /* for coex */
 static void rtw8723d_coex_cfg_init(struct rtw_dev *rtwdev)
 {
@@ -1506,14 +1535,14 @@ static void rtw8723d_coex_cfg_init(struct rtw_dev *rtwdev)
 
        /* BT report packet sample rate  */
        /* 0x790[5:0]=0x5 */
-       rtw_write8_set(rtwdev, REG_BT_TDMA_TIME, 0x05);
+       rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0x5);
 
        /* enable BT counter statistics */
        rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x1);
 
        /* enable PTA (3-wire function form BT side) */
        rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN);
-       rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_AOD_GPIO3);
+       rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_PO_BT_PTA_PINS);
 
        /* enable PTA (tx/rx signal form WiFi side) */
        rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN);
@@ -1931,6 +1960,7 @@ static struct rtw_chip_ops rtw8723d_ops = {
        .efuse_grant            = rtw8723d_efuse_grant,
        .false_alarm_statistics = rtw8723d_false_alarm_statistics,
        .phy_calibration        = rtw8723d_phy_calibration,
+       .cck_pd_set             = rtw8723d_phy_cck_pd_set,
        .pwr_track              = rtw8723d_pwr_track,
        .config_bfee            = NULL,
        .set_gid_table          = NULL,
@@ -1949,19 +1979,19 @@ static struct rtw_chip_ops rtw8723d_ops = {
 static const struct coex_table_para table_sant_8723d[] = {
        {0xffffffff, 0xffffffff}, /* case-0 */
        {0x55555555, 0x55555555},
-       {0x65555555, 0x65555555},
+       {0x66555555, 0x66555555},
        {0xaaaaaaaa, 0xaaaaaaaa},
        {0x5a5a5a5a, 0x5a5a5a5a},
        {0xfafafafa, 0xfafafafa}, /* case-5 */
-       {0xa5555555, 0xaaaa5aaa},
-       {0x6a5a5a5a, 0x5a5a5a5a},
+       {0x6a5a5555, 0xaaaaaaaa},
+       {0x6a5a56aa, 0x6a5a56aa},
        {0x6a5a5a5a, 0x6a5a5a5a},
        {0x66555555, 0x5a5a5a5a},
-       {0x65555555, 0x6a5a5a5a}, /* case-10 */
-       {0x65555555, 0xfafafafa},
+       {0x66555555, 0x6a5a5a5a}, /* case-10 */
+       {0x66555555, 0x6a5a5aaa},
        {0x66555555, 0x5a5a5aaa},
-       {0x65555555, 0x5aaa5aaa},
-       {0x65555555, 0xaaaa5aaa},
+       {0x66555555, 0x6aaa5aaa},
+       {0x66555555, 0xaaaa5aaa},
        {0x66555555, 0xaaaaaaaa}, /* case-15 */
        {0xffff55ff, 0xfafafafa},
        {0xffff55ff, 0x6afa5afa},
@@ -1970,38 +2000,41 @@ static const struct coex_table_para table_sant_8723d[] = {
        {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */
        {0xaa5555aa, 0xaaaaaaaa},
        {0xffffffff, 0x5a5a5a5a},
-       {0xffffffff, 0x6a5a5a5a},
+       {0xffffffff, 0x5a5a5a5a},
        {0xffffffff, 0x55555555},
-       {0xffffffff, 0x6a5a5aaa}, /* case-25 */
+       {0xffffffff, 0x5a5a5aaa}, /* case-25 */
        {0x55555555, 0x5a5a5a5a},
        {0x55555555, 0xaaaaaaaa},
-       {0x55555555, 0x6a6a6a6a},
-       {0x656a656a, 0x656a656a}
+       {0x55555555, 0x6a5a6a5a},
+       {0x66556655, 0x66556655},
+       {0x66556aaa, 0x6a5a6aaa}, /* case-30 */
+       {0xffffffff, 0x5aaa5aaa},
+       {0x56555555, 0x5a5a5aaa},
 };
 
 /* Non-Shared-Antenna Coex Table */
 static const struct coex_table_para table_nsant_8723d[] = {
        {0xffffffff, 0xffffffff}, /* case-100 */
        {0x55555555, 0x55555555},
-       {0x65555555, 0x65555555},
+       {0x66555555, 0x66555555},
        {0xaaaaaaaa, 0xaaaaaaaa},
        {0x5a5a5a5a, 0x5a5a5a5a},
        {0xfafafafa, 0xfafafafa}, /* case-105 */
        {0x5afa5afa, 0x5afa5afa},
        {0x55555555, 0xfafafafa},
-       {0x65555555, 0xfafafafa},
-       {0x65555555, 0x5a5a5a5a},
-       {0x65555555, 0x6a5a5a5a}, /* case-110 */
-       {0x65555555, 0xaaaaaaaa},
+       {0x66555555, 0xfafafafa},
+       {0x66555555, 0x5a5a5a5a},
+       {0x66555555, 0x6a5a5a5a}, /* case-110 */
+       {0x66555555, 0xaaaaaaaa},
        {0xffff55ff, 0xfafafafa},
        {0xffff55ff, 0x5afa5afa},
        {0xffff55ff, 0xaaaaaaaa},
-       {0xaaffffaa, 0xfafafafa}, /* case-115 */
+       {0xffff55ff, 0xffff55ff}, /* case-115 */
        {0xaaffffaa, 0x5afa5afa},
        {0xaaffffaa, 0xaaaaaaaa},
        {0xffffffff, 0xfafafafa},
        {0xffffffff, 0x5afa5afa},
-       {0xffffffff, 0xaaaaaaaa},/* case-120 */
+       {0xffffffff, 0xaaaaaaaa}, /* case-120 */
        {0x55ff55ff, 0x5afa5afa},
        {0x55ff55ff, 0xaaaaaaaa},
        {0x55ff55ff, 0x55ff55ff}
@@ -2009,31 +2042,31 @@ static const struct coex_table_para table_nsant_8723d[] = {
 
 /* Shared-Antenna TDMA */
 static const struct coex_tdma_para tdma_sant_8723d[] = {
-       { {0x08, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */
+       { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */
        { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */
        { {0x61, 0x3a, 0x03, 0x11, 0x11} },
-       { {0x61, 0x20, 0x03, 0x11, 0x11} },
        { {0x61, 0x30, 0x03, 0x11, 0x11} },
+       { {0x61, 0x20, 0x03, 0x11, 0x11} },
        { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-5 */
-       { {0x61, 0x48, 0x03, 0x11, 0x10} },
+       { {0x61, 0x45, 0x03, 0x11, 0x10} },
        { {0x61, 0x3a, 0x03, 0x11, 0x10} },
        { {0x61, 0x30, 0x03, 0x11, 0x10} },
        { {0x61, 0x20, 0x03, 0x11, 0x10} },
        { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */
-       { {0x61, 0x10, 0x03, 0x11, 0x14} },
+       { {0x61, 0x08, 0x03, 0x11, 0x14} },
        { {0x61, 0x08, 0x03, 0x10, 0x14} },
-       { {0x51, 0x10, 0x03, 0x10, 0x54} },
-       { {0x51, 0x10, 0x03, 0x10, 0x55} },
-       { {0x51, 0x10, 0x07, 0x10, 0x54} }, /* case-15 */
+       { {0x51, 0x08, 0x03, 0x10, 0x54} },
+       { {0x51, 0x08, 0x03, 0x10, 0x55} },
+       { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */
        { {0x51, 0x45, 0x03, 0x10, 0x50} },
        { {0x51, 0x3a, 0x03, 0x10, 0x50} },
        { {0x51, 0x30, 0x03, 0x10, 0x50} },
        { {0x51, 0x20, 0x03, 0x10, 0x50} },
-       { {0x51, 0x15, 0x03, 0x10, 0x50} }, /* case-20 */
+       { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */
        { {0x51, 0x4a, 0x03, 0x10, 0x50} },
        { {0x51, 0x0c, 0x03, 0x10, 0x54} },
        { {0x55, 0x08, 0x03, 0x10, 0x54} },
-       { {0x65, 0x10, 0x03, 0x11, 0x11} },
+       { {0x65, 0x10, 0x03, 0x11, 0x10} },
        { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */
        { {0x51, 0x08, 0x03, 0x10, 0x50} },
        { {0x61, 0x08, 0x03, 0x11, 0x11} }
@@ -2041,7 +2074,7 @@ static const struct coex_tdma_para tdma_sant_8723d[] = {
 
 /* Non-Shared-Antenna TDMA */
 static const struct coex_tdma_para tdma_nsant_8723d[] = {
-       { {0x00, 0x00, 0x00, 0x40, 0x01} }, /* case-100 */
+       { {0x00, 0x00, 0x00, 0x00, 0x01} }, /* case-100 */
        { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-101 */
        { {0x61, 0x3a, 0x03, 0x11, 0x11} },
        { {0x61, 0x30, 0x03, 0x11, 0x11} },
@@ -2062,7 +2095,7 @@ static const struct coex_tdma_para tdma_nsant_8723d[] = {
        { {0x51, 0x30, 0x03, 0x10, 0x50} },
        { {0x51, 0x20, 0x03, 0x10, 0x50} },
        { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-120 */
-       { {0x51, 0x08, 0x03, 0x10, 0x50} },
+       { {0x51, 0x08, 0x03, 0x10, 0x50} }
 };
 
 /* rssi in percentage % (dbm = % - 100) */
@@ -2719,6 +2752,7 @@ struct rtw_chip_info rtw8723d_hw_spec = {
        .bt_desired_ver = 0x2f,
        .scbd_support = true,
        .new_scbd10_def = true,
+       .ble_hid_profile_support = false,
        .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
        .bt_rssi_type = COEX_BTRSSI_RATIO,
        .ant_isolation = 15,
index 7894d32..41d3517 100644 (file)
@@ -163,6 +163,7 @@ static inline s32 iqk_mult(s32 x, s32 y, s32 *ext)
 #define REG_CCK0_SYS           0x0a00
 #define BIT_CCK_SIDE_BAND      BIT(4)
 #define REG_CCK_ANT_SEL_11N    0x0a04
+#define REG_PWRTH              0x0a08
 #define REG_CCK_FA_RST_11N     0x0a2c
 #define BIT_MASK_CCK_CNT_KEEP  BIT(12)
 #define BIT_MASK_CCK_CNT_EN    BIT(13)
@@ -175,6 +176,8 @@ static inline s32 iqk_mult(s32 x, s32 y, s32 *ext)
 #define REG_CCK_CCA_CNT_11N    0x0a60
 #define BIT_MASK_CCK_FA_MSB    GENMASK(7, 0)
 #define BIT_MASK_CCK_FA_LSB    GENMASK(15, 8)
+#define REG_PWRTH2             0x0aa8
+#define REG_CSRATIO            0x0aaa
 #define REG_OFDM_FA_HOLDC_11N  0x0c00
 #define BIT_MASK_OFDM_FA_KEEP  BIT(31)
 #define REG_BB_RX_PATH_11N     0x0c04
index da2e741..fbfd854 100644 (file)
@@ -656,8 +656,7 @@ static void rtw8821c_coex_cfg_init(struct rtw_dev *rtwdev)
        rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
 
        /* BT report packet sample rate */
-       rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, SAMPLE_RATE_MASK,
-                       SAMPLE_RATE);
+       rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0x5);
 
        /* enable BT counter statistics */
        rtw_write8(rtwdev, REG_BT_STAT_CTRL, BT_CNT_ENABLE);
@@ -1021,6 +1020,7 @@ static void rtw8821c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
 {
        struct rtw_dm_info *dm_info = &rtwdev->dm_info;
        u8 pd[CCK_PD_LV_MAX] = {3, 7, 13, 13, 13};
+       u8 cck_n_rx;
 
        if (dm_info->min_rssi > 60) {
                new_lvl = 4;
@@ -1028,9 +1028,20 @@ static void rtw8821c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
                goto set_cck_pd;
        }
 
+       rtw_dbg(rtwdev, RTW_DBG_PHY, "lv: (%d) -> (%d)\n",
+               dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A], new_lvl);
+
        if (dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] == new_lvl)
                return;
 
+       cck_n_rx = (rtw_read8_mask(rtwdev, REG_CCK0_FAREPORT, BIT_CCK0_2RX) &&
+                   rtw_read8_mask(rtwdev, REG_CCK0_FAREPORT, BIT_CCK0_MRC)) ? 2 : 1;
+       rtw_dbg(rtwdev, RTW_DBG_PHY,
+               "is_linked=%d, lv=%d, n_rx=%d, cs_ratio=0x%x, pd_th=0x%x, cck_fa_avg=%d\n",
+               rtw_is_assoc(rtwdev), new_lvl, cck_n_rx,
+               dm_info->cck_pd_default + new_lvl * 2,
+               pd[new_lvl], dm_info->cck_fa_avg);
+
        dm_info->cck_fa_avg = CCK_FA_AVG_RESET;
 
 set_cck_pd:
@@ -1819,6 +1830,7 @@ struct rtw_chip_info rtw8821c_hw_spec = {
        .bt_desired_ver = 0x46,
        .scbd_support = true,
        .new_scbd10_def = false,
+       .ble_hid_profile_support = false,
        .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
        .bt_rssi_type = COEX_BTRSSI_RATIO,
        .ant_isolation = 15,
index bd01e82..e11e3fc 100644 (file)
@@ -231,8 +231,6 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
 #define REG_IQKFAILMSK 0x1bf0
 #define BIT_MASK_R_RFE_SEL_15  GENMASK(31, 28)
 #define BIT_SDIO_INT BIT(18)
-#define SAMPLE_RATE_MASK GENMASK(5, 0)
-#define SAMPLE_RATE    0x5
 #define BT_CNT_ENABLE  0x1
 #define BIT_BCN_QUEUE  BIT(3)
 #define BCN_PRI_EN     0x1
index 22d0dd6..f178915 100644 (file)
@@ -87,7 +87,7 @@ static const u32 rtw8822b_txscale_tbl[RTW_TXSCALE_SIZE] = {
        0x2d3, 0x2fe, 0x32b, 0x35c, 0x38e, 0x3c4, 0x3fe
 };
 
-static const u8 rtw8822b_get_swing_index(struct rtw_dev *rtwdev)
+static u8 rtw8822b_get_swing_index(struct rtw_dev *rtwdev)
 {
        u8 i = 0;
        u32 swing, table_value;
@@ -1120,21 +1120,21 @@ static void rtw8822b_coex_cfg_init(struct rtw_dev *rtwdev)
 
        /* BT report packet sample rate */
        /* 0x790[5:0]=0x5 */
-       rtw_write8_set(rtwdev, REG_BT_TDMA_TIME, 0x05);
+       rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0x5);
 
        /* enable BT counter statistics */
        rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x1);
 
        /* enable PTA (3-wire function form BT side) */
        rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN);
-       rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_AOD_GPIO3);
+       rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_PO_BT_PTA_PINS);
 
        /* enable PTA (tx/rx signal form WiFi side) */
        rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN);
        /* wl tx signal to PTA not case EDCCA */
        rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT_PTA_EDCCA_EN);
        /* GNT_BT=1 while select both */
-       rtw_write8_set(rtwdev, REG_BT_COEX_V2, BIT_GNT_BT_POLARITY);
+       rtw_write16_set(rtwdev, REG_BT_COEX_V2, BIT_GNT_BT_POLARITY);
 }
 
 static void rtw8822b_coex_cfg_ant_switch(struct rtw_dev *rtwdev,
@@ -1341,6 +1341,7 @@ static void rtw8822b_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
        coex_dm->cur_wl_rx_low_gain_en = low_gain;
 
        if (coex_dm->cur_wl_rx_low_gain_en) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], Hi-Li Table On!\n");
                for (i = 0; i < ARRAY_SIZE(wl_rx_low_gain_on); i++)
                        rtw_write32(rtwdev, REG_RX_GAIN_EN, wl_rx_low_gain_on[i]);
 
@@ -1350,6 +1351,7 @@ static void rtw8822b_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
                rtw_write_rf(rtwdev, RF_PATH_B, RF_RCKD, 0x2, 0x1);
                rtw_write_rf(rtwdev, RF_PATH_B, RF_RCK, 0x3f, 0x3f);
        } else {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], Hi-Li Table Off!\n");
                for (i = 0; i < ARRAY_SIZE(wl_rx_low_gain_off); i++)
                        rtw_write32(rtwdev, 0x81c, wl_rx_low_gain_off[i]);
 
@@ -2141,14 +2143,14 @@ static const struct coex_table_para table_sant_8822b[] = {
        {0xaaaaaaaa, 0xaaaaaaaa},
        {0x5a5a5a5a, 0x5a5a5a5a},
        {0xfafafafa, 0xfafafafa}, /* case-5 */
-       {0x6a5a6a5a, 0xaaaaaaaa},
+       {0x6a5a5555, 0xaaaaaaaa},
        {0x6a5a56aa, 0x6a5a56aa},
        {0x6a5a5a5a, 0x6a5a5a5a},
        {0x66555555, 0x5a5a5a5a},
        {0x66555555, 0x6a5a5a5a}, /* case-10 */
        {0x66555555, 0xfafafafa},
        {0x66555555, 0x5a5a5aaa},
-       {0x66555555, 0x5aaa5aaa},
+       {0x66555555, 0x6aaa5aaa},
        {0x66555555, 0xaaaa5aaa},
        {0x66555555, 0xaaaaaaaa}, /* case-15 */
        {0xffff55ff, 0xfafafafa},
@@ -2158,13 +2160,16 @@ static const struct coex_table_para table_sant_8822b[] = {
        {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */
        {0xaa5555aa, 0xaaaaaaaa},
        {0xffffffff, 0x5a5a5a5a},
-       {0xffffffff, 0x6a5a5a5a},
+       {0xffffffff, 0x5a5a5a5a},
        {0xffffffff, 0x55555555},
        {0xffffffff, 0x6a5a5aaa}, /* case-25 */
        {0x55555555, 0x5a5a5a5a},
        {0x55555555, 0xaaaaaaaa},
        {0x55555555, 0x6a5a6a5a},
-       {0x66556655, 0x66556655}
+       {0x66556655, 0x66556655},
+       {0x66556aaa, 0x6a5a6aaa}, /* case-30 */
+       {0xffffffff, 0x5aaa5aaa},
+       {0x56555555, 0x5a5a5aaa},
 };
 
 /* Non-Shared-Antenna Coex Table */
@@ -2184,7 +2189,7 @@ static const struct coex_table_para table_nsant_8822b[] = {
        {0xffff55ff, 0xfafafafa},
        {0xffff55ff, 0x5afa5afa},
        {0xffff55ff, 0xaaaaaaaa},
-       {0xaaffffaa, 0xfafafafa}, /* case-115 */
+       {0xffff55ff, 0xffff55ff}, /* case-115 */
        {0xaaffffaa, 0x5afa5afa},
        {0xaaffffaa, 0xaaaaaaaa},
        {0xffffffff, 0xfafafafa},
@@ -2213,7 +2218,7 @@ static const struct coex_tdma_para tdma_sant_8822b[] = {
        { {0x51, 0x08, 0x03, 0x10, 0x54} },
        { {0x51, 0x08, 0x03, 0x10, 0x55} },
        { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */
-       { {0x51, 0x45, 0x03, 0x10, 0x10} },
+       { {0x51, 0x45, 0x03, 0x10, 0x50} },
        { {0x51, 0x3a, 0x03, 0x10, 0x50} },
        { {0x51, 0x30, 0x03, 0x10, 0x50} },
        { {0x51, 0x20, 0x03, 0x10, 0x50} },
@@ -2221,7 +2226,7 @@ static const struct coex_tdma_para tdma_sant_8822b[] = {
        { {0x51, 0x4a, 0x03, 0x10, 0x50} },
        { {0x51, 0x0c, 0x03, 0x10, 0x54} },
        { {0x55, 0x08, 0x03, 0x10, 0x54} },
-       { {0x65, 0x10, 0x03, 0x11, 0x11} },
+       { {0x65, 0x10, 0x03, 0x11, 0x10} },
        { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */
        { {0x51, 0x08, 0x03, 0x10, 0x50} },
        { {0x61, 0x08, 0x03, 0x11, 0x11} }
@@ -2230,7 +2235,7 @@ static const struct coex_tdma_para tdma_sant_8822b[] = {
 /* Non-Shared-Antenna TDMA */
 static const struct coex_tdma_para tdma_nsant_8822b[] = {
        { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-100 */
-       { {0x61, 0x45, 0x03, 0x11, 0x11} },
+       { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-101 */
        { {0x61, 0x3a, 0x03, 0x11, 0x11} },
        { {0x61, 0x30, 0x03, 0x11, 0x11} },
        { {0x61, 0x20, 0x03, 0x11, 0x11} },
@@ -2249,13 +2254,13 @@ static const struct coex_tdma_para tdma_nsant_8822b[] = {
        { {0x51, 0x3a, 0x03, 0x10, 0x50} },
        { {0x51, 0x30, 0x03, 0x10, 0x50} },
        { {0x51, 0x20, 0x03, 0x10, 0x50} },
-       { {0x51, 0x10, 0x03, 0x10, 0x50} }  /* case-120 */
+       { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-120 */
+       { {0x51, 0x08, 0x03, 0x10, 0x50} }
 };
 
 /* rssi in percentage % (dbm = % - 100) */
 static const u8 wl_rssi_step_8822b[] = {60, 50, 44, 30};
 static const u8 bt_rssi_step_8822b[] = {30, 30, 30, 30};
-static const struct coex_5g_afh_map afh_5g_8822b[] = { {0, 0, 0} };
 
 /* wl_tx_dec_power, bt_tx_dec_power, wl_rx_gain, bt_rx_lna_constrain */
 static const struct coex_rf_para rf_para_tx_8822b[] = {
@@ -2276,6 +2281,27 @@ static const struct coex_rf_para rf_para_rx_8822b[] = {
        {1, 13, true, 1}
 };
 
+static const struct coex_5g_afh_map afh_5g_8822b[] = {
+       {120, 2, 4},
+       {124, 8, 8},
+       {128, 17, 8},
+       {132, 26, 10},
+       {136, 34, 8},
+       {140, 42, 10},
+       {144, 51, 8},
+       {149, 62, 8},
+       {153, 71, 10},
+       {157, 77, 4},
+       {118, 2, 4},
+       {126, 12, 16},
+       {134, 29, 16},
+       {142, 46, 16},
+       {151, 66, 16},
+       {159, 76, 4},
+       {122, 10, 20},
+       {138, 37, 34},
+       {155, 68, 20}
+};
 static_assert(ARRAY_SIZE(rf_para_tx_8822b) == ARRAY_SIZE(rf_para_rx_8822b));
 
 static const u8
@@ -2481,6 +2507,7 @@ struct rtw_chip_info rtw8822b_hw_spec = {
        .bt_desired_ver = 0x6,
        .scbd_support = true,
        .new_scbd10_def = false,
+       .ble_hid_profile_support = false,
        .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
        .bt_rssi_type = COEX_BTRSSI_RATIO,
        .ant_isolation = 15,
index e37300e..7dd3ccb 100644 (file)
@@ -2132,28 +2132,28 @@ static void rtw8822c_coex_cfg_init(struct rtw_dev *rtwdev)
        /* enable TBTT nterrupt */
        rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
 
-       /* BT report packet sample rate  */
+       /* BT report packet sample rate */
        /* 0x790[5:0]=0x5 */
-       rtw_write8_set(rtwdev, REG_BT_TDMA_TIME, 0x05);
+       rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0x5);
 
        /* enable BT counter statistics */
        rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x1);
 
        /* enable PTA (3-wire function form BT side) */
        rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN);
-       rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_AOD_GPIO3);
+       rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_PO_BT_PTA_PINS);
 
        /* enable PTA (tx/rx signal form WiFi side) */
        rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN);
        /* wl tx signal to PTA not case EDCCA */
        rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT_PTA_EDCCA_EN);
        /* GNT_BT=1 while select both */
-       rtw_write8_set(rtwdev, REG_BT_COEX_V2, BIT_GNT_BT_POLARITY);
-       /* BT_CCA = ~GNT_WL_BB, (not or GNT_BT_BB, LTE_Rx */
+       rtw_write16_set(rtwdev, REG_BT_COEX_V2, BIT_GNT_BT_POLARITY);
+       /* BT_CCA = ~GNT_WL_BB, not or GNT_BT_BB, LTE_Rx */
        rtw_write8_clr(rtwdev, REG_DUMMY_PAGE4_V1, BIT_BTCCA_CTRL);
 
        /* to avoid RF parameter error */
-       rtw_write_rf(rtwdev, RF_PATH_B, 0x1, 0xfffff, 0x40000);
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_MODOPT, 0xfffff, 0x40000);
 }
 
 static void rtw8822c_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
@@ -2190,10 +2190,10 @@ static void rtw8822c_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
         * disable WL-S1 BB chage RF mode if GNT_BT
         * since RF TRx mask can do it
         */
-       rtw_write8_mask(rtwdev, 0x1c32, BIT(6), 1);
-       rtw_write8_mask(rtwdev, 0x1c39, BIT(4), 0);
-       rtw_write8_mask(rtwdev, 0x1c3b, BIT(4), 1);
-       rtw_write8_mask(rtwdev, 0x4160, BIT(3), 1);
+       rtw_write8_mask(rtwdev, REG_ANAPAR + 2, BIT_ANAPAR_BTPS >> 16, 1);
+       rtw_write8_mask(rtwdev, REG_RSTB_SEL + 1, BIT_DAC_OFF_ENABLE, 0);
+       rtw_write8_mask(rtwdev, REG_RSTB_SEL + 3, BIT_DAC_OFF_ENABLE, 1);
+       rtw_write8_mask(rtwdev, REG_IGN_GNTBT4, BIT_PI_IGNORE_GNT_BT, 1);
 
        /* disable WL-S0 BB chage RF mode if wifi is at 5G,
         * or antenna path is separated
@@ -2201,26 +2201,32 @@ static void rtw8822c_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
        if (coex_stat->wl_coex_mode == COEX_WLINK_5G ||
            coex->under_5g || !efuse->share_ant) {
                if (coex_stat->kt_ver >= 3) {
-                       rtw_write8_mask(rtwdev, 0x1860, BIT(3), 0);
-                       rtw_write8_mask(rtwdev, 0x1ca7, BIT(3), 1);
+                       rtw_write8_mask(rtwdev, REG_IGN_GNT_BT1,
+                                       BIT_PI_IGNORE_GNT_BT, 0);
+                       rtw_write8_mask(rtwdev, REG_NOMASK_TXBT,
+                                       BIT_NOMASK_TXBT_ENABLE, 1);
                } else {
-                       rtw_write8_mask(rtwdev, 0x1860, BIT(3), 1);
+                       rtw_write8_mask(rtwdev, REG_IGN_GNT_BT1,
+                                       BIT_PI_IGNORE_GNT_BT, 1);
                }
        } else {
                /* shared-antenna */
-               rtw_write8_mask(rtwdev, 0x1860, BIT(3), 0);
-               if (coex_stat->kt_ver >= 3)
-                       rtw_write8_mask(rtwdev, 0x1ca7, BIT(3), 0);
+               rtw_write8_mask(rtwdev, REG_IGN_GNT_BT1,
+                               BIT_PI_IGNORE_GNT_BT, 0);
+               if (coex_stat->kt_ver >= 3) {
+                       rtw_write8_mask(rtwdev, REG_NOMASK_TXBT,
+                                       BIT_NOMASK_TXBT_ENABLE, 0);
+               }
        }
 }
 
 static void rtw8822c_coex_cfg_gnt_debug(struct rtw_dev *rtwdev)
 {
-       rtw_write8_mask(rtwdev, 0x66, BIT(4), 0);
-       rtw_write8_mask(rtwdev, 0x67, BIT(0), 0);
-       rtw_write8_mask(rtwdev, 0x42, BIT(3), 0);
-       rtw_write8_mask(rtwdev, 0x65, BIT(7), 0);
-       rtw_write8_mask(rtwdev, 0x73, BIT(3), 0);
+       rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 2, BIT_BTGP_SPI_EN >> 16, 0);
+       rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 3, BIT_BTGP_JTAG_EN >> 24, 0);
+       rtw_write8_mask(rtwdev, REG_GPIO_MUXCFG + 2, BIT_FSPI_EN >> 16, 0);
+       rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 1, BIT_LED1DIS >> 8, 0);
+       rtw_write8_mask(rtwdev, REG_SYS_SDIO_CTRL + 3, BIT_DBG_GNT_WL_BT >> 24, 0);
 }
 
 static void rtw8822c_coex_cfg_rfe_type(struct rtw_dev *rtwdev)
@@ -2241,9 +2247,9 @@ static void rtw8822c_coex_cfg_rfe_type(struct rtw_dev *rtwdev)
                coex_rfe->wlg_at_btg = false;
 
        /* disable LTE coex in wifi side */
-       rtw_coex_write_indirect_reg(rtwdev, 0x38, BIT_LTE_COEX_EN, 0x0);
-       rtw_coex_write_indirect_reg(rtwdev, 0xa0, MASKLWORD, 0xffff);
-       rtw_coex_write_indirect_reg(rtwdev, 0xa4, MASKLWORD, 0xffff);
+       rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, BIT_LTE_COEX_EN, 0x0);
+       rtw_coex_write_indirect_reg(rtwdev, LTE_WL_TRX_CTRL, MASKLWORD, 0xffff);
+       rtw_coex_write_indirect_reg(rtwdev, LTE_BT_TRX_CTRL, MASKLWORD, 0xffff);
 }
 
 static void rtw8822c_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
@@ -2268,16 +2274,22 @@ static void rtw8822c_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
        coex_dm->cur_wl_rx_low_gain_en = low_gain;
 
        if (coex_dm->cur_wl_rx_low_gain_en) {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], Hi-Li Table On!\n");
+
                /* set Rx filter corner RCK offset */
-               rtw_write_rf(rtwdev, RF_PATH_A, 0xde, 0xfffff, 0x22);
-               rtw_write_rf(rtwdev, RF_PATH_A, 0x1d, 0xfffff, 0x36);
-               rtw_write_rf(rtwdev, RF_PATH_B, 0xde, 0xfffff, 0x22);
-               rtw_write_rf(rtwdev, RF_PATH_B, 0x1d, 0xfffff, 0x36);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_RCKD, RFREG_MASK, 0x22);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_RCK, RFREG_MASK, 0x36);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_RCKD, RFREG_MASK, 0x22);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_RCK, RFREG_MASK, 0x36);
+
        } else {
+               rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], Hi-Li Table Off!\n");
+
                /* set Rx filter corner RCK offset */
-               rtw_write_rf(rtwdev, RF_PATH_A, 0xde, 0xfffff, 0x20);
-               rtw_write_rf(rtwdev, RF_PATH_A, 0x1d, 0xfffff, 0x0);
-               rtw_write_rf(rtwdev, RF_PATH_B, 0x1d, 0xfffff, 0x0);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_RCKD, RFREG_MASK, 0x20);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_RCK, RFREG_MASK, 0x0);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_RCKD, RFREG_MASK, 0x20);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_RCK, RFREG_MASK, 0x0);
        }
 }
 
@@ -2442,7 +2454,7 @@ static void rtw8822c_dpk_rxbb_dc_cal(struct rtw_dev *rtwdev, u8 path)
 static u8 rtw8822c_dpk_dc_corr_check(struct rtw_dev *rtwdev, u8 path)
 {
        u16 dc_i, dc_q;
-       u8 corr_val, corr_idx;
+       u8 corr_idx;
 
        rtw_write32(rtwdev, REG_RXSRAM_CTL, 0x000900f0);
        dc_i = (u16)rtw_read32_mask(rtwdev, REG_STAT_RPT, GENMASK(27, 16));
@@ -2455,7 +2467,7 @@ static u8 rtw8822c_dpk_dc_corr_check(struct rtw_dev *rtwdev, u8 path)
 
        rtw_write32(rtwdev, REG_RXSRAM_CTL, 0x000000f0);
        corr_idx = (u8)rtw_read32_mask(rtwdev, REG_STAT_RPT, GENMASK(7, 0));
-       corr_val = (u8)rtw_read32_mask(rtwdev, REG_STAT_RPT, GENMASK(15, 8));
+       rtw_read32_mask(rtwdev, REG_STAT_RPT, GENMASK(15, 8));
 
        if (dc_i > 200 || dc_q > 200 || corr_idx < 40 || corr_idx > 65)
                return 1;
@@ -3442,6 +3454,10 @@ rtw8822c_phy_cck_pd_set_reg(struct rtw_dev *rtwdev,
                         rtw8822c_cck_pd_reg[bw][nrx].reg_cs,
                         rtw8822c_cck_pd_reg[bw][nrx].mask_cs,
                         cs);
+
+       rtw_dbg(rtwdev, RTW_DBG_PHY,
+               "is_linked=%d, bw=%d, nrx=%d, cs_ratio=0x%x, pd_th=0x%x\n",
+               rtw_is_assoc(rtwdev), bw, nrx, cs, pd);
 }
 
 static void rtw8822c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
@@ -3455,6 +3471,10 @@ static void rtw8822c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
        nrx = (u8)rtw_read32_mask(rtwdev, 0x1a2c, 0x60000);
        bw = (u8)rtw_read32_mask(rtwdev, 0x9b0, 0xc);
 
+       rtw_dbg(rtwdev, RTW_DBG_PHY, "lv: (%d) -> (%d) bw=%d nr=%d cck_fa_avg=%d\n",
+               dm_info->cck_pd_lv[bw][nrx], new_lvl, bw, nrx,
+               dm_info->cck_fa_avg);
+
        if (dm_info->cck_pd_lv[bw][nrx] == new_lvl)
                return;
 
@@ -3983,14 +4003,14 @@ static const struct coex_table_para table_sant_8822c[] = {
        {0xaaaaaaaa, 0xaaaaaaaa},
        {0x5a5a5a5a, 0x5a5a5a5a},
        {0xfafafafa, 0xfafafafa}, /* case-5 */
-       {0x6a5a6a5a, 0xaaaaaaaa},
+       {0x6a5a5555, 0xaaaaaaaa},
        {0x6a5a56aa, 0x6a5a56aa},
        {0x6a5a5a5a, 0x6a5a5a5a},
        {0x66555555, 0x5a5a5a5a},
        {0x66555555, 0x6a5a5a5a}, /* case-10 */
-       {0x66555555, 0xfafafafa},
+       {0x66555555, 0x6a5a5aaa},
        {0x66555555, 0x5a5a5aaa},
-       {0x66555555, 0x5aaa5aaa},
+       {0x66555555, 0x6aaa5aaa},
        {0x66555555, 0xaaaa5aaa},
        {0x66555555, 0xaaaaaaaa}, /* case-15 */
        {0xffff55ff, 0xfafafafa},
@@ -4000,13 +4020,16 @@ static const struct coex_table_para table_sant_8822c[] = {
        {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */
        {0xaa5555aa, 0xaaaaaaaa},
        {0xffffffff, 0x5a5a5a5a},
-       {0xffffffff, 0x6a5a5a5a},
+       {0xffffffff, 0x5a5a5a5a},
        {0xffffffff, 0x55555555},
-       {0xffffffff, 0x6a5a5aaa}, /* case-25 */
+       {0xffffffff, 0x5a5a5aaa}, /* case-25 */
        {0x55555555, 0x5a5a5a5a},
        {0x55555555, 0xaaaaaaaa},
        {0x55555555, 0x6a5a6a5a},
-       {0x66556655, 0x66556655}
+       {0x66556655, 0x66556655},
+       {0x66556aaa, 0x6a5a6aaa}, /*case-30*/
+       {0xffffffff, 0x5aaa5aaa},
+       {0x56555555, 0x5a5a5aaa},
 };
 
 /* Non-Shared-Antenna Coex Table */
@@ -4026,12 +4049,12 @@ static const struct coex_table_para table_nsant_8822c[] = {
        {0xffff55ff, 0xfafafafa},
        {0xffff55ff, 0x5afa5afa},
        {0xffff55ff, 0xaaaaaaaa},
-       {0xaaffffaa, 0xfafafafa}, /* case-115 */
+       {0xffff55ff, 0xffff55ff}, /* case-115 */
        {0xaaffffaa, 0x5afa5afa},
        {0xaaffffaa, 0xaaaaaaaa},
        {0xffffffff, 0xfafafafa},
        {0xffffffff, 0x5afa5afa},
-       {0xffffffff, 0xaaaaaaaa},/* case-120 */
+       {0xffffffff, 0xaaaaaaaa}, /* case-120 */
        {0x55ff55ff, 0x5afa5afa},
        {0x55ff55ff, 0xaaaaaaaa},
        {0x55ff55ff, 0x55ff55ff}
@@ -4040,7 +4063,7 @@ static const struct coex_table_para table_nsant_8822c[] = {
 /* Shared-Antenna TDMA */
 static const struct coex_tdma_para tdma_sant_8822c[] = {
        { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */
-       { {0x61, 0x45, 0x03, 0x11, 0x11} },
+       { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */
        { {0x61, 0x3a, 0x03, 0x11, 0x11} },
        { {0x61, 0x30, 0x03, 0x11, 0x11} },
        { {0x61, 0x20, 0x03, 0x11, 0x11} },
@@ -4055,7 +4078,7 @@ static const struct coex_tdma_para tdma_sant_8822c[] = {
        { {0x51, 0x08, 0x03, 0x10, 0x54} },
        { {0x51, 0x08, 0x03, 0x10, 0x55} },
        { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */
-       { {0x51, 0x45, 0x03, 0x10, 0x10} },
+       { {0x51, 0x45, 0x03, 0x10, 0x50} },
        { {0x51, 0x3a, 0x03, 0x10, 0x50} },
        { {0x51, 0x30, 0x03, 0x10, 0x50} },
        { {0x51, 0x20, 0x03, 0x10, 0x50} },
@@ -4063,7 +4086,7 @@ static const struct coex_tdma_para tdma_sant_8822c[] = {
        { {0x51, 0x4a, 0x03, 0x10, 0x50} },
        { {0x51, 0x0c, 0x03, 0x10, 0x54} },
        { {0x55, 0x08, 0x03, 0x10, 0x54} },
-       { {0x65, 0x10, 0x03, 0x11, 0x11} },
+       { {0x65, 0x10, 0x03, 0x11, 0x10} },
        { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */
        { {0x51, 0x08, 0x03, 0x10, 0x50} },
        { {0x61, 0x08, 0x03, 0x11, 0x11} }
@@ -4091,7 +4114,8 @@ static const struct coex_tdma_para tdma_nsant_8822c[] = {
        { {0x51, 0x3a, 0x03, 0x10, 0x50} },
        { {0x51, 0x30, 0x03, 0x10, 0x50} },
        { {0x51, 0x20, 0x03, 0x10, 0x50} },
-       { {0x51, 0x10, 0x03, 0x10, 0x50} }  /* case-120 */
+       { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-120 */
+       { {0x51, 0x08, 0x03, 0x10, 0x50} }
 };
 
 /* rssi in percentage % (dbm = % - 100) */
@@ -4337,10 +4361,11 @@ struct rtw_chip_info rtw8822c_hw_spec = {
        .wowlan_stub = &rtw_wowlan_stub_8822c,
        .max_sched_scan_ssids = 4,
 #endif
-       .coex_para_ver = 0x20070217,
-       .bt_desired_ver = 0x17,
+       .coex_para_ver = 0x201029,
+       .bt_desired_ver = 0x1c,
        .scbd_support = true,
        .new_scbd10_def = true,
+       .ble_hid_profile_support = true,
        .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
        .bt_rssi_type = COEX_BTRSSI_DBM,
        .ant_isolation = 15,
index 2fcdf70..fc9544f 100644 (file)
@@ -332,7 +332,8 @@ static void rtw_wow_fw_security_type_iter(struct ieee80211_hw *hw,
                key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
                break;
        default:
-               rtw_err(rtwdev, "Unsupported key type for wowlan mode\n");
+               rtw_err(rtwdev, "Unsupported key type for wowlan mode: %#x\n",
+                       key->cipher);
                hw_key_type = 0;
                break;
        }
@@ -555,7 +556,7 @@ static int rtw_wow_leave_no_link_ps(struct rtw_dev *rtwdev)
        int ret = 0;
 
        if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) {
-               if (rtw_fw_lps_deep_mode)
+               if (rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE)
                        rtw_leave_lps_deep(rtwdev);
        } else {
                if (test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags)) {
@@ -616,7 +617,8 @@ static int rtw_wow_enter_ps(struct rtw_dev *rtwdev)
 
        if (rtw_wow_mgd_linked(rtwdev))
                ret = rtw_wow_enter_linked_ps(rtwdev);
-       else if (rtw_wow_no_link(rtwdev) && rtw_fw_lps_deep_mode)
+       else if (rtw_wow_no_link(rtwdev) &&
+                rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE)
                ret = rtw_wow_enter_no_link_ps(rtwdev);
 
        return ret;
index 3f7e3cf..ce98921 100644 (file)
@@ -248,7 +248,8 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
                        rsi_set_len_qno(&data_desc->len_qno,
                                        (skb->len - FRAME_DESC_SZ),
                                        RSI_WIFI_MGMT_Q);
-               if ((skb->len - header_size) == EAPOL4_PACKET_LEN) {
+               if (((skb->len - header_size) == EAPOL4_PACKET_LEN) ||
+                   ((skb->len - header_size) == EAPOL4_PACKET_LEN - 2)) {
                        data_desc->misc_flags |=
                                RSI_DESC_REQUIRE_CFM_TO_HOST;
                        xtend_desc->confirm_frame_type = EAPOL4_CONFIRM;
index a7b8684..592e9da 100644 (file)
@@ -153,9 +153,7 @@ static void rsi_handle_interrupt(struct sdio_func *function)
        if (adapter->priv->fsm_state == FSM_FW_NOT_LOADED)
                return;
 
-       dev->sdio_irq_task = current;
-       rsi_interrupt_handler(adapter);
-       dev->sdio_irq_task = NULL;
+       rsi_set_event(&dev->rx_thread.event);
 }
 
 /**
@@ -1058,8 +1056,6 @@ static int rsi_probe(struct sdio_func *pfunction,
                rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__);
                goto fail_kill_thread;
        }
-       skb_queue_head_init(&sdev->rx_q.head);
-       sdev->rx_q.num_rx_pkts = 0;
 
        sdio_claim_host(pfunction);
        if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) {
index 7825c9a..8ace187 100644 (file)
@@ -60,39 +60,20 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word)
        return status;
 }
 
+static void rsi_rx_handler(struct rsi_hw *adapter);
+
 void rsi_sdio_rx_thread(struct rsi_common *common)
 {
        struct rsi_hw *adapter = common->priv;
        struct rsi_91x_sdiodev *sdev = adapter->rsi_dev;
-       struct sk_buff *skb;
-       int status;
 
        do {
                rsi_wait_event(&sdev->rx_thread.event, EVENT_WAIT_FOREVER);
                rsi_reset_event(&sdev->rx_thread.event);
+               rsi_rx_handler(adapter);
+       } while (!atomic_read(&sdev->rx_thread.thread_done));
 
-               while (true) {
-                       if (atomic_read(&sdev->rx_thread.thread_done))
-                               goto out;
-
-                       skb = skb_dequeue(&sdev->rx_q.head);
-                       if (!skb)
-                               break;
-                       if (sdev->rx_q.num_rx_pkts > 0)
-                               sdev->rx_q.num_rx_pkts--;
-                       status = rsi_read_pkt(common, skb->data, skb->len);
-                       if (status) {
-                               rsi_dbg(ERR_ZONE, "Failed to read the packet\n");
-                               dev_kfree_skb(skb);
-                               break;
-                       }
-                       dev_kfree_skb(skb);
-               }
-       } while (1);
-
-out:
        rsi_dbg(INFO_ZONE, "%s: Terminated SDIO RX thread\n", __func__);
-       skb_queue_purge(&sdev->rx_q.head);
        atomic_inc(&sdev->rx_thread.thread_done);
        complete_and_exit(&sdev->rx_thread.completion, 0);
 }
@@ -113,10 +94,6 @@ static int rsi_process_pkt(struct rsi_common *common)
        u32 rcv_pkt_len = 0;
        int status = 0;
        u8 value = 0;
-       struct sk_buff *skb;
-
-       if (dev->rx_q.num_rx_pkts >= RSI_MAX_RX_PKTS)
-               return 0;
 
        num_blks = ((adapter->interrupt_status & 1) |
                        ((adapter->interrupt_status >> RECV_NUM_BLOCKS) << 1));
@@ -144,22 +121,19 @@ static int rsi_process_pkt(struct rsi_common *common)
 
        rcv_pkt_len = (num_blks * 256);
 
-       skb = dev_alloc_skb(rcv_pkt_len);
-       if (!skb)
-               return -ENOMEM;
-
-       status = rsi_sdio_host_intf_read_pkt(adapter, skb->data, rcv_pkt_len);
+       status = rsi_sdio_host_intf_read_pkt(adapter, dev->pktbuffer,
+                                            rcv_pkt_len);
        if (status) {
                rsi_dbg(ERR_ZONE, "%s: Failed to read packet from card\n",
                        __func__);
-               dev_kfree_skb(skb);
                return status;
        }
-       skb_put(skb, rcv_pkt_len);
-       skb_queue_tail(&dev->rx_q.head, skb);
-       dev->rx_q.num_rx_pkts++;
 
-       rsi_set_event(&dev->rx_thread.event);
+       status = rsi_read_pkt(common, dev->pktbuffer, rcv_pkt_len);
+       if (status) {
+               rsi_dbg(ERR_ZONE, "Failed to read the packet\n");
+               return status;
+       }
 
        return 0;
 }
@@ -251,18 +225,17 @@ int rsi_init_sdio_slave_regs(struct rsi_hw *adapter)
 }
 
 /**
- * rsi_interrupt_handler() - This function read and process SDIO interrupts.
+ * rsi_rx_handler() - Read and process SDIO interrupts.
  * @adapter: Pointer to the adapter structure.
  *
  * Return: None.
  */
-void rsi_interrupt_handler(struct rsi_hw *adapter)
+static void rsi_rx_handler(struct rsi_hw *adapter)
 {
        struct rsi_common *common = adapter->priv;
        struct rsi_91x_sdiodev *dev =
                (struct rsi_91x_sdiodev *)adapter->rsi_dev;
        int status;
-       enum sdio_interrupt_type isr_type;
        u8 isr_status = 0;
        u8 fw_status = 0;
 
@@ -293,73 +266,69 @@ void rsi_interrupt_handler(struct rsi_hw *adapter)
                        __func__, isr_status, (1 << MSDU_PKT_PENDING),
                        (1 << FW_ASSERT_IND));
 
-               do {
-                       RSI_GET_SDIO_INTERRUPT_TYPE(isr_status, isr_type);
-
-                       switch (isr_type) {
-                       case BUFFER_AVAILABLE:
-                               status = rsi_sdio_check_buffer_status(adapter,
-                                                                     0);
-                               if (status < 0)
-                                       rsi_dbg(ERR_ZONE,
-                                               "%s: Failed to check buffer status\n",
-                                               __func__);
-                               rsi_sdio_ack_intr(common->priv,
-                                                 (1 << PKT_BUFF_AVAILABLE));
-                               rsi_set_event(&common->tx_thread.event);
-
-                               rsi_dbg(ISR_ZONE,
-                                       "%s: ==> BUFFER_AVAILABLE <==\n",
-                                       __func__);
-                               dev->buff_status_updated = true;
-                               break;
-
-                       case FIRMWARE_ASSERT_IND:
+               if (isr_status & BIT(PKT_BUFF_AVAILABLE)) {
+                       status = rsi_sdio_check_buffer_status(adapter, 0);
+                       if (status < 0)
                                rsi_dbg(ERR_ZONE,
-                                       "%s: ==> FIRMWARE Assert <==\n",
+                                       "%s: Failed to check buffer status\n",
                                        __func__);
-                               status = rsi_sdio_read_register(common->priv,
+                       rsi_sdio_ack_intr(common->priv,
+                                         BIT(PKT_BUFF_AVAILABLE));
+                       rsi_set_event(&common->tx_thread.event);
+
+                       rsi_dbg(ISR_ZONE, "%s: ==> BUFFER_AVAILABLE <==\n",
+                               __func__);
+                       dev->buff_status_updated = true;
+
+                       isr_status &= ~BIT(PKT_BUFF_AVAILABLE);
+               }
+
+               if (isr_status & BIT(FW_ASSERT_IND)) {
+                       rsi_dbg(ERR_ZONE, "%s: ==> FIRMWARE Assert <==\n",
+                               __func__);
+                       status = rsi_sdio_read_register(common->priv,
                                                        SDIO_FW_STATUS_REG,
                                                        &fw_status);
-                               if (status) {
-                                       rsi_dbg(ERR_ZONE,
-                                               "%s: Failed to read f/w reg\n",
-                                               __func__);
-                               } else {
-                                       rsi_dbg(ERR_ZONE,
-                                               "%s: Firmware Status is 0x%x\n",
-                                               __func__ , fw_status);
-                                       rsi_sdio_ack_intr(common->priv,
-                                                         (1 << FW_ASSERT_IND));
-                               }
-
-                               common->fsm_state = FSM_CARD_NOT_READY;
-                               break;
-
-                       case MSDU_PACKET_PENDING:
-                               rsi_dbg(ISR_ZONE, "Pkt pending interrupt\n");
-                               dev->rx_info.total_sdio_msdu_pending_intr++;
-
-                               status = rsi_process_pkt(common);
-                               if (status) {
-                                       rsi_dbg(ERR_ZONE,
-                                               "%s: Failed to read pkt\n",
-                                               __func__);
-                                       mutex_unlock(&common->rx_lock);
-                                       return;
-                               }
-                               break;
-                       default:
-                               rsi_sdio_ack_intr(common->priv, isr_status);
-                               dev->rx_info.total_sdio_unknown_intr++;
-                               isr_status = 0;
-                               rsi_dbg(ISR_ZONE,
-                                       "Unknown Interrupt %x\n",
-                                       isr_status);
-                               break;
+                       if (status) {
+                               rsi_dbg(ERR_ZONE,
+                                       "%s: Failed to read f/w reg\n",
+                                       __func__);
+                       } else {
+                               rsi_dbg(ERR_ZONE,
+                                       "%s: Firmware Status is 0x%x\n",
+                                       __func__, fw_status);
+                               rsi_sdio_ack_intr(common->priv,
+                                                 BIT(FW_ASSERT_IND));
                        }
-                       isr_status ^= BIT(isr_type - 1);
-               } while (isr_status);
+
+                       common->fsm_state = FSM_CARD_NOT_READY;
+
+                       isr_status &= ~BIT(FW_ASSERT_IND);
+               }
+
+               if (isr_status & BIT(MSDU_PKT_PENDING)) {
+                       rsi_dbg(ISR_ZONE, "Pkt pending interrupt\n");
+                       dev->rx_info.total_sdio_msdu_pending_intr++;
+
+                       status = rsi_process_pkt(common);
+                       if (status) {
+                               rsi_dbg(ERR_ZONE, "%s: Failed to read pkt\n",
+                                       __func__);
+                               mutex_unlock(&common->rx_lock);
+                               return;
+                       }
+
+                       isr_status &= ~BIT(MSDU_PKT_PENDING);
+               }
+
+               if (isr_status) {
+                       rsi_sdio_ack_intr(common->priv, isr_status);
+                       dev->rx_info.total_sdio_unknown_intr++;
+                       isr_status = 0;
+                       rsi_dbg(ISR_ZONE, "Unknown Interrupt %x\n",
+                               isr_status);
+               }
+
                mutex_unlock(&common->rx_lock);
        } while (1);
 }
index a62d41c..a4a533c 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2014 Redpine Signals Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -75,7 +75,7 @@ static int rsi_usb_card_write(struct rsi_hw *adapter,
  * rsi_write_multiple() - This function writes multiple bytes of information
  *                       to the USB card.
  * @adapter: Pointer to the adapter structure.
- * @addr: Address of the register.
+ * @endpoint: Type of endpoint.
  * @data: Pointer to the data that has to be written.
  * @count: Number of multiple bytes to be written.
  *
@@ -313,6 +313,8 @@ static void rsi_rx_urb_kill(struct rsi_hw *adapter, u8 ep_num)
 /**
  * rsi_rx_urb_submit() - This function submits the given URB to the USB stack.
  * @adapter: Pointer to the adapter structure.
+ * @ep_num: Endpoint number.
+ * @mem_flags: The type of memory to allocate.
  *
  * Return: 0 on success, a negative error code on failure.
  */
@@ -741,24 +743,24 @@ static int rsi_reset_card(struct rsi_hw *adapter)
                if (ret < 0)
                        goto fail;
        } else {
-               if ((rsi_usb_master_reg_write(adapter,
-                                             NWP_WWD_INTERRUPT_TIMER,
-                                             NWP_WWD_INT_TIMER_CLKS,
-                                             RSI_9116_REG_SIZE)) < 0) {
+               ret = rsi_usb_master_reg_write(adapter,
+                                              NWP_WWD_INTERRUPT_TIMER,
+                                              NWP_WWD_INT_TIMER_CLKS,
+                                              RSI_9116_REG_SIZE);
+               if (ret < 0)
                        goto fail;
-               }
-               if ((rsi_usb_master_reg_write(adapter,
-                                             NWP_WWD_SYSTEM_RESET_TIMER,
-                                             NWP_WWD_SYS_RESET_TIMER_CLKS,
-                                             RSI_9116_REG_SIZE)) < 0) {
+               ret = rsi_usb_master_reg_write(adapter,
+                                              NWP_WWD_SYSTEM_RESET_TIMER,
+                                              NWP_WWD_SYS_RESET_TIMER_CLKS,
+                                              RSI_9116_REG_SIZE);
+               if (ret < 0)
                        goto fail;
-               }
-               if ((rsi_usb_master_reg_write(adapter,
-                                             NWP_WWD_MODE_AND_RSTART,
-                                             NWP_WWD_TIMER_DISABLE,
-                                             RSI_9116_REG_SIZE)) < 0) {
+               ret = rsi_usb_master_reg_write(adapter,
+                                              NWP_WWD_MODE_AND_RSTART,
+                                              NWP_WWD_TIMER_DISABLE,
+                                              RSI_9116_REG_SIZE);
+               if (ret < 0)
                        goto fail;
-               }
        }
 
        rsi_dbg(INFO_ZONE, "Reset card done\n");
index b1687d2..4ffcdde 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2014 Redpine Signals Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
index 9afc1d0..1c75626 100644 (file)
@@ -107,11 +107,6 @@ struct receive_info {
        u32 buf_available_counter;
 };
 
-struct rsi_sdio_rx_q {
-       u8 num_rx_pkts;
-       struct sk_buff_head head;
-};
-
 struct rsi_91x_sdiodev {
        struct sdio_func *pfunction;
        struct task_struct *sdio_irq_task;
@@ -124,11 +119,10 @@ struct rsi_91x_sdiodev {
        u16 tx_blk_size;
        u8 write_fail;
        bool buff_status_updated;
-       struct rsi_sdio_rx_q rx_q;
        struct rsi_thread rx_thread;
+       u8 pktbuffer[8192] __aligned(4);
 };
 
-void rsi_interrupt_handler(struct rsi_hw *adapter);
 int rsi_init_sdio_slave_regs(struct rsi_hw *adapter);
 int rsi_sdio_read_register(struct rsi_hw *adapter, u32 addr, u8 *data);
 int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, u8 *pkt, u32 length);
index 02efe84..c364a39 100644 (file)
@@ -85,7 +85,7 @@ int cw1200_register_bh(struct cw1200_common *priv)
 
 void cw1200_unregister_bh(struct cw1200_common *priv)
 {
-       atomic_add(1, &priv->bh_term);
+       atomic_inc(&priv->bh_term);
        wake_up(&priv->bh_wq);
 
        flush_workqueue(priv->bh_workqueue);
@@ -107,7 +107,7 @@ void cw1200_irq_handler(struct cw1200_common *priv)
        if (/* WARN_ON */(priv->bh_error))
                return;
 
-       if (atomic_add_return(1, &priv->bh_rx) == 1)
+       if (atomic_inc_return(&priv->bh_rx) == 1)
                wake_up(&priv->bh_wq);
 }
 EXPORT_SYMBOL_GPL(cw1200_irq_handler);
@@ -120,7 +120,7 @@ void cw1200_bh_wakeup(struct cw1200_common *priv)
                return;
        }
 
-       if (atomic_add_return(1, &priv->bh_tx) == 1)
+       if (atomic_inc_return(&priv->bh_tx) == 1)
                wake_up(&priv->bh_wq);
 }
 
@@ -382,7 +382,7 @@ static int cw1200_bh_tx_helper(struct cw1200_common *priv,
        BUG_ON(tx_len < sizeof(*wsm));
        BUG_ON(__le16_to_cpu(wsm->len) != tx_len);
 
-       atomic_add(1, &priv->bh_tx);
+       atomic_inc(&priv->bh_tx);
 
        tx_len = priv->hwbus_ops->align_size(
                priv->hwbus_priv, tx_len);
@@ -537,7 +537,7 @@ static int cw1200_bh(void *arg)
                        pr_debug("[BH] Device resume.\n");
                        atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
                        wake_up(&priv->bh_evt_wq);
-                       atomic_add(1, &priv->bh_rx);
+                       atomic_inc(&priv->bh_rx);
                        goto done;
                }
 
index f7fe56a..326b1cc 100644 (file)
@@ -381,6 +381,7 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
                                    CW1200_LINK_ID_MAX,
                                    cw1200_skb_dtor,
                                    priv)) {
+               destroy_workqueue(priv->workqueue);
                ieee80211_free_hw(hw);
                return NULL;
        }
@@ -392,6 +393,7 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
                        for (; i > 0; i--)
                                cw1200_queue_deinit(&priv->tx_queue[i - 1]);
                        cw1200_queue_stats_deinit(&priv->tx_queue_stats);
+                       destroy_workqueue(priv->workqueue);
                        ieee80211_free_hw(hw);
                        return NULL;
                }
index d9b6147..99624dd 100644 (file)
@@ -1139,7 +1139,7 @@ static int wsm_cmd_send(struct cw1200_common *priv,
                        pr_err("Outstanding outgoing frames:  %d\n", priv->hw_bufs_used);
 
                        /* Kill BH thread to report the error to the top layer. */
-                       atomic_add(1, &priv->bh_term);
+                       atomic_inc(&priv->bh_term);
                        wake_up(&priv->bh_wq);
                        ret = -ETIMEDOUT;
                }
@@ -1160,7 +1160,7 @@ done:
 void wsm_lock_tx(struct cw1200_common *priv)
 {
        wsm_cmd_lock(priv);
-       if (atomic_add_return(1, &priv->tx_lock) == 1) {
+       if (atomic_inc_return(&priv->tx_lock) == 1) {
                if (wsm_flush_tx(priv))
                        pr_debug("[WSM] TX is locked.\n");
        }
@@ -1169,7 +1169,7 @@ void wsm_lock_tx(struct cw1200_common *priv)
 
 void wsm_lock_tx_async(struct cw1200_common *priv)
 {
-       if (atomic_add_return(1, &priv->tx_lock) == 1)
+       if (atomic_inc_return(&priv->tx_lock) == 1)
                pr_debug("[WSM] TX is locked (async).\n");
 }
 
@@ -1223,7 +1223,7 @@ bool wsm_flush_tx(struct cw1200_common *priv)
 void wsm_unlock_tx(struct cw1200_common *priv)
 {
        int tx_lock;
-       tx_lock = atomic_sub_return(1, &priv->tx_lock);
+       tx_lock = atomic_dec_return(&priv->tx_lock);
        BUG_ON(tx_lock < 0);
 
        if (tx_lock == 0) {
index 9547aea..e1095b8 100644 (file)
@@ -63,7 +63,7 @@ out:
  *
  * @wl: wl struct
  * @buf: buffer containing the command, with all headers, must work with dma
- * @len: length of the buffer
+ * @buf_len: length of the buffer
  * @answer: is answer needed
  */
 int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer)
index d48746e..a1b778a 100644 (file)
@@ -39,7 +39,7 @@ static const struct file_operations name## _ops = {                   \
 
 #define DEBUGFS_ADD(name, parent)                                      \
        wl->debugfs.name = debugfs_create_file(#name, 0400, parent,     \
-                                              wl, &name## _ops);       \
+                                              wl, &name## _ops)        \
 
 #define DEBUGFS_DEL(name)                                              \
        do {                                                            \
index 6863fd5..122c7a4 100644 (file)
@@ -2227,7 +2227,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
        switch (ieee80211_vif_type_p2p(vif)) {
        case NL80211_IFTYPE_P2P_CLIENT:
                wlvif->p2p = 1;
-               /* fall-through */
+               fallthrough;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_DEVICE:
                wlvif->bss_type = BSS_TYPE_STA_BSS;
@@ -2237,7 +2237,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
                break;
        case NL80211_IFTYPE_P2P_GO:
                wlvif->p2p = 1;
-               /* fall-through */
+               fallthrough;
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_MESH_POINT:
                wlvif->bss_type = BSS_TYPE_AP_BSS;
index 18c4d99..f26fc15 100644 (file)
@@ -391,7 +391,7 @@ static int wl12xx_spi_set_power(struct device *child, bool enable)
        return ret;
 }
 
-/**
+/*
  * wl12xx_spi_set_block_size
  *
  * This function is not needed for spi mode, but need to be present.
@@ -431,7 +431,6 @@ MODULE_DEVICE_TABLE(of, wlcore_spi_of_match_table);
 /**
  * wlcore_probe_of - DT node parsing.
  * @spi: SPI slave device parameters.
- * @res: resource parameters.
  * @glue: wl12xx SPI bus to slave device glue parameters.
  * @pdev_data: wlcore device parameters
  */
index 7ac1814..5cf0379 100644 (file)
@@ -100,7 +100,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
                                       struct bin_attribute *bin_attr,
                                       char *buffer, loff_t pos, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct wl1271 *wl = dev_get_drvdata(dev);
        ssize_t len;
        int ret;
index 026e88b..8ca5789 100644 (file)
@@ -134,7 +134,7 @@ static const struct {
 
 /**
  * iw_valid_channel - validate channel in regulatory domain
- * @reg_comain: regulatory domain
+ * @reg_domain: regulatory domain
  * @channel: channel to validate
  *
  * Returns 0 if invalid in the specified regulatory domain, non-zero if valid.
@@ -458,11 +458,9 @@ out:
 /**
  * wl3501_send_pkt - Send a packet.
  * @this: Card
- *
- * Send a packet.
- *
- * data = Ethernet raw frame.  (e.g. data[0] - data[5] is Dest MAC Addr,
+ * @data: Ethernet raw frame.  (e.g. data[0] - data[5] is Dest MAC Addr,
  *                                   data[6] - data[11] is Src MAC Addr)
+ * @len: Packet length
  * Ref: IEEE 802.11
  */
 static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len)
index 66367ab..5c4cd0e 100644 (file)
@@ -1711,11 +1711,6 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
                         count, USB_MAX_IOREAD16_COUNT);
                return -EINVAL;
        }
-       if (in_atomic()) {
-               dev_dbg_f(zd_usb_dev(usb),
-                        "error: io in atomic context not supported\n");
-               return -EWOULDBLOCK;
-       }
        if (!usb_int_enabled(usb)) {
                dev_dbg_f(zd_usb_dev(usb),
                          "error: usb interrupt not enabled\n");
@@ -1882,11 +1877,6 @@ int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
                        count, USB_MAX_IOWRITE16_COUNT);
                return -EINVAL;
        }
-       if (in_atomic()) {
-               dev_dbg_f(zd_usb_dev(usb),
-                       "error: io in atomic context not supported\n");
-               return -EWOULDBLOCK;
-       }
 
        udev = zd_usb_to_usbdev(usb);
 
@@ -1966,11 +1956,6 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
        int i, req_len, actual_req_len;
        u16 bit_value_template;
 
-       if (in_atomic()) {
-               dev_dbg_f(zd_usb_dev(usb),
-                       "error: io in atomic context not supported\n");
-               return -EWOULDBLOCK;
-       }
        if (bits < USB_MIN_RFWRITE_BIT_COUNT) {
                dev_dbg_f(zd_usb_dev(usb),
                        "error: bits %d are smaller than"