summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/80211.tmpl2
-rw-r--r--drivers/bcma/driver_chipcommon.c5
-rw-r--r--drivers/bcma/driver_chipcommon_pmu.c34
-rw-r--r--drivers/bcma/scan.c16
-rw-r--r--drivers/bcma/sprom.c1
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c8
-rw-r--r--drivers/net/wireless/ath/ar5523/ar5523.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c31
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c7
-rw-r--r--drivers/net/wireless/ath/carl9170/carl9170.h8
-rw-r--r--drivers/net/wireless/ath/carl9170/debug.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c4
-rw-r--r--drivers/net/wireless/ath/carl9170/phy.c81
-rw-r--r--drivers/net/wireless/ath/key.c9
-rw-r--r--drivers/net/wireless/b43/b43.h2
-rw-r--r--drivers/net/wireless/b43/main.c23
-rw-r--r--drivers/net/wireless/b43/phy_lp.c12
-rw-r--r--drivers/net/wireless/b43/phy_n.c6
-rw-r--r--drivers/net/wireless/b43/radio_2056.c6
-rw-r--r--drivers/net/wireless/b43/sdio.h4
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c4
-rw-r--r--drivers/net/wireless/b43/tables_phy_lcn.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c30
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c60
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h33
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h13
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c50
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h21
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c116
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c117
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.c25
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.c1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c1801
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c190
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h14
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c495
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h11
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/aiutils.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/d11.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c87
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c362
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.h25
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c40
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c35
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c14
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pmu.c54
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pmu.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pub.h17
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_wifi.h28
-rw-r--r--drivers/net/wireless/iwlegacy/common.c3
-rw-r--r--drivers/net/wireless/iwlegacy/common.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-test.c3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/bt-coex.c21
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c10
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h6
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h38
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c23
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c30
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c29
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h15
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c136
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c36
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c7
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/quota.c3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c38
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c10
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c5
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c8
-rw-r--r--drivers/net/wireless/mwifiex/11ac.c41
-rw-r--r--drivers/net/wireless/mwifiex/11ac.h17
-rw-r--r--drivers/net/wireless/mwifiex/11n.c22
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c12
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c35
-rw-r--r--drivers/net/wireless/mwifiex/decl.h11
-rw-r--r--drivers/net/wireless/mwifiex/fw.h11
-rw-r--r--drivers/net/wireless/mwifiex/init.c6
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h8
-rw-r--r--drivers/net/wireless/mwifiex/join.c23
-rw-r--r--drivers/net/wireless/mwifiex/main.h13
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c47
-rw-r--r--drivers/net/wireless/mwifiex/scan.c11
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c4
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c4
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c3
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c55
-rw-r--r--drivers/net/wireless/mwifiex/util.c1
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c76
-rw-r--r--drivers/net/wireless/mwl8k.c10
-rw-r--r--drivers/net/wireless/p54/main.c2
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig7
-rw-r--r--drivers/net/wireless/rt2x00/Makefile1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c92
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h19
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mmio.c216
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mmio.h119
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c174
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h88
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c1
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig9
-rw-r--r--drivers/net/wireless/rtlwifi/Makefile1
-rw-r--r--drivers/net/wireless/rtlwifi/base.c379
-rw-r--r--drivers/net/wireless/rtlwifi/base.h14
-rw-r--r--drivers/net/wireless/rtlwifi/core.c215
-rw-r--r--drivers/net/wireless/rtlwifi/debug.c5
-rw-r--r--drivers/net/wireless/rtlwifi/debug.h13
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.c53
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.h1
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c150
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h2
-rw-r--r--drivers/net/wireless/rtlwifi/ps.c330
-rw-r--r--drivers/net/wireless/rtlwifi/ps.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/Makefile16
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/def.h324
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.c1794
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.h326
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/fw.c830
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/fw.h301
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/hw.c2530
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/hw.h68
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/led.c157
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/led.h38
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/phy.c2202
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/phy.h236
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c109
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h327
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c140
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h97
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/reg.h2258
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/rf.c467
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/rf.h46
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/sw.c400
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/sw.h36
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/table.c643
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/table.h47
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/trx.c817
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/trx.h795
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c101
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c99
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.c118
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.h4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/reg.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/sw.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.c324
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c20
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c32
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/hw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/phy.c40
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/reg.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/sw.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/def.h7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.c49
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.c150
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.h3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/phy.c61
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/phy.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/sw.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.c296
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/dm.c88
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/dm.h6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/fw.c97
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/fw.h7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hw.c70
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/led.c22
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/sw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/trx.c10
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c220
-rw-r--r--drivers/net/wireless/rtlwifi/usb.h5
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h221
-rw-r--r--drivers/net/wireless/ti/wl1251/sdio.c4
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c1
-rw-r--r--drivers/net/wireless/ti/wl12xx/wl12xx.h2
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c25
-rw-r--r--drivers/net/wireless/ti/wl18xx/reg.h29
-rw-r--r--drivers/net/wireless/ti/wl18xx/wl18xx.h4
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.c29
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.h16
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c32
-rw-r--r--drivers/net/wireless/ti/wlcore/debug.h33
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c3
-rw-r--r--drivers/net/wireless/ti/wlcore/event.c9
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c200
-rw-r--r--drivers/net/wireless/ti/wlcore/ps.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c39
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h3
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore_i.h29
-rw-r--r--drivers/ssb/pci.c23
-rw-r--r--include/linux/bcma/bcma.h54
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h3
-rw-r--r--include/linux/ssb/ssb.h54
-rw-r--r--include/linux/ssb/ssb_regs.h10
-rw-r--r--include/net/bluetooth/bluetooth.h12
-rw-r--r--include/net/bluetooth/hci.h21
-rw-r--r--include/net/bluetooth/hci_core.h28
-rw-r--r--include/net/bluetooth/rfcomm.h6
-rw-r--r--include/net/mac80211.h68
-rw-r--r--net/bluetooth/a2mp.c6
-rw-r--r--net/bluetooth/af_bluetooth.c15
-rw-r--r--net/bluetooth/bnep/sock.c4
-rw-r--r--net/bluetooth/cmtp/sock.c4
-rw-r--r--net/bluetooth/hci_conn.c4
-rw-r--r--net/bluetooth/hci_core.c727
-rw-r--r--net/bluetooth/hci_event.c605
-rw-r--r--net/bluetooth/hci_sock.c9
-rw-r--r--net/bluetooth/hci_sysfs.c4
-rw-r--r--net/bluetooth/hidp/core.c4
-rw-r--r--net/bluetooth/hidp/sock.c4
-rw-r--r--net/bluetooth/l2cap_sock.c4
-rw-r--r--net/bluetooth/mgmt.c680
-rw-r--r--net/bluetooth/rfcomm/core.c167
-rw-r--r--net/bluetooth/rfcomm/sock.c3
-rw-r--r--net/bluetooth/sco.c3
-rw-r--r--net/mac80211/cfg.c29
-rw-r--r--net/mac80211/debugfs_key.c10
-rw-r--r--net/mac80211/debugfs_netdev.c22
-rw-r--r--net/mac80211/driver-ops.h60
-rw-r--r--net/mac80211/ieee80211_i.h11
-rw-r--r--net/mac80211/iface.c17
-rw-r--r--net/mac80211/key.c129
-rw-r--r--net/mac80211/key.h15
-rw-r--r--net/mac80211/main.c22
-rw-r--r--net/mac80211/mesh.c5
-rw-r--r--net/mac80211/mlme.c12
-rw-r--r--net/mac80211/offchannel.c8
-rw-r--r--net/mac80211/pm.c6
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c24
-rw-r--r--net/mac80211/scan.c7
-rw-r--r--net/mac80211/sta_info.c54
-rw-r--r--net/mac80211/sta_info.h9
-rw-r--r--net/mac80211/trace.h35
-rw-r--r--net/mac80211/tx.c8
-rw-r--r--net/mac80211/util.c48
-rw-r--r--net/wireless/core.c4
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/sme.c4
258 files changed, 23444 insertions, 3956 deletions
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index 284ced7a228f..0f6a3edcd44b 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -437,7 +437,7 @@
</section>
!Finclude/net/mac80211.h ieee80211_get_buffered_bc
!Finclude/net/mac80211.h ieee80211_beacon_get
-!Finclude/net/mac80211.h ieee80211_sta_eosp_irqsafe
+!Finclude/net/mac80211.h ieee80211_sta_eosp
!Finclude/net/mac80211.h ieee80211_frame_release_type
!Finclude/net/mac80211.h ieee80211_sta_ps_transition
!Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 28fa50ad87be..036c6744b39b 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -25,13 +25,14 @@ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
return value;
}
-static u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc)
+u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc)
{
if (cc->capabilities & BCMA_CC_CAP_PMU)
return bcma_pmu_get_alp_clock(cc);
return 20000000;
}
+EXPORT_SYMBOL_GPL(bcma_chipco_get_alp_clock);
static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
{
@@ -213,6 +214,7 @@ u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
return res;
}
+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_out);
u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
{
@@ -225,6 +227,7 @@ u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
return res;
}
+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen);
/*
* If the bit is set to 0, chipcommon controlls this GPIO,
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index 932b101dee36..edca73af3cc0 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -174,19 +174,35 @@ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc)
struct bcma_bus *bus = cc->core->bus;
switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM4313:
+ case BCMA_CHIP_ID_BCM43224:
+ case BCMA_CHIP_ID_BCM43225:
+ case BCMA_CHIP_ID_BCM43227:
+ case BCMA_CHIP_ID_BCM43228:
+ case BCMA_CHIP_ID_BCM4331:
+ case BCMA_CHIP_ID_BCM43421:
+ case BCMA_CHIP_ID_BCM43428:
+ case BCMA_CHIP_ID_BCM43431:
case BCMA_CHIP_ID_BCM4716:
- case BCMA_CHIP_ID_BCM4748:
case BCMA_CHIP_ID_BCM47162:
- case BCMA_CHIP_ID_BCM4313:
- case BCMA_CHIP_ID_BCM5357:
+ case BCMA_CHIP_ID_BCM4748:
case BCMA_CHIP_ID_BCM4749:
+ case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM53572:
+ case BCMA_CHIP_ID_BCM6362:
/* always 20Mhz */
return 20000 * 1000;
- case BCMA_CHIP_ID_BCM5356:
case BCMA_CHIP_ID_BCM4706:
+ case BCMA_CHIP_ID_BCM5356:
/* always 25Mhz */
return 25000 * 1000;
+ case BCMA_CHIP_ID_BCM43460:
+ case BCMA_CHIP_ID_BCM4352:
+ case BCMA_CHIP_ID_BCM4360:
+ if (cc->status & BCMA_CC_CHIPST_4360_XTAL_40MZ)
+ return 40000 * 1000;
+ else
+ return 20000 * 1000;
default:
bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
@@ -373,7 +389,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
- tmp = 1 << 10;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
case BCMA_CHIP_ID_BCM4331:
@@ -394,7 +410,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
0x03000a08);
}
- tmp = 1 << 10;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
case BCMA_CHIP_ID_BCM43224:
@@ -427,7 +443,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
0x88888815);
}
- tmp = 1 << 10;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
case BCMA_CHIP_ID_BCM4716:
@@ -461,7 +477,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
0x88888815);
}
- tmp = 3 << 9;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD | BCMA_CC_PMU_CTL_NOILPONW;
break;
case BCMA_CHIP_ID_BCM43227:
@@ -497,7 +513,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
0x88888815);
}
- tmp = 1 << 10;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
default:
bcma_err(bus, "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 8d0b57164018..bca9c80056fe 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -137,19 +137,19 @@ static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
addr);
}
-static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr)
+static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = readl(*eromptr);
(*eromptr)++;
return ent;
}
-static void bcma_erom_push_ent(u32 **eromptr)
+static void bcma_erom_push_ent(u32 __iomem **eromptr)
{
(*eromptr)--;
}
-static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
+static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = bcma_erom_get_ent(bus, eromptr);
if (!(ent & SCAN_ER_VALID))
@@ -159,14 +159,14 @@ static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
return ent;
}
-static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr)
+static bool bcma_erom_is_end(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = bcma_erom_get_ent(bus, eromptr);
bcma_erom_push_ent(eromptr);
return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
}
-static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
+static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = bcma_erom_get_ent(bus, eromptr);
bcma_erom_push_ent(eromptr);
@@ -175,7 +175,7 @@ static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
}
-static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
+static void bcma_erom_skip_component(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent;
while (1) {
@@ -189,7 +189,7 @@ static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
bcma_erom_push_ent(eromptr);
}
-static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
+static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = bcma_erom_get_ent(bus, eromptr);
if (!(ent & SCAN_ER_VALID))
@@ -199,7 +199,7 @@ static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
return ent;
}
-static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
+static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
u32 type, u8 port)
{
u32 addrl, addrh, sizel, sizeh = 0;
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index 4adf9ef9a113..8934298a638d 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -217,6 +217,7 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
}
SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
+ SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
SSB_SPROM4_TXPID2G0_SHIFT);
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 9959d4cb23dc..1cb51839912d 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -83,8 +83,8 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
- .helper = "sd8688_helper.bin",
- .firmware = "sd8688.bin",
+ .helper = "mrvl/sd8688_helper.bin",
+ .firmware = "mrvl/sd8688.bin",
.reg = &btmrvl_reg_8688,
.sd_blksz_fw_dl = 64,
};
@@ -1185,7 +1185,7 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE("sd8688_helper.bin");
-MODULE_FIRMWARE("sd8688.bin");
+MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
+MODULE_FIRMWARE("mrvl/sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
index 7157f7d311c5..afd1e36d308f 100644
--- a/drivers/net/wireless/ath/ar5523/ar5523.c
+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -1091,7 +1091,7 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return ret;
}
-static void ar5523_flush(struct ieee80211_hw *hw, bool drop)
+static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct ar5523 *ar = hw->priv;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index c55e5bbafc46..9f589744a9f9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -731,7 +731,8 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in %d ms; noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
return false;
}
REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
@@ -745,7 +746,8 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in %d ms; noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
return false;
}
@@ -841,7 +843,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in %d ms; noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index f76c3ca07a45..639ba7d18ea4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -1126,7 +1126,8 @@ skip_tx_iqcal:
ar9003_hw_rtt_disable(ah);
ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in %d ms; noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 67a2a4b3b883..e6307b86363a 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -2072,7 +2072,7 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_modal_eeprom);
sc->rfs_chan_spec_scan = relay_open("spectral_scan",
sc->debug.debugfs_phy,
- 262144, 4, &rfs_spec_scan_cb,
+ 1024, 256, &rfs_spec_scan_cb,
NULL);
debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c
index ecc81792f2dc..508f8b33f0ef 100644
--- a/drivers/net/wireless/ath/ath9k/dfs.c
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
@@ -193,9 +193,7 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
DFS_STAT_INC(sc, pulses_processed);
if (pd != NULL && pd->add_pulse(pd, &pe)) {
DFS_STAT_INC(sc, radar_detected);
- /*
- * TODO: forward radar event to DFS management layer
- */
+ ieee80211_radar_detected(sc->hw);
}
}
}
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c
index 55d28072adeb..b7611b7bbe43 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
@@ -105,6 +105,24 @@ static ssize_t write_file_dfs(struct file *file, const char __user *user_buf,
return count;
}
+static ssize_t write_file_simulate_radar(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+
+ ieee80211_radar_detected(sc->hw);
+
+ return count;
+}
+
+static const struct file_operations fops_simulate_radar = {
+ .write = write_file_simulate_radar,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static const struct file_operations fops_dfs_stats = {
.read = read_file_dfs,
.write = write_file_dfs,
@@ -117,4 +135,6 @@ void ath9k_dfs_init_debug(struct ath_softc *sc)
{
debugfs_create_file("dfs_stats", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_dfs_stats);
+ debugfs_create_file("dfs_simulate_radar", S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_simulate_radar);
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 4fa2bb167050..3473a797651a 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2380,8 +2380,11 @@ static bool ath9k_hw_dfs_tested(struct ath_hw *ah)
{
switch (ah->hw_version.macVersion) {
+ /* for temporary testing DFS with 9280 */
+ case AR_SREV_VERSION_9280:
/* AR9580 will likely be our first target to get testing on */
case AR_SREV_VERSION_9580:
+ return true;
default:
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index af932c9444de..3be2eb0da84a 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -319,6 +319,10 @@ static void ath9k_reg_notifier(struct wiphy *wiphy,
ath9k_ps_wakeup(sc);
ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
+ /* synchronize DFS detector if regulatory domain changed */
+ if (sc->dfs_detector != NULL)
+ sc->dfs_detector->set_dfs_domain(sc->dfs_detector,
+ request->dfs_region);
ath9k_ps_restore(sc);
}
}
@@ -727,12 +731,28 @@ static const struct ieee80211_iface_limit if_limits[] = {
BIT(NL80211_IFTYPE_P2P_GO) },
};
-static const struct ieee80211_iface_combination if_comb = {
- .limits = if_limits,
- .n_limits = ARRAY_SIZE(if_limits),
- .max_interfaces = 2048,
- .num_different_channels = 1,
- .beacon_int_infra_match = true,
+
+static const struct ieee80211_iface_limit if_dfs_limits[] = {
+ { .max = 1, .types = BIT(NL80211_IFTYPE_AP) },
+};
+
+static const struct ieee80211_iface_combination if_comb[] = {
+ {
+ .limits = if_limits,
+ .n_limits = ARRAY_SIZE(if_limits),
+ .max_interfaces = 2048,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+ },
+ {
+ .limits = if_dfs_limits,
+ .n_limits = ARRAY_SIZE(if_dfs_limits),
+ .max_interfaces = 1,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+ .radar_detect_widths = BIT(NL80211_CHAN_NO_HT) |
+ BIT(NL80211_CHAN_HT20),
+ }
};
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
@@ -763,8 +783,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
- hw->wiphy->iface_combinations = &if_comb;
- hw->wiphy->n_iface_combinations = 1;
+ hw->wiphy->iface_combinations = if_comb;
+ hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
if (AR_SREV_5416(sc->sc_ah))
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 6e66f9c6782b..1bf52c88004a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -280,6 +280,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
if (r) {
ath_err(common,
"Unable to reset channel, reset status %d\n", r);
+
+ ath9k_hw_enable_interrupts(ah);
+ ath9k_queue_reset(sc, RESET_TYPE_BB_HANG);
+
goto out;
}
@@ -1245,10 +1249,27 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (old_pos >= 0)
ath_update_survey_nf(sc, old_pos);
- /* perform spectral scan if requested. */
- if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN)
- ath9k_spectral_scan_trigger(hw);
-
+ /*
+ * Enable radar pulse detection if on a DFS channel. Spectral
+ * scanning and radar detection can not be used concurrently.
+ */
+ if (hw->conf.radar_enabled) {
+ u32 rxfilter;
+
+ /* set HW specific DFS configuration */
+ ath9k_hw_set_radar_params(ah);
+ rxfilter = ath9k_hw_getrxfilter(ah);
+ rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
+ ATH9K_RX_FILTER_PHYERR;
+ ath9k_hw_setrxfilter(ah, rxfilter);
+ ath_dbg(common, DFS, "DFS enabled at freq %d\n",
+ curchan->center_freq);
+ } else {
+ /* perform spectral scan if requested. */
+ if (sc->scanning &&
+ sc->spectral_mode == SPECTRAL_CHANSCAN)
+ ath9k_spectral_scan_trigger(hw);
+ }
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -1745,7 +1766,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
mutex_unlock(&sc->mutex);
}
-static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
+static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index ee156e543147..ee7ca5aecdb0 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -381,6 +381,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
| ATH9K_RX_FILTER_MCAST;
+ /* if operating on a DFS channel, enable radar pulse detection */
+ if (sc->hw->conf.radar_enabled)
+ rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR;
+
if (sc->rx.rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
@@ -1228,6 +1232,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
rxs->mactime += 0x100000000ULL;
+ if (rs.rs_phyerr == ATH9K_PHYERR_RADAR)
+ ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime);
+
if (rs.rs_status & ATH9K_RXERR_PHY) {
if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) {
RX_STAT_INC(rx_spectral);
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 25599741cd8a..9dce106cd6d4 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -70,12 +70,6 @@
static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 3, 2, 1, 0 };
-enum carl9170_rf_init_mode {
- CARL9170_RFI_NONE,
- CARL9170_RFI_WARM,
- CARL9170_RFI_COLD,
-};
-
#define CARL9170_MAX_RX_BUFFER_SIZE 8192
enum carl9170_device_state {
@@ -599,7 +593,7 @@ int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state);
/* PHY / RF */
int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
- enum nl80211_channel_type bw, enum carl9170_rf_init_mode rfi);
+ enum nl80211_channel_type bw);
int carl9170_get_noisefloor(struct ar9170 *ar);
/* FW */
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
index 93fe6003a493..40109be81f7c 100644
--- a/drivers/net/wireless/ath/carl9170/debug.c
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -655,7 +655,7 @@ static ssize_t carl9170_debugfs_bug_write(struct ar9170 *ar, const char *buf,
case 'P':
err = carl9170_set_channel(ar, ar->hw->conf.channel,
- ar->hw->conf.channel_type, CARL9170_RFI_COLD);
+ ar->hw->conf.channel_type);
if (err < 0)
count = err;
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index f293b3ff4756..699c557bc2c7 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -939,7 +939,7 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
goto out;
err = carl9170_set_channel(ar, hw->conf.channel,
- hw->conf.channel_type, CARL9170_RFI_NONE);
+ hw->conf.channel_type);
if (err)
goto out;
@@ -1703,7 +1703,7 @@ found:
return 0;
}
-static void carl9170_op_flush(struct ieee80211_hw *hw, bool drop)
+static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct ar9170 *ar = hw->priv;
unsigned int vid;
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index b72c09cf43a4..07f82234c860 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1569,16 +1569,14 @@ static enum carl9170_bw nl80211_to_carl(enum nl80211_channel_type type)
}
int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
- enum nl80211_channel_type _bw,
- enum carl9170_rf_init_mode rfi)
+ enum nl80211_channel_type _bw)
{
const struct carl9170_phy_freq_params *freqpar;
struct carl9170_rf_init_result rf_res;
struct carl9170_rf_init rf;
- u32 cmd, tmp, offs = 0, new_ht = 0;
+ u32 tmp, offs = 0, new_ht = 0;
int err;
enum carl9170_bw bw;
- bool warm_reset;
struct ieee80211_channel *old_channel = NULL;
bw = nl80211_to_carl(_bw);
@@ -1592,51 +1590,27 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
/* may be NULL at first setup */
if (ar->channel) {
old_channel = ar->channel;
- warm_reset = (old_channel->band != channel->band) ||
- (old_channel->center_freq ==
- channel->center_freq) ||
- (ar->ht_settings != new_ht);
-
ar->channel = NULL;
- } else {
- warm_reset = true;
}
- /* HW workaround */
- if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] &&
- channel->center_freq <= 2417)
- warm_reset = true;
-
- if (rfi != CARL9170_RFI_NONE || warm_reset) {
- u32 val;
-
- if (rfi == CARL9170_RFI_COLD)
- val = AR9170_PWR_RESET_BB_COLD_RESET;
- else
- val = AR9170_PWR_RESET_BB_WARM_RESET;
-
- /* warm/cold reset BB/ADDA */
- err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, val);
- if (err)
- return err;
-
- err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, 0x0);
- if (err)
- return err;
+ /* cold reset BB/ADDA */
+ err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET,
+ AR9170_PWR_RESET_BB_COLD_RESET);
+ if (err)
+ return err;
- err = carl9170_init_phy(ar, channel->band);
- if (err)
- return err;
+ err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, 0x0);
+ if (err)
+ return err;
- err = carl9170_init_rf_banks_0_7(ar,
- channel->band == IEEE80211_BAND_5GHZ);
- if (err)
- return err;
+ err = carl9170_init_phy(ar, channel->band);
+ if (err)
+ return err;
- cmd = CARL9170_CMD_RF_INIT;
- } else {
- cmd = CARL9170_CMD_FREQUENCY;
- }
+ err = carl9170_init_rf_banks_0_7(ar,
+ channel->band == IEEE80211_BAND_5GHZ);
+ if (err)
+ return err;
err = carl9170_exec_cmd(ar, CARL9170_CMD_FREQ_START, 0, NULL, 0, NULL);
if (err)
@@ -1648,8 +1622,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return err;
err = carl9170_init_rf_bank4_pwr(ar,
- channel->band == IEEE80211_BAND_5GHZ,
- channel->center_freq, bw);
+ channel->band == IEEE80211_BAND_5GHZ,
+ channel->center_freq, bw);
if (err)
return err;
@@ -1703,13 +1677,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
rf.delta_slope_coeff_man = cpu_to_le32(freqpar->coeff_man);
rf.delta_slope_coeff_exp_shgi = cpu_to_le32(freqpar->coeff_exp_shgi);
rf.delta_slope_coeff_man_shgi = cpu_to_le32(freqpar->coeff_man_shgi);
-
- if (rfi != CARL9170_RFI_NONE)
- rf.finiteLoopCount = cpu_to_le32(2000);
- else
- rf.finiteLoopCount = cpu_to_le32(1000);
-
- err = carl9170_exec_cmd(ar, cmd, sizeof(rf), &rf,
+ rf.finiteLoopCount = cpu_to_le32(2000);
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_RF_INIT, sizeof(rf), &rf,
sizeof(rf_res), &rf_res);
if (err)
return err;
@@ -1724,9 +1693,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
old_channel->center_freq : -1, channel->center_freq,
err);
- if ((rfi == CARL9170_RFI_COLD) || (ar->chan_fail > 3)) {
- /*
- * We have tried very hard to change to _another_
+ if (ar->chan_fail > 3) {
+ /* We have tried very hard to change to _another_
* channel and we've failed to do so!
* Chances are that the PHY/RF is no longer
* operable (due to corruptions/fatal events/bugs?)
@@ -1736,8 +1704,7 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return 0;
}
- err = carl9170_set_channel(ar, channel, _bw,
- CARL9170_RFI_COLD);
+ err = carl9170_set_channel(ar, channel, _bw);
if (err)
return err;
} else {
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index 5c54aa43ca2d..1816b4e7dc26 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -45,7 +45,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
void *ah = common->ah;
if (entry >= common->keymax) {
- ath_err(common, "keycache entry %u out of range\n", entry);
+ ath_err(common, "keyreset: keycache entry %u out of range\n",
+ entry);
return false;
}
@@ -91,7 +92,8 @@ static bool ath_hw_keysetmac(struct ath_common *common,
void *ah = common->ah;
if (entry >= common->keymax) {
- ath_err(common, "keycache entry %u out of range\n", entry);
+ ath_err(common, "keysetmac: keycache entry %u out of range\n",
+ entry);
return false;
}
@@ -133,7 +135,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
u32 keyType;
if (entry >= common->keymax) {
- ath_err(common, "keycache entry %u out of range\n", entry);
+ ath_err(common, "set-entry: keycache entry %u out of range\n",
+ entry);
return false;
}
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index fe4a77ee05c9..f5e840104f4b 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -285,7 +285,9 @@ enum {
#define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */
#define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */
/* SHM_SHARED beacon/AP variables */
+#define B43_SHM_SH_BT_BASE0 0x0068 /* Beacon template base 0 */
#define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
+#define B43_SHM_SH_BT_BASE1 0x0468 /* Beacon template base 1 */
#define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
#define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
#define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index c4d0cc582555..4ac73d2f8605 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1310,17 +1310,19 @@ static u32 b43_jssi_read(struct b43_wldev *dev)
{
u32 val = 0;
- val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A);
+ val = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI1);
val <<= 16;
- val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088);
+ val |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI0);
return val;
}
static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
{
- b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF));
- b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI0,
+ (jssi & 0x0000FFFF));
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI1,
+ (jssi & 0xFFFF0000) >> 16);
}
static void b43_generate_noise_sample(struct b43_wldev *dev)
@@ -1623,7 +1625,7 @@ static void b43_upload_beacon0(struct b43_wldev *dev)
if (wl->beacon0_uploaded)
return;
- b43_write_beacon_template(dev, 0x68, 0x18);
+ b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE0, B43_SHM_SH_BTL0);
wl->beacon0_uploaded = true;
}
@@ -1633,7 +1635,7 @@ static void b43_upload_beacon1(struct b43_wldev *dev)
if (wl->beacon1_uploaded)
return;
- b43_write_beacon_template(dev, 0x468, 0x1A);
+ b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE1, B43_SHM_SH_BTL1);
wl->beacon1_uploaded = true;
}
@@ -2780,9 +2782,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
case B43_BUS_BCMA:
- bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
- (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc,
- BCMA_CC_GPIOCTL) & ~mask) | set);
+ bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, mask, set);
break;
#endif
#ifdef CONFIG_B43_SSB
@@ -2807,8 +2807,7 @@ static void b43_gpio_cleanup(struct b43_wldev *dev)
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
case B43_BUS_BCMA:
- bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
- 0);
+ bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, ~0, 0);
break;
#endif
#ifdef CONFIG_B43_SSB
@@ -3116,7 +3115,7 @@ static int b43_chip_init(struct b43_wldev *dev)
/* Probe Response Timeout value */
/* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
- b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 0);
/* Initially set the wireless operation mode. */
b43_adjust_opmode(dev);
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 3ae28561f7a4..5ed352ddae9e 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -104,14 +104,8 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
maxpwr = sprom->maxpwr_bg;
lpphy->max_tx_pwr_med_band = maxpwr;
cckpo = sprom->cck2gpo;
- /*
- * We don't read SPROM's opo as specs say. On rev8 SPROMs
- * opo == ofdm2gpo and we don't know any SSB with LP-PHY
- * and SPROM rev below 8.
- */
- B43_WARN_ON(sprom->revision < 8);
- ofdmpo = sprom->ofdm2gpo;
if (cckpo) {
+ ofdmpo = sprom->ofdm2gpo;
for (i = 0; i < 4; i++) {
lpphy->tx_max_rate[i] =
maxpwr - (ofdmpo & 0xF) * 2;
@@ -124,11 +118,11 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
ofdmpo >>= 4;
}
} else {
- ofdmpo &= 0xFF;
+ u8 opo = sprom->opo;
for (i = 0; i < 4; i++)
lpphy->tx_max_rate[i] = maxpwr;
for (i = 4; i < 15; i++)
- lpphy->tx_max_rate[i] = maxpwr - ofdmpo;
+ lpphy->tx_max_rate[i] = maxpwr - opo;
}
} else { /* 5GHz */
lpphy->tx_isolation_low_band = sprom->tri5gl;
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index e8486c1e091a..f9339e7ea6af 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -2789,10 +2789,6 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
* Tx and Rx
**************************************************/
-void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
-{//TODO
-}
-
static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
{//TODO
}
@@ -4892,7 +4888,7 @@ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N */
-int b43_phy_initn(struct b43_wldev *dev)
+static int b43_phy_initn(struct b43_wldev *dev)
{
struct ssb_sprom *sprom = dev->dev->bus_sprom;
struct b43_phy *phy = &dev->phy;
diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c
index ce037fb6789a..b4fd9345d673 100644
--- a/drivers/net/wireless/b43/radio_2056.c
+++ b/drivers/net/wireless/b43/radio_2056.c
@@ -2980,7 +2980,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev8_rx[] = {
.rx = prefix##_rx, \
.rx_length = ARRAY_SIZE(prefix##_rx)
-struct b2056_inittabs_pts b2056_inittabs[] = {
+static const struct b2056_inittabs_pts b2056_inittabs[] = {
[3] = { INITTABSPTS(b2056_inittab_rev3) },
[4] = { INITTABSPTS(b2056_inittab_rev4) },
[5] = { INITTABSPTS(b2056_inittab_rev5) },
@@ -9035,7 +9035,7 @@ static void b2056_upload_inittab(struct b43_wldev *dev, bool ghz5,
void b2056_upload_inittabs(struct b43_wldev *dev,
bool ghz5, bool ignore_uploadflag)
{
- struct b2056_inittabs_pts *pts;
+ const struct b2056_inittabs_pts *pts;
if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) {
B43_WARN_ON(1);
@@ -9057,7 +9057,7 @@ void b2056_upload_inittabs(struct b43_wldev *dev,
void b2056_upload_syn_pll_cp2(struct b43_wldev *dev, bool ghz5)
{
- struct b2056_inittabs_pts *pts;
+ const struct b2056_inittabs_pts *pts;
const struct b2056_inittab_entry *e;
if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) {
diff --git a/drivers/net/wireless/b43/sdio.h b/drivers/net/wireless/b43/sdio.h
index fb633094403a..1e93926f388f 100644
--- a/drivers/net/wireless/b43/sdio.h
+++ b/drivers/net/wireless/b43/sdio.h
@@ -25,12 +25,12 @@ void b43_sdio_exit(void);
#else /* CONFIG_B43_SDIO */
-int b43_sdio_request_irq(struct b43_wldev *dev,
+static inline int b43_sdio_request_irq(struct b43_wldev *dev,
void (*handler)(struct b43_wldev *dev))
{
return -ENODEV;
}
-void b43_sdio_free_irq(struct b43_wldev *dev)
+static inline void b43_sdio_free_irq(struct b43_wldev *dev)
{
}
static inline int b43_sdio_init(void)
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index aaca60c6f575..110510d53958 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -2800,7 +2800,7 @@ static const struct nphy_rf_control_override_rev7
{ 0x0010, 0x344, 0x345, 0x0010, 4 },
};
-struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
+static struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
{ 10, 14, 19, 27 },
{ -5, 6, 10, 15 },
{ 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA },
@@ -2811,7 +2811,7 @@ struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
0x18, 0x18, 0x18,
0x01D0, 0x5,
};
-struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = {
+static struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = {
{ /* 2GHz */
{ /* PHY rev 3 */
{ 7, 11, 16, 23 },
diff --git a/drivers/net/wireless/b43/tables_phy_lcn.c b/drivers/net/wireless/b43/tables_phy_lcn.c
index 5176363cadf2..e347b8d80ea4 100644
--- a/drivers/net/wireless/b43/tables_phy_lcn.c
+++ b/drivers/net/wireless/b43/tables_phy_lcn.c
@@ -313,7 +313,7 @@ static const u32 b43_lcntab_0x18[] = {
* TX gain.
**************************************************/
-const struct b43_lcntab_tx_gain_tbl_entry
+static const struct b43_lcntab_tx_gain_tbl_entry
b43_lcntab_tx_gain_tbl_2ghz_ext_pa_rev0[B43_LCNTAB_TX_GAIN_SIZE] = {
{ 0x03, 0x00, 0x1f, 0x0, 0x48 },
{ 0x03, 0x00, 0x1f, 0x0, 0x46 },
@@ -449,7 +449,7 @@ const struct b43_lcntab_tx_gain_tbl_entry
* SW control.
**************************************************/
-const u16 b43_lcntab_sw_ctl_4313_epa_rev0[] = {
+static const u16 b43_lcntab_sw_ctl_4313_epa_rev0[] = {
0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001,
0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
@@ -631,7 +631,7 @@ static void b43_phy_lcn_upload_static_tables(struct b43_wldev *dev)
lcntab_upload(dev, B43_LCNTAB32(0x18, 0), b43_lcntab_0x18);
}
-void b43_phy_lcn_load_tx_gain_tab(struct b43_wldev *dev,
+static void b43_phy_lcn_load_tx_gain_tab(struct b43_wldev *dev,
const struct b43_lcntab_tx_gain_tbl_entry *gain_table)
{
u32 i;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 11fd1c735589..f3149debede0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -65,7 +65,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
u8 data;
unsigned long flags;
- brcmf_dbg(TRACE, "Entering: irq %d\n", sdiodev->irq);
+ brcmf_dbg(SDIO, "Entering: irq %d\n", sdiodev->irq);
ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler,
sdiodev->irq_flags, "brcmf_oob_intr",
@@ -102,7 +102,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
- brcmf_dbg(TRACE, "Entering\n");
+ brcmf_dbg(SDIO, "Entering\n");
sdio_claim_host(sdiodev->func[1]);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
@@ -136,7 +136,7 @@ static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
{
- brcmf_dbg(TRACE, "Entering\n");
+ brcmf_dbg(SDIO, "Entering\n");
sdio_claim_host(sdiodev->func[1]);
sdio_claim_irq(sdiodev->func[1], brcmf_sdio_irqhandler);
@@ -148,7 +148,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
- brcmf_dbg(TRACE, "Entering\n");
+ brcmf_dbg(SDIO, "Entering\n");
sdio_claim_host(sdiodev->func[1]);
sdio_release_irq(sdiodev->func[2]);
@@ -253,9 +253,9 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
u8 data;
int retval;
- brcmf_dbg(INFO, "addr:0x%08x\n", addr);
+ brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
- brcmf_dbg(INFO, "data:0x%02x\n", data);
+ brcmf_dbg(SDIO, "data:0x%02x\n", data);
if (ret)
*ret = retval;
@@ -268,9 +268,9 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
u32 data;
int retval;
- brcmf_dbg(INFO, "addr:0x%08x\n", addr);
+ brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
- brcmf_dbg(INFO, "data:0x%08x\n", data);
+ brcmf_dbg(SDIO, "data:0x%08x\n", data);
if (ret)
*ret = retval;
@@ -283,7 +283,7 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
{
int retval;
- brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
+ brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
if (ret)
@@ -295,7 +295,7 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
{
int retval;
- brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
+ brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
if (ret)
@@ -358,7 +358,7 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint width;
int err = 0;
- brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+ brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
@@ -381,7 +381,7 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint width;
int err = 0;
- brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+ brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pktq->qlen);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
@@ -428,7 +428,7 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
- brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+ brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);
/* Async not implemented yet */
@@ -492,13 +492,13 @@ int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
{
char t_func = (char)fn;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
/* issue abort cmd52 command through F0 */
brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
SDIO_CCCR_ABORT, &t_func);
- brcmf_dbg(TRACE, "Exit\n");
+ brcmf_dbg(SDIO, "Exit\n");
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index d92d373733d7..716548989e4f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -139,7 +139,7 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
{
int err_ret;
- brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
+ brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
if (brcmf_pm_resume_error(sdiodev))
@@ -179,7 +179,7 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
return -EINVAL;
}
- brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
+ brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
rw, func, addr, nbytes);
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
@@ -252,7 +252,7 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
struct sk_buff *pkt;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_chain_wait);
if (brcmf_pm_resume_error(sdiodev))
@@ -270,7 +270,7 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
write ? "TX" : "RX", pkt, SGCount, addr,
pkt_len, err_ret);
} else {
- brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+ brcmf_dbg(SDIO, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
write ? "TX" : "RX", pkt, SGCount, addr,
pkt_len);
}
@@ -280,7 +280,7 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
SGCount++;
}
- brcmf_dbg(TRACE, "Exit\n");
+ brcmf_dbg(SDIO, "Exit\n");
return err_ret;
}
@@ -295,7 +295,7 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
uint pkt_len;
bool fifo = (fix_inc == SDIOH_DATA_FIX);
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
if (pkt == NULL)
return -EINVAL;
@@ -314,7 +314,7 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
brcmf_err("%s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
write ? "TX" : "RX", pkt, addr, pkt_len, status);
} else {
- brcmf_dbg(TRACE, "%s xfr'd %p, addr=0x%05x, len=%d\n",
+ brcmf_dbg(SDIO, "%s xfr'd %p, addr=0x%05x, len=%d\n",
write ? "TX" : "RX", pkt, addr, pkt_len);
}
@@ -350,12 +350,12 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
u32 fbraddr;
u8 func;
- brcmf_dbg(TRACE, "\n");
+ brcmf_dbg(SDIO, "\n");
/* Get the Card's common CIS address */
sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev,
SDIO_CCCR_CIS);
- brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n",
+ brcmf_dbg(SDIO, "Card's Common CIS Ptr = 0x%x\n",
sdiodev->func_cis_ptr[0]);
/* Get the Card's function CIS (for each function) */
@@ -363,7 +363,7 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
sdiodev->func_cis_ptr[func] =
brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr);
- brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n",
+ brcmf_dbg(SDIO, "Function %d CIS Ptr = 0x%x\n",
func, sdiodev->func_cis_ptr[func]);
}
@@ -382,7 +382,7 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
{
int err_ret = 0;
- brcmf_dbg(TRACE, "\n");
+ brcmf_dbg(SDIO, "\n");
sdiodev->num_funcs = 2;
@@ -404,13 +404,13 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
out:
sdio_release_host(sdiodev->func[1]);
- brcmf_dbg(TRACE, "Done\n");
+ brcmf_dbg(SDIO, "Done\n");
return err_ret;
}
void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
{
- brcmf_dbg(TRACE, "\n");
+ brcmf_dbg(SDIO, "\n");
/* Disable Function 2 */
sdio_claim_host(sdiodev->func[2]);
@@ -458,11 +458,11 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(TRACE, "Class=%x\n", func->class);
- brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
- brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
- brcmf_dbg(TRACE, "Function#: %d\n", func->num);
+ brcmf_dbg(SDIO, "Enter\n");
+ brcmf_dbg(SDIO, "Class=%x\n", func->class);
+ brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
+ brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
+ brcmf_dbg(SDIO, "Function#: %d\n", func->num);
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
@@ -501,13 +501,13 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
if (err)
goto fail;
- brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
+ brcmf_dbg(SDIO, "F2 found, calling brcmf_sdio_probe...\n");
err = brcmf_sdio_probe(sdiodev);
if (err) {
brcmf_err("F2 error, probe failed %d...\n", err);
goto fail;
}
- brcmf_dbg(TRACE, "F2 init completed...\n");
+ brcmf_dbg(SDIO, "F2 init completed...\n");
return 0;
fail:
@@ -523,10 +523,10 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev;
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
- brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
- brcmf_dbg(TRACE, "Function: %d\n", func->num);
+ brcmf_dbg(SDIO, "Enter\n");
+ brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
+ brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
+ brcmf_dbg(SDIO, "Function: %d\n", func->num);
if (func->num != 1 && func->num != 2)
return;
@@ -543,7 +543,7 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
kfree(sdiodev);
}
- brcmf_dbg(TRACE, "Exit\n");
+ brcmf_dbg(SDIO, "Exit\n");
}
#ifdef CONFIG_PM_SLEEP
@@ -554,7 +554,7 @@ static int brcmf_sdio_suspend(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0;
- brcmf_dbg(TRACE, "\n");
+ brcmf_dbg(SDIO, "\n");
atomic_set(&sdiodev->suspend, true);
@@ -645,7 +645,7 @@ static struct platform_driver brcmf_sdio_pd = {
void brcmf_sdio_exit(void)
{
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
sdio_unregister_driver(&brcmf_sdmmc_driver);
@@ -656,7 +656,7 @@ void brcmf_sdio_init(void)
{
int ret;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
ret = platform_driver_register(&brcmf_sdio_pd);
@@ -666,7 +666,7 @@ void brcmf_sdio_init(void)
#else
void brcmf_sdio_exit(void)
{
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
sdio_unregister_driver(&brcmf_sdmmc_driver);
}
@@ -675,7 +675,7 @@ void brcmf_sdio_init(void)
{
int ret;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
ret = sdio_register_driver(&brcmf_sdmmc_driver);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index c7fa20846b32..5249c67b466c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -72,6 +72,7 @@
#define BRCMF_C_SET_WSEC 134
#define BRCMF_C_GET_PHY_NOISE 135
#define BRCMF_C_GET_BSS_INFO 136
+#define BRCMF_C_GET_BANDLIST 140
#define BRCMF_C_SET_SCB_TIMEOUT 158
#define BRCMF_C_GET_PHYLIST 180
#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
@@ -475,6 +476,11 @@ struct brcmf_sta_info_le {
__le32 rx_decrypt_failures; /* # of packet decrypted failed */
};
+struct brcmf_chanspec_list {
+ __le32 count; /* # of entries */
+ __le32 element[1]; /* variable length uint32 list */
+};
+
/*
* WLC_E_PROBRESP_MSG
* WLC_E_P2P_PROBREQ_MSG
@@ -542,10 +548,25 @@ struct brcmf_if_event {
u8 action;
u8 flags;
u8 bssidx;
+ u8 role;
};
-/* forward declaration */
+/* forward declarations */
struct brcmf_cfg80211_vif;
+struct brcmf_fws_mac_descriptor;
+
+/**
+ * enum brcmf_netif_stop_reason - reason for stopping netif queue.
+ *
+ * @BRCMF_NETIF_STOP_REASON_FWS_FC:
+ * netif stopped due to firmware signalling flow control.
+ * @BRCMF_NETIF_STOP_REASON_BLOCK_BUS:
+ * netif stopped due to bus blocking.
+ */
+enum brcmf_netif_stop_reason {
+ BRCMF_NETIF_STOP_REASON_FWS_FC = 1,
+ BRCMF_NETIF_STOP_REASON_BLOCK_BUS = 2
+};
/**
* struct brcmf_if - interface control information.
@@ -554,9 +575,13 @@ struct brcmf_cfg80211_vif;
* @vif: points to cfg80211 specific interface information.
* @ndev: associated network device.
* @stats: interface specific network statistics.
+ * @setmacaddr_work: worker object for setting mac address.
+ * @multicast_work: worker object for multicast provisioning.
+ * @fws_desc: interface specific firmware-signalling descriptor.
* @ifidx: interface index in device firmware.
* @bssidx: index of bss associated with this interface.
* @mac_addr: assigned mac address.
+ * @netif_stop: bitmap indicates reason why netif queues are stopped.
* @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
* @pend_8021x_wait: used for signalling change in count.
*/
@@ -567,9 +592,11 @@ struct brcmf_if {
struct net_device_stats stats;
struct work_struct setmacaddr_work;
struct work_struct multicast_work;
+ struct brcmf_fws_mac_descriptor *fws_desc;
int ifidx;
s32 bssidx;
u8 mac_addr[ETH_ALEN];
+ u8 netif_stop;
atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait;
};
@@ -594,6 +621,10 @@ extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx,
s32 ifidx, char *name, u8 *mac_addr);
extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
+void brcmf_txflowblock_if(struct brcmf_if *ifp,
+ enum brcmf_netif_stop_reason reason, bool state);
extern u32 brcmf_get_chip_info(struct brcmf_if *ifp);
+extern void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
+ bool success);
#endif /* _BRCMF_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index 883ef9063e8a..080395f49fa5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -39,10 +39,12 @@ struct brcmf_bus_dcmd {
* @txdata: send a data frame to the dongle (callee disposes skb).
* @txctl: transmit a control request message to dongle.
* @rxctl: receive a control response message from dongle.
+ * @gettxq: obtain a reference of bus transmit queue (optional).
*
* This structure provides an abstract interface towards the
* bus specific driver. For control messages to common driver
- * will assure there is only one active transaction.
+ * will assure there is only one active transaction. Unless
+ * indicated otherwise these callbacks are mandatory.
*/
struct brcmf_bus_ops {
int (*init)(struct device *dev);
@@ -50,6 +52,7 @@ struct brcmf_bus_ops {
int (*txdata)(struct device *dev, struct sk_buff *skb);
int (*txctl)(struct device *dev, unsigned char *msg, uint len);
int (*rxctl)(struct device *dev, unsigned char *msg, uint len);
+ struct pktq * (*gettxq)(struct device *dev);
};
/**
@@ -115,6 +118,14 @@ int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
return bus->ops->rxctl(bus->dev, msg, len);
}
+static inline
+struct pktq *brcmf_bus_gettxq(struct brcmf_bus *bus)
+{
+ if (!bus->ops->gettxq)
+ return ERR_PTR(-ENOENT);
+
+ return bus->ops->gettxq(bus->dev);
+}
/*
* interface functions from common layer
*/
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
index e224bcb90024..59c77aa3b959 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
@@ -303,8 +303,8 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
/* Pop BDC header used to convey priority for buses that don't */
- if (pktbuf->len < BDC_HEADER_LEN) {
- brcmf_err("rx data too short (%d < %d)\n",
+ if (pktbuf->len <= BDC_HEADER_LEN) {
+ brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",
pktbuf->len, BDC_HEADER_LEN);
return -EBADE;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
index ac792499b46a..202869cd0932 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -130,7 +130,7 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
size_t count, loff_t *ppos)
{
struct brcmf_fws_stats *fwstats = f->private_data;
- char buf[100];
+ char buf[650];
int res;
/* only allow read from start */
@@ -138,14 +138,52 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
return 0;
res = scnprintf(buf, sizeof(buf),
- "header_pulls: %u\n"
- "header_only_pkt: %u\n"
- "tlv_parse_failed: %u\n"
- "tlv_invalid_type: %u\n",
+ "header_pulls: %u\n"
+ "header_only_pkt: %u\n"
+ "tlv_parse_failed: %u\n"
+ "tlv_invalid_type: %u\n"
+ "mac_update_fails: %u\n"
+ "ps_update_fails: %u\n"
+ "if_update_fails: %u\n"
+ "pkt2bus: %u\n"
+ "generic_error: %u\n"
+ "rollback_success: %u\n"
+ "rollback_failed: %u\n"
+ "delayq_full: %u\n"
+ "supprq_full: %u\n"
+ "txs_indicate: %u\n"
+ "txs_discard: %u\n"
+ "txs_suppr_core: %u\n"
+ "txs_suppr_ps: %u\n"
+ "txs_tossed: %u\n"
+ "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
+ "fifo_credits_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
fwstats->header_pulls,
fwstats->header_only_pkt,
fwstats->tlv_parse_failed,
- fwstats->tlv_invalid_type);
+ fwstats->tlv_invalid_type,
+ fwstats->mac_update_failed,
+ fwstats->mac_ps_update_failed,
+ fwstats->if_update_failed,
+ fwstats->pkt2bus,
+ fwstats->generic_error,
+ fwstats->rollback_success,
+ fwstats->rollback_failed,
+ fwstats->delayq_full_error,
+ fwstats->supprq_full_error,
+ fwstats->txs_indicate,
+ fwstats->txs_discard,
+ fwstats->txs_supp_core,
+ fwstats->txs_supp_ps,
+ fwstats->txs_tossed,
+ fwstats->send_pkts[0], fwstats->send_pkts[1],
+ fwstats->send_pkts[2], fwstats->send_pkts[3],
+ fwstats->send_pkts[4],
+ fwstats->fifo_credits_sent[0],
+ fwstats->fifo_credits_sent[1],
+ fwstats->fifo_credits_sent[2],
+ fwstats->fifo_credits_sent[3],
+ fwstats->fifo_credits_sent[4]);
return simple_read_from_buffer(data, count, ppos, buf, res);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index 4bc646bde16f..009c87bfd9ae 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -34,6 +34,7 @@
#define BRCMF_SCAN_VAL 0x00004000
#define BRCMF_CONN_VAL 0x00008000
#define BRCMF_CDC_VAL 0x00010000
+#define BRCMF_SDIO_VAL 0x00020000
/* set default print format */
#undef pr_fmt
@@ -92,6 +93,7 @@ do { \
#define brcmf_dbg_hex_dump(test, data, len, fmt, ...) \
do { \
+ trace_brcmf_hexdump((void *)data, len); \
if (test) \
brcmu_dbg_hex_dump(data, len, fmt, ##__VA_ARGS__); \
} while (0)
@@ -137,6 +139,25 @@ struct brcmf_fws_stats {
u32 tlv_invalid_type;
u32 header_only_pkt;
u32 header_pulls;
+ u32 pkt2bus;
+ u32 send_pkts[5];
+ u32 fifo_credits_sent[5];
+ u32 fifo_credits_back[6];
+ u32 generic_error;
+ u32 mac_update_failed;
+ u32 mac_ps_update_failed;
+ u32 if_update_failed;
+ u32 packet_request_failed;
+ u32 credit_request_failed;
+ u32 rollback_success;
+ u32 rollback_failed;
+ u32 delayq_full_error;
+ u32 supprq_full_error;
+ u32 txs_indicate;
+ u32 txs_discard;
+ u32 txs_supp_core;
+ u32 txs_supp_ps;
+ u32 txs_tossed;
};
struct brcmf_pub;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index fa5a2af04d46..763a84eba216 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -223,18 +223,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done;
}
- /* handle ethernet header */
- eh = (struct ethhdr *)(skb->data);
- if (is_multicast_ether_addr(eh->h_dest))
- drvr->tx_multicast++;
- if (ntohs(eh->h_proto) == ETH_P_PAE)
- atomic_inc(&ifp->pend_8021x_cnt);
-
- /* If the protocol uses a data header, apply it */
- brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb);
-
- /* Use bus module to send data frame */
- ret = brcmf_bus_txdata(drvr->bus_if, skb);
+ ret = brcmf_fws_process_skb(ifp, skb);
done:
if (ret) {
@@ -248,9 +237,27 @@ done:
return NETDEV_TX_OK;
}
+void brcmf_txflowblock_if(struct brcmf_if *ifp,
+ enum brcmf_netif_stop_reason reason, bool state)
+{
+ if (!ifp)
+ return;
+
+ brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
+ ifp->bssidx, ifp->netif_stop, reason, state);
+ if (state) {
+ if (!ifp->netif_stop)
+ netif_stop_queue(ifp->ndev);
+ ifp->netif_stop |= reason;
+ } else {
+ ifp->netif_stop &= ~reason;
+ if (!ifp->netif_stop)
+ netif_wake_queue(ifp->ndev);
+ }
+}
+
void brcmf_txflowblock(struct device *dev, bool state)
{
- struct net_device *ndev;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
int i;
@@ -258,13 +265,8 @@ void brcmf_txflowblock(struct device *dev, bool state)
brcmf_dbg(TRACE, "Enter\n");
for (i = 0; i < BRCMF_MAX_IFS; i++)
- if (drvr->iflist[i]) {
- ndev = drvr->iflist[i]->ndev;
- if (state)
- netif_stop_queue(ndev);
- else
- netif_wake_queue(ndev);
- }
+ brcmf_txflowblock_if(drvr->iflist[i],
+ BRCMF_NETIF_STOP_REASON_BLOCK_BUS, state);
}
void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
@@ -321,13 +323,8 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
/* Strip header, count, deliver upward */
skb_pull(skb, ETH_HLEN);
- /* Process special event packets and then discard them */
- brcmf_fweh_process_skb(drvr, skb, &ifidx);
-
- if (drvr->iflist[ifidx]) {
- ifp = drvr->iflist[ifidx];
- ifp->ndev->last_rx = jiffies;
- }
+ /* Process special event packets */
+ brcmf_fweh_process_skb(drvr, skb);
if (!(ifp->ndev->flags & IFF_UP)) {
brcmu_pkt_buf_free_skb(skb);
@@ -350,14 +347,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
}
}
-void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
+ bool success)
{
- u8 ifidx;
+ struct brcmf_if *ifp;
struct ethhdr *eh;
+ u8 ifidx;
u16 type;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- struct brcmf_if *ifp;
int res;
res = brcmf_proto_hdrpull(drvr, false, &ifidx, txp);
@@ -378,11 +374,24 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
}
if (!success)
ifp->stats.tx_errors++;
-
done:
brcmu_pkt_buf_free_skb(txp);
}
+void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ /* await txstatus signal for firmware if active */
+ if (brcmf_fws_fc_active(drvr->fws)) {
+ if (!success)
+ brcmf_fws_bustxfail(drvr->fws, txp);
+ } else {
+ brcmf_txfinalize(drvr, txp, success);
+ }
+}
+
static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
@@ -741,28 +750,35 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
}
}
- /* Allocate netdev, including space for private structure */
- ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
- if (!ndev) {
- brcmf_err("OOM - alloc_netdev\n");
- return ERR_PTR(-ENOMEM);
+ if (!brcmf_p2p_enable && bssidx == 1) {
+ /* this is P2P_DEVICE interface */
+ brcmf_dbg(INFO, "allocate non-netdev interface\n");
+ ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
+ } else {
+ brcmf_dbg(INFO, "allocate netdev interface\n");
+ /* Allocate netdev, including space for private structure */
+ ndev = alloc_netdev(sizeof(*ifp), name, ether_setup);
+ if (!ndev) {
+ brcmf_err("OOM - alloc_netdev\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ifp = netdev_priv(ndev);
+ ifp->ndev = ndev;
}
- ifp = netdev_priv(ndev);
- ifp->ndev = ndev;
ifp->drvr = drvr;
drvr->iflist[bssidx] = ifp;
ifp->ifidx = ifidx;
ifp->bssidx = bssidx;
-
init_waitqueue_head(&ifp->pend_8021x_wait);
if (mac_addr != NULL)
memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
- current->pid, ifp->ndev->name, ifp->mac_addr);
+ current->pid, name, ifp->mac_addr);
return ifp;
}
@@ -794,11 +810,13 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
}
unregister_netdev(ifp->ndev);
- drvr->iflist[bssidx] = NULL;
if (bssidx == 0)
brcmf_cfg80211_detach(drvr->config);
free_netdev(ifp->ndev);
+ } else {
+ kfree(ifp);
}
+ drvr->iflist[bssidx] = NULL;
}
int brcmf_attach(uint bus_hdrlen, struct device *dev)
@@ -882,6 +900,7 @@ int brcmf_bus_start(struct device *dev)
drvr->fw_signals = true;
(void)brcmf_fws_init(drvr);
+ brcmf_fws_add_interface(ifp);
drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
if (drvr->config == NULL) {
@@ -899,8 +918,10 @@ fail:
brcmf_err("failed: %d\n", ret);
if (drvr->config)
brcmf_cfg80211_detach(drvr->config);
- if (drvr->fws)
+ if (drvr->fws) {
+ brcmf_fws_del_interface(ifp);
brcmf_fws_deinit(drvr);
+ }
free_netdev(ifp->ndev);
drvr->iflist[0] = NULL;
if (p2p_ifp) {
@@ -956,16 +977,17 @@ void brcmf_detach(struct device *dev)
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
- if (drvr->iflist[i])
+ if (drvr->iflist[i]) {
+ brcmf_fws_del_interface(drvr->iflist[i]);
brcmf_del_if(drvr, i);
+ }
brcmf_bus_detach(drvr);
if (drvr->prot)
brcmf_proto_detach(drvr);
- if (drvr->fws)
- brcmf_fws_deinit(drvr);
+ brcmf_fws_deinit(drvr);
brcmf_debugfs_detach(drvr);
bus_if->drvr = NULL;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 9a2edd3f0a5c..4ff2d3c52ee6 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -94,6 +94,7 @@ struct rte_console {
#include "dhd_bus.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
#define TXQLEN 2048 /* bulk tx queue length */
#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
@@ -675,7 +676,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
u8 clkctl, clkreq, devctl;
unsigned long timeout;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
clkctl = 0;
@@ -713,7 +714,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
- brcmf_dbg(INFO, "CLKCTL: set PENDING\n");
+ brcmf_dbg(SDIO, "CLKCTL: set PENDING\n");
bus->clkstate = CLK_PENDING;
return 0;
@@ -750,7 +751,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
/* Mark clock available */
bus->clkstate = CLK_AVAIL;
- brcmf_dbg(INFO, "CLKCTL: turned ON\n");
+ brcmf_dbg(SDIO, "CLKCTL: turned ON\n");
#if defined(DEBUG)
if (!bus->alp_only) {
@@ -775,7 +776,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
bus->clkstate = CLK_SDONLY;
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
clkreq, &err);
- brcmf_dbg(INFO, "CLKCTL: turned OFF\n");
+ brcmf_dbg(SDIO, "CLKCTL: turned OFF\n");
if (err) {
brcmf_err("Failed access turning clock off: %d\n",
err);
@@ -788,7 +789,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
/* Change idle/active SD state */
static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)
{
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
if (on)
bus->clkstate = CLK_SDONLY;
@@ -805,7 +806,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
uint oldstate = bus->clkstate;
#endif /* DEBUG */
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
/* Early exit if we're already there */
if (bus->clkstate == target) {
@@ -849,7 +850,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
break;
}
#ifdef DEBUG
- brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate);
+ brcmf_dbg(SDIO, "%d -> %d\n", oldstate, bus->clkstate);
#endif /* DEBUG */
return 0;
@@ -862,7 +863,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
u8 fcbits;
int ret;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
/* Read mailbox data and ack that we did so */
ret = r_sdreg32(bus, &hmb_data,
@@ -875,7 +876,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
/* Dongle recomposed rx frames, accept them again */
if (hmb_data & HMB_DATA_NAKHANDLED) {
- brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n",
+ brcmf_dbg(SDIO, "Dongle reports NAK handled, expect rtx of %d\n",
bus->rx_seq);
if (!bus->rxskip)
brcmf_err("unexpected NAKHANDLED!\n");
@@ -896,7 +897,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
"expecting %d\n",
bus->sdpcm_ver, SDPCM_PROT_VERSION);
else
- brcmf_dbg(INFO, "Dongle ready, protocol version %d\n",
+ brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n",
bus->sdpcm_ver);
}
@@ -970,7 +971,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
if (!retries)
brcmf_err("count never zeroed: last 0x%04x\n", lastrbc);
else
- brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
+ brcmf_dbg(SDIO, "flush took %d iterations\n", 0xffff - retries);
if (rtx) {
bus->sdcnt.rxrtx++;
@@ -1173,7 +1174,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
/* If packets, issue read(s) and send up packet chain */
/* Return sequence numbers consumed? */
- brcmf_dbg(TRACE, "start: glomd %p glom %p\n",
+ brcmf_dbg(SDIO, "start: glomd %p glom %p\n",
bus->glomd, skb_peek(&bus->glom));
/* If there's a descriptor, generate the packet chain */
@@ -1781,7 +1782,6 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
u8 *frame;
u16 len, pad = 0;
u32 swheader;
- struct sk_buff *new;
int i;
brcmf_dbg(TRACE, "Enter\n");
@@ -1795,27 +1795,14 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
skb_headroom(pkt), pad);
bus->sdiodev->bus_if->tx_realloc++;
- new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
- if (!new) {
- brcmf_err("couldn't allocate new %d-byte packet\n",
- pkt->len + BRCMF_SDALIGN);
- ret = -ENOMEM;
+ ret = skb_cow(pkt, BRCMF_SDALIGN);
+ if (ret)
goto done;
- }
-
- pkt_align(new, pkt->len, BRCMF_SDALIGN);
- memcpy(new->data, pkt->data, pkt->len);
- brcmu_pkt_buf_free_skb(pkt);
- pkt = new;
- frame = (u8 *) (pkt->data);
- /* precondition: (frame % BRCMF_SDALIGN) == 0) */
- pad = 0;
- } else {
- skb_push(pkt, pad);
- frame = (u8 *) (pkt->data);
- /* precondition: pad + SDPCM_HDRLEN <= pkt->len */
- memset(frame, 0, pad + SDPCM_HDRLEN);
+ pad = ((unsigned long)frame % BRCMF_SDALIGN);
}
+ skb_push(pkt, pad);
+ frame = (u8 *) (pkt->data);
+ memset(frame, 0, pad + SDPCM_HDRLEN);
}
/* precondition: pad < BRCMF_SDALIGN */
@@ -1830,8 +1817,8 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
(((pad +
SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
- put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
- put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+ *(((__le32 *) frame) + 1) = cpu_to_le32(swheader);
+ *(((__le32 *) frame) + 2) = 0;
#ifdef DEBUG
tx_packets[pkt->priority]++;
@@ -1897,7 +1884,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
done:
/* restore pkt buffer pointer before calling tx complete routine */
skb_pull(pkt, SDPCM_HDRLEN + pad);
- brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0);
+ brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0);
return ret;
}
@@ -2131,7 +2118,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
}
- brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
+ brcmf_dbg(SDIO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
devctl, clkctl);
if (SBSDIO_HTAV(clkctl)) {
@@ -2307,6 +2294,15 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
}
}
+static struct pktq *brcmf_sdbrcm_bus_gettxq(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+
+ return &bus->txq;
+}
+
static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
{
int ret = -EBADE;
@@ -2392,7 +2388,7 @@ brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,
/* Do the transfer(s) */
while (size) {
- brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
+ brcmf_dbg(SDIO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
write ? "write" : "read", dsize,
sdaddr, address & SBSDIO_SBWINDOW_MASK);
bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,
@@ -2625,10 +2621,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
msecs_to_jiffies(2000));
if (!bus->ctrl_frame_stat) {
- brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
+ brcmf_dbg(SDIO, "ctrl_frame_stat == false\n");
ret = 0;
} else {
- brcmf_dbg(INFO, "ctrl_frame_stat == true\n");
+ brcmf_dbg(SDIO, "ctrl_frame_stat == true\n");
ret = -1;
}
}
@@ -2699,7 +2695,7 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
addr = le32_to_cpu(addr_le);
- brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);
+ brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr);
/*
* Check if addr is valid.
@@ -2726,8 +2722,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
sh->console_addr = le32_to_cpu(sh_le.console_addr);
sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
- if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
- brcmf_err("sdpcm_shared version mismatch: dhd %d dongle %d\n",
+ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) {
+ brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n",
SDPCM_SHARED_VERSION,
sh->flags & SDPCM_SHARED_VERSION_MASK);
return -EPROTO;
@@ -2809,21 +2805,18 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
int error, res;
char buf[350];
struct brcmf_trap_info tr;
- int nbytes;
loff_t pos = 0;
- if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
+ if ((sh->flags & SDPCM_SHARED_TRAP) == 0) {
+ brcmf_dbg(INFO, "no trap in firmware\n");
return 0;
+ }
error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
sizeof(struct brcmf_trap_info));
if (error < 0)
return error;
- nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
- if (nbytes < 0)
- return nbytes;
-
res = scnprintf(buf, sizeof(buf),
"dongle trap info: type 0x%x @ epc 0x%08x\n"
" cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
@@ -2839,12 +2832,7 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
- error = simple_read_from_buffer(data+nbytes, count, &pos, buf, res);
- if (error < 0)
- return error;
-
- nbytes += error;
- return nbytes;
+ return simple_read_from_buffer(data, count, &pos, buf, res);
}
static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
@@ -2926,14 +2914,20 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
error = brcmf_sdio_assert_info(bus, &sh, data, count);
if (error < 0)
goto done;
-
nbytes = error;
- error = brcmf_sdio_trap_info(bus, &sh, data, count);
+
+ error = brcmf_sdio_trap_info(bus, &sh, data+nbytes, count);
+ if (error < 0)
+ goto done;
+ nbytes += error;
+
+ error = brcmf_sdio_dump_console(bus, &sh, data+nbytes, count);
if (error < 0)
goto done;
+ nbytes += error;
- error += nbytes;
- *ppos += error;
+ error = nbytes;
+ *ppos += nbytes;
done:
return error;
}
@@ -3309,15 +3303,15 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
goto err;
}
- /* External image takes precedence if specified */
if (brcmf_sdbrcm_download_code_file(bus)) {
brcmf_err("dongle image file download failed\n");
goto err;
}
- /* External nvram takes precedence if specified */
- if (brcmf_sdbrcm_download_nvram(bus))
+ if (brcmf_sdbrcm_download_nvram(bus)) {
brcmf_err("dongle nvram file download failed\n");
+ goto err;
+ }
/* Take arm out of reset */
if (brcmf_sdbrcm_download_state(bus, false)) {
@@ -3848,6 +3842,7 @@ static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.txdata = brcmf_sdbrcm_bus_txdata,
.txctl = brcmf_sdbrcm_bus_txctl,
.rxctl = brcmf_sdbrcm_bus_rxctl,
+ .gettxq = brcmf_sdbrcm_bus_gettxq,
};
void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
index e9d6f91a1f2b..5a64280e6485 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -20,6 +20,8 @@
#include "dhd.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
+#include "fwsignal.h"
#include "fweh.h"
#include "fwil.h"
@@ -154,7 +156,7 @@ static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp,
fweh = &ifp->drvr->fweh;
/* handle the event if valid interface and handler */
- if (ifp->ndev && fweh->evt_handler[code])
+ if (fweh->evt_handler[code])
err = fweh->evt_handler[code](ifp, emsg, data);
else
brcmf_err("unhandled event %d ignored\n", code);
@@ -179,9 +181,9 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
struct brcmf_if *ifp;
int err = 0;
- brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u\n",
- ifevent->action, ifevent->ifidx,
- ifevent->bssidx, ifevent->flags);
+ brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n",
+ ifevent->action, ifevent->ifidx, ifevent->bssidx,
+ ifevent->flags, ifevent->role);
if (ifevent->ifidx >= BRCMF_MAX_IFS) {
brcmf_err("invalid interface index: %u\n",
@@ -198,15 +200,20 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
emsg->ifname, emsg->addr);
if (IS_ERR(ifp))
return;
-
+ brcmf_fws_add_interface(ifp);
if (!drvr->fweh.evt_handler[BRCMF_E_IF])
err = brcmf_net_attach(ifp, false);
}
+ if (ifevent->action == BRCMF_E_IF_CHANGE)
+ brcmf_fws_reset_interface(ifp);
+
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
- if (ifevent->action == BRCMF_E_IF_DEL)
+ if (ifevent->action == BRCMF_E_IF_DEL) {
+ brcmf_fws_del_interface(ifp);
brcmf_del_if(drvr, ifevent->bssidx);
+ }
}
/**
@@ -400,13 +407,12 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp)
*
* @drvr: driver information object.
* @event_packet: event packet to process.
- * @ifidx: index of the firmware interface (may change).
*
* If the packet buffer contains a firmware event message it will
* dispatch the event to a registered handler (using worker).
*/
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
- struct brcmf_event *event_packet, u8 *ifidx)
+ struct brcmf_event *event_packet)
{
enum brcmf_fweh_event_code code;
struct brcmf_fweh_info *fweh = &drvr->fweh;
@@ -418,7 +424,6 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
/* get event info */
code = get_unaligned_be32(&event_packet->msg.event_type);
datalen = get_unaligned_be32(&event_packet->msg.datalen);
- *ifidx = event_packet->msg.ifidx;
data = &event_packet[1];
if (code >= BRCMF_E_LAST)
@@ -435,7 +440,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
return;
event->code = code;
- event->ifidx = *ifidx;
+ event->ifidx = event_packet->msg.ifidx;
/* use memcpy to get aligned event message */
memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
index 8c39b51dcccf..6ec5db9c60a5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
@@ -187,10 +187,10 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr,
enum brcmf_fweh_event_code code);
int brcmf_fweh_activate_events(struct brcmf_if *ifp);
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
- struct brcmf_event *event_packet, u8 *ifidx);
+ struct brcmf_event *event_packet);
static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
- struct sk_buff *skb, u8 *ifidx)
+ struct sk_buff *skb)
{
struct brcmf_event *event_packet;
u8 *data;
@@ -213,7 +213,7 @@ static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
return;
- brcmf_fweh_process_event(drvr, event_packet, ifidx);
+ brcmf_fweh_process_event(drvr, event_packet);
}
#endif /* FWEH_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
index 8d1def935b8d..04f395930d86 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
@@ -25,6 +25,7 @@
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
#include "fwil.h"
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 071d55f9cd4d..b3c608ee37cf 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -14,17 +14,22 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/types.h>
+#include <linux/module.h>
#include <linux/if_ether.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/err.h>
#include <uapi/linux/nl80211.h>
+#include <net/cfg80211.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
+#include "dhd_proto.h"
#include "dhd_dbg.h"
+#include "dhd_bus.h"
#include "fwil.h"
#include "fweh.h"
#include "fwsignal.h"
@@ -54,7 +59,7 @@
BRCMF_FWS_TLV_DEF(RSSI, 8, 1) \
BRCMF_FWS_TLV_DEF(INTERFACE_OPEN, 9, 1) \
BRCMF_FWS_TLV_DEF(INTERFACE_CLOSE, 10, 1) \
- BRCMF_FWS_TLV_DEF(FIFO_CREDITBACK, 11, 8) \
+ BRCMF_FWS_TLV_DEF(FIFO_CREDITBACK, 11, 6) \
BRCMF_FWS_TLV_DEF(PENDING_TRAFFIC_BMP, 12, 2) \
BRCMF_FWS_TLV_DEF(MAC_REQUEST_PACKET, 13, 3) \
BRCMF_FWS_TLV_DEF(HOST_REORDER_RXPKTS, 14, 10) \
@@ -62,7 +67,7 @@
BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \
BRCMF_FWS_TLV_DEF(FILLER, 255, 0)
-/**
+/*
* enum brcmf_fws_tlv_type - definition of tlv identifiers.
*/
#define BRCMF_FWS_TLV_DEF(name, id, len) \
@@ -73,18 +78,18 @@ enum brcmf_fws_tlv_type {
};
#undef BRCMF_FWS_TLV_DEF
-/**
- * enum brcmf_fws_tlv_len - length values for tlvs.
+/*
+ * enum brcmf_fws_tlv_len - definition of tlv lengths.
*/
#define BRCMF_FWS_TLV_DEF(name, id, len) \
- BRCMF_FWS_TYPE_ ## name ## _LEN = len,
+ BRCMF_FWS_TYPE_ ## name ## _LEN = (len),
enum brcmf_fws_tlv_len {
BRCMF_FWS_TLV_DEFLIST
};
#undef BRCMF_FWS_TLV_DEF
#ifdef DEBUG
-/**
+/*
* brcmf_fws_tlv_names - array of tlv names.
*/
#define BRCMF_FWS_TLV_DEF(name, id, len) \
@@ -114,43 +119,109 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
}
#endif /* DEBUG */
-/**
+/*
* flags used to enable tlv signalling from firmware.
*/
-#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001
-#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002
-#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004
-#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008
-#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010
-#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
-#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
-
-#define BRCMF_FWS_HANGER_MAXITEMS 1024
-#define BRCMF_FWS_HANGER_ITEM_STATE_FREE 1
-#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE 2
-#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3
-
-#define BRCMF_FWS_STATE_OPEN 1
-#define BRCMF_FWS_STATE_CLOSE 2
-
-#define BRCMF_FWS_FCMODE_NONE 0
-#define BRCMF_FWS_FCMODE_IMPLIED_CREDIT 1
-#define BRCMF_FWS_FCMODE_EXPLICIT_CREDIT 2
+#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001
+#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002
+#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004
+#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008
+#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010
+#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
+#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32
-#define BRCMF_FWS_MAX_IFNUM 16
#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff
#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0
#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1
+#define BRCMF_FWS_FLOWCONTROL_HIWATER 128
+#define BRCMF_FWS_FLOWCONTROL_LOWATER 64
+
+#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2)
+#define BRCMF_FWS_PSQ_LEN 256
+
+#define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST 0x01
+#define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED 0x02
/**
- * FWFC packet identifier
+ * enum brcmf_fws_skb_state - indicates processing state of skb.
+ *
+ * @BRCMF_FWS_SKBSTATE_NEW: sk_buff is newly arrived in the driver.
+ * @BRCMF_FWS_SKBSTATE_DELAYED: sk_buff had to wait on queue.
+ * @BRCMF_FWS_SKBSTATE_SUPPRESSED: sk_buff has been suppressed by firmware.
+ */
+enum brcmf_fws_skb_state {
+ BRCMF_FWS_SKBSTATE_NEW,
+ BRCMF_FWS_SKBSTATE_DELAYED,
+ BRCMF_FWS_SKBSTATE_SUPPRESSED
+};
+
+/**
+ * struct brcmf_skbuff_cb - control buffer associated with skbuff.
+ *
+ * @if_flags: holds interface index and packet related flags.
+ * @htod: host to device packet identifier (used in PKTTAG tlv).
+ * @state: transmit state of the packet.
+ * @mac: descriptor related to destination for this packet.
+ *
+ * This information is stored in control buffer struct sk_buff::cb, which
+ * provides 48 bytes of storage so this structure should not exceed that.
+ */
+struct brcmf_skbuff_cb {
+ u16 if_flags;
+ u32 htod;
+ enum brcmf_fws_skb_state state;
+ struct brcmf_fws_mac_descriptor *mac;
+};
+
+/*
+ * macro casting skbuff control buffer to struct brcmf_skbuff_cb.
+ */
+#define brcmf_skbcb(skb) ((struct brcmf_skbuff_cb *)((skb)->cb))
+
+/*
+ * sk_buff control if flags
+ *
+ * b[11] - packet sent upon firmware request.
+ * b[10] - packet only contains signalling data.
+ * b[9] - packet is a tx packet.
+ * b[8] - packet uses FIFO credit (non-pspoll).
+ * b[7] - interface in AP mode.
+ * b[6:4] - AC FIFO number.
+ * b[3:0] - interface index.
+ */
+#define BRCMF_SKB_IF_FLAGS_REQUESTED_MASK 0x0800
+#define BRCMF_SKB_IF_FLAGS_REQUESTED_SHIFT 11
+#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_MASK 0x0400
+#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_SHIFT 10
+#define BRCMF_SKB_IF_FLAGS_TRANSMIT_MASK 0x0200
+#define BRCMF_SKB_IF_FLAGS_TRANSMIT_SHIFT 9
+#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK 0x0100
+#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_SHIFT 8
+#define BRCMF_SKB_IF_FLAGS_IF_AP_MASK 0x0080
+#define BRCMF_SKB_IF_FLAGS_IF_AP_SHIFT 7
+#define BRCMF_SKB_IF_FLAGS_FIFO_MASK 0x0070
+#define BRCMF_SKB_IF_FLAGS_FIFO_SHIFT 4
+#define BRCMF_SKB_IF_FLAGS_INDEX_MASK 0x000f
+#define BRCMF_SKB_IF_FLAGS_INDEX_SHIFT 0
+
+#define brcmf_skb_if_flags_set_field(skb, field, value) \
+ brcmu_maskset16(&(brcmf_skbcb(skb)->if_flags), \
+ BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
+ BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT, (value))
+#define brcmf_skb_if_flags_get_field(skb, field) \
+ brcmu_maskget16(brcmf_skbcb(skb)->if_flags, \
+ BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
+ BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT)
+
+/*
+ * sk_buff control packet identifier
*
* 32-bit packet identifier used in PKTTAG tlv from host to dongle.
*
* - Generated at the host (e.g. dhd)
- * - Seen as a generic sequence number by wlc except the flags field
+ * - Seen as a generic sequence number by firmware except for the flags field.
*
* Generation : b[31] => generation number for this packet [host->fw]
* OR, current generation number [fw->host]
@@ -159,35 +230,1057 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
* h-slot : b[23:8] => hanger-slot
* freerun : b[7:0] => A free running counter
*/
-#define BRCMF_FWS_PKTTAG_GENERATION_MASK 0x80000000
-#define BRCMF_FWS_PKTTAG_GENERATION_SHIFT 31
-#define BRCMF_FWS_PKTTAG_FLAGS_MASK 0x78000000
-#define BRCMF_FWS_PKTTAG_FLAGS_SHIFT 27
-#define BRCMF_FWS_PKTTAG_FIFO_MASK 0x07000000
-#define BRCMF_FWS_PKTTAG_FIFO_SHIFT 24
-#define BRCMF_FWS_PKTTAG_HSLOT_MASK 0x00ffff00
-#define BRCMF_FWS_PKTTAG_HSLOT_SHIFT 8
-#define BRCMF_FWS_PKTTAG_FREERUN_MASK 0x000000ff
-#define BRCMF_FWS_PKTTAG_FREERUN_SHIFT 0
-
-#define brcmf_fws_pkttag_set_field(var, field, value) \
- brcmu_maskset32((var), BRCMF_FWS_PKTTAG_ ## field ## _MASK, \
- BRCMF_FWS_PKTTAG_ ## field ## _SHIFT, (value))
-#define brcmf_fws_pkttag_get_field(var, field) \
- brcmu_maskget32((var), BRCMF_FWS_PKTTAG_ ## field ## _MASK, \
- BRCMF_FWS_PKTTAG_ ## field ## _SHIFT)
+#define BRCMF_SKB_HTOD_TAG_GENERATION_MASK 0x80000000
+#define BRCMF_SKB_HTOD_TAG_GENERATION_SHIFT 31
+#define BRCMF_SKB_HTOD_TAG_FLAGS_MASK 0x78000000
+#define BRCMF_SKB_HTOD_TAG_FLAGS_SHIFT 27
+#define BRCMF_SKB_HTOD_TAG_FIFO_MASK 0x07000000
+#define BRCMF_SKB_HTOD_TAG_FIFO_SHIFT 24
+#define BRCMF_SKB_HTOD_TAG_HSLOT_MASK 0x00ffff00
+#define BRCMF_SKB_HTOD_TAG_HSLOT_SHIFT 8
+#define BRCMF_SKB_HTOD_TAG_FREERUN_MASK 0x000000ff
+#define BRCMF_SKB_HTOD_TAG_FREERUN_SHIFT 0
+
+#define brcmf_skb_htod_tag_set_field(skb, field, value) \
+ brcmu_maskset32(&(brcmf_skbcb(skb)->htod), \
+ BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
+ BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT, (value))
+#define brcmf_skb_htod_tag_get_field(skb, field) \
+ brcmu_maskget32(brcmf_skbcb(skb)->htod, \
+ BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
+ BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
+
+#define BRCMF_FWS_TXSTAT_GENERATION_MASK 0x80000000
+#define BRCMF_FWS_TXSTAT_GENERATION_SHIFT 31
+#define BRCMF_FWS_TXSTAT_FLAGS_MASK 0x78000000
+#define BRCMF_FWS_TXSTAT_FLAGS_SHIFT 27
+#define BRCMF_FWS_TXSTAT_FIFO_MASK 0x07000000
+#define BRCMF_FWS_TXSTAT_FIFO_SHIFT 24
+#define BRCMF_FWS_TXSTAT_HSLOT_MASK 0x00FFFF00
+#define BRCMF_FWS_TXSTAT_HSLOT_SHIFT 8
+#define BRCMF_FWS_TXSTAT_PKTID_MASK 0x00FFFFFF
+#define BRCMF_FWS_TXSTAT_PKTID_SHIFT 0
+
+#define brcmf_txstatus_get_field(txs, field) \
+ brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \
+ BRCMF_FWS_TXSTAT_ ## field ## _SHIFT)
+
+/**
+ * enum brcmf_fws_fifo - fifo indices used by dongle firmware.
+ *
+ * @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
+ * @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
+ * @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
+ * @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic.
+ * @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only).
+ * @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only).
+ * @BRCMF_FWS_FIFO_COUNT: number of fifos.
+ */
+enum brcmf_fws_fifo {
+ BRCMF_FWS_FIFO_AC_BK,
+ BRCMF_FWS_FIFO_AC_BE,
+ BRCMF_FWS_FIFO_AC_VI,
+ BRCMF_FWS_FIFO_AC_VO,
+ BRCMF_FWS_FIFO_BCMC,
+ BRCMF_FWS_FIFO_ATIM,
+ BRCMF_FWS_FIFO_COUNT
+};
+
+/**
+ * enum brcmf_fws_txstatus - txstatus flag values.
+ *
+ * @BRCMF_FWS_TXSTATUS_DISCARD:
+ * host is free to discard the packet.
+ * @BRCMF_FWS_TXSTATUS_CORE_SUPPRESS:
+ * 802.11 core suppressed the packet.
+ * @BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS:
+ * firmware suppress the packet as device is already in PS mode.
+ * @BRCMF_FWS_TXSTATUS_FW_TOSSED:
+ * firmware tossed the packet.
+ */
+enum brcmf_fws_txstatus {
+ BRCMF_FWS_TXSTATUS_DISCARD,
+ BRCMF_FWS_TXSTATUS_CORE_SUPPRESS,
+ BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS,
+ BRCMF_FWS_TXSTATUS_FW_TOSSED
+};
+
+enum brcmf_fws_fcmode {
+ BRCMF_FWS_FCMODE_NONE,
+ BRCMF_FWS_FCMODE_IMPLIED_CREDIT,
+ BRCMF_FWS_FCMODE_EXPLICIT_CREDIT
+};
+
+enum brcmf_fws_mac_desc_state {
+ BRCMF_FWS_STATE_OPEN = 1,
+ BRCMF_FWS_STATE_CLOSE
+};
+
+/**
+ * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
+ *
+ * @occupied: slot is in use.
+ * @mac_handle: handle for mac entry determined by firmware.
+ * @interface_id: interface index.
+ * @state: current state.
+ * @suppressed: mac entry is suppressed.
+ * @generation: generation bit.
+ * @ac_bitmap: ac queue bitmap.
+ * @requested_credit: credits requested by firmware.
+ * @ea: ethernet address.
+ * @seq: per-node free-running sequence.
+ * @psq: power-save queue.
+ * @transit_count: packet in transit to firmware.
+ */
+struct brcmf_fws_mac_descriptor {
+ u8 occupied;
+ u8 mac_handle;
+ u8 interface_id;
+ u8 state;
+ bool suppressed;
+ u8 generation;
+ u8 ac_bitmap;
+ u8 requested_credit;
+ u8 requested_packet;
+ u8 ea[ETH_ALEN];
+ u8 seq[BRCMF_FWS_FIFO_COUNT];
+ struct pktq psq;
+ int transit_count;
+ int suppress_count;
+ int suppr_transit_count;
+ bool send_tim_signal;
+ u8 traffic_pending_bmp;
+ u8 traffic_lastreported_bmp;
+};
+
+#define BRCMF_FWS_HANGER_MAXITEMS 1024
+
+/**
+ * enum brcmf_fws_hanger_item_state - state of hanger item.
+ *
+ * @BRCMF_FWS_HANGER_ITEM_STATE_FREE: item is free for use.
+ * @BRCMF_FWS_HANGER_ITEM_STATE_INUSE: item is in use.
+ * @BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED: item was suppressed.
+ */
+enum brcmf_fws_hanger_item_state {
+ BRCMF_FWS_HANGER_ITEM_STATE_FREE = 1,
+ BRCMF_FWS_HANGER_ITEM_STATE_INUSE,
+ BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED
+};
+
+
+/**
+ * struct brcmf_fws_hanger_item - single entry for tx pending packet.
+ *
+ * @state: entry is either free or occupied.
+ * @gen: generation.
+ * @pkt: packet itself.
+ */
+struct brcmf_fws_hanger_item {
+ enum brcmf_fws_hanger_item_state state;
+ u8 gen;
+ struct sk_buff *pkt;
+};
+
+/**
+ * struct brcmf_fws_hanger - holds packets awaiting firmware txstatus.
+ *
+ * @pushed: packets pushed to await txstatus.
+ * @popped: packets popped upon handling txstatus.
+ * @failed_to_push: packets that could not be pushed.
+ * @failed_to_pop: packets that could not be popped.
+ * @failed_slotfind: packets for which failed to find an entry.
+ * @slot_pos: last returned item index for a free entry.
+ * @items: array of hanger items.
+ */
+struct brcmf_fws_hanger {
+ u32 pushed;
+ u32 popped;
+ u32 failed_to_push;
+ u32 failed_to_pop;
+ u32 failed_slotfind;
+ u32 slot_pos;
+ struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS];
+};
+
+struct brcmf_fws_macdesc_table {
+ struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
+ struct brcmf_fws_mac_descriptor iface[BRCMF_MAX_IFS];
+ struct brcmf_fws_mac_descriptor other;
+};
struct brcmf_fws_info {
struct brcmf_pub *drvr;
struct brcmf_fws_stats stats;
+ struct brcmf_fws_hanger hanger;
+ enum brcmf_fws_fcmode fcmode;
+ struct brcmf_fws_macdesc_table desc;
+ struct workqueue_struct *fws_wq;
+ struct work_struct fws_dequeue_work;
+ u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT];
+ int fifo_credit[BRCMF_FWS_FIFO_COUNT];
+ int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
+ u32 fifo_credit_map;
+ u32 fifo_delay_map;
};
+/*
+ * brcmf_fws_prio2fifo - mapping from 802.1d priority to firmware fifo index.
+ */
+static const int brcmf_fws_prio2fifo[] = {
+ BRCMF_FWS_FIFO_AC_BE,
+ BRCMF_FWS_FIFO_AC_BK,
+ BRCMF_FWS_FIFO_AC_BK,
+ BRCMF_FWS_FIFO_AC_BE,
+ BRCMF_FWS_FIFO_AC_VI,
+ BRCMF_FWS_FIFO_AC_VI,
+ BRCMF_FWS_FIFO_AC_VO,
+ BRCMF_FWS_FIFO_AC_VO
+};
+
+static int fcmode;
+module_param(fcmode, int, S_IRUSR);
+MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control");
+
+#define BRCMF_FWS_TLV_DEF(name, id, len) \
+ case BRCMF_FWS_TYPE_ ## name: \
+ return len;
+
+/**
+ * brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
+ *
+ * @fws: firmware-signalling information.
+ * @id: identifier of the TLV.
+ *
+ * Return: the specified length for the given TLV; Otherwise -EINVAL.
+ */
+static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
+ enum brcmf_fws_tlv_type id)
+{
+ switch (id) {
+ BRCMF_FWS_TLV_DEFLIST
+ default:
+ fws->stats.tlv_invalid_type++;
+ break;
+ }
+ return -EINVAL;
+}
+#undef BRCMF_FWS_TLV_DEF
+
+static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
+{
+ u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
+ return ifidx == *(int *)arg;
+}
+
+static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
+ int ifidx)
+{
+ bool (*matchfn)(struct sk_buff *, void *) = NULL;
+ struct sk_buff *skb;
+ int prec;
+
+ if (ifidx != -1)
+ matchfn = brcmf_fws_ifidx_match;
+ for (prec = 0; prec < q->num_prec; prec++) {
+ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
+ while (skb) {
+ brcmu_pkt_buf_free_skb(skb);
+ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
+ }
+ }
+}
+
+static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
+{
+ int i;
+
+ brcmf_dbg(TRACE, "enter\n");
+ memset(hanger, 0, sizeof(*hanger));
+ for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
+ hanger->items[i].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
+}
+
+static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
+{
+ u32 i;
+
+ brcmf_dbg(TRACE, "enter\n");
+ i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
+
+ while (i != h->slot_pos) {
+ if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
+ h->slot_pos = i;
+ goto done;
+ }
+ i++;
+ if (i == BRCMF_FWS_HANGER_MAXITEMS)
+ i = 0;
+ }
+ brcmf_err("all slots occupied\n");
+ h->failed_slotfind++;
+ i = BRCMF_FWS_HANGER_MAXITEMS;
+done:
+ brcmf_dbg(TRACE, "exit: %d\n", i);
+ return i;
+}
+
+static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
+ struct sk_buff *pkt, u32 slot_id)
+{
+ brcmf_dbg(TRACE, "enter\n");
+ if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
+ return -ENOENT;
+
+ if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
+ brcmf_err("slot is not free\n");
+ h->failed_to_push++;
+ return -EINVAL;
+ }
+
+ h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE;
+ h->items[slot_id].pkt = pkt;
+ h->pushed++;
+ return 0;
+}
+
+static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
+ u32 slot_id, struct sk_buff **pktout,
+ bool remove_item)
+{
+ brcmf_dbg(TRACE, "enter\n");
+ if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
+ return -ENOENT;
+
+ if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
+ brcmf_err("entry not in use\n");
+ h->failed_to_pop++;
+ return -EINVAL;
+ }
+
+ *pktout = h->items[slot_id].pkt;
+ if (remove_item) {
+ h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
+ h->items[slot_id].pkt = NULL;
+ h->items[slot_id].gen = 0xff;
+ h->popped++;
+ }
+ return 0;
+}
+
+static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
+ u32 slot_id, u8 gen)
+{
+ brcmf_dbg(TRACE, "enter\n");
+
+ if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
+ return -ENOENT;
+
+ h->items[slot_id].gen = gen;
+
+ if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_INUSE) {
+ brcmf_err("entry not in use\n");
+ return -EINVAL;
+ }
+
+ h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
+ return 0;
+}
+
+static int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger,
+ struct sk_buff *pkt, u32 slot_id,
+ int *gen)
+{
+ brcmf_dbg(TRACE, "enter\n");
+ *gen = 0xff;
+
+ if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
+ return -ENOENT;
+
+ if (hanger->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
+ brcmf_err("slot not in use\n");
+ return -EINVAL;
+ }
+
+ *gen = hanger->items[slot_id].gen;
+ return 0;
+}
+
+static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
+ bool (*fn)(struct sk_buff *, void *),
+ int ifidx)
+{
+ struct brcmf_fws_hanger *h = &fws->hanger;
+ struct sk_buff *skb;
+ int i;
+ enum brcmf_fws_hanger_item_state s;
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ for (i = 0; i < ARRAY_SIZE(h->items); i++) {
+ s = h->items[i].state;
+ if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE ||
+ s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) {
+ skb = h->items[i].pkt;
+ if (fn == NULL || fn(skb, &ifidx)) {
+ /* suppress packets freed from psq */
+ if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE)
+ brcmu_pkt_buf_free_skb(skb);
+ h->items[i].state =
+ BRCMF_FWS_HANGER_ITEM_STATE_FREE;
+ }
+ }
+ }
+}
+
+static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc,
+ u8 *addr, u8 ifidx)
+{
+ brcmf_dbg(TRACE,
+ "enter: desc %p ea=%pM, ifidx=%u\n", desc, addr, ifidx);
+ desc->occupied = 1;
+ desc->state = BRCMF_FWS_STATE_OPEN;
+ desc->requested_credit = 0;
+ /* depending on use may need ifp->bssidx instead */
+ desc->interface_id = ifidx;
+ desc->ac_bitmap = 0xff; /* update this when handling APSD */
+ if (addr)
+ memcpy(&desc->ea[0], addr, ETH_ALEN);
+}
+
+static
+void brcmf_fws_clear_mac_descriptor(struct brcmf_fws_mac_descriptor *desc)
+{
+ brcmf_dbg(TRACE,
+ "enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id);
+ desc->occupied = 0;
+ desc->state = BRCMF_FWS_STATE_CLOSE;
+ desc->requested_credit = 0;
+}
+
+static struct brcmf_fws_mac_descriptor *
+brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+ int i;
+
+ brcmf_dbg(TRACE, "enter: ea=%pM\n", ea);
+ if (ea == NULL)
+ return ERR_PTR(-EINVAL);
+
+ entry = &fws->desc.nodes[0];
+ for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++) {
+ if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN))
+ return entry;
+ entry++;
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+static struct brcmf_fws_mac_descriptor*
+brcmf_fws_find_mac_desc(struct brcmf_fws_info *fws, int ifidx, u8 *da)
+{
+ struct brcmf_fws_mac_descriptor *entry = &fws->desc.other;
+ struct brcmf_if *ifp;
+ bool multicast;
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+
+ multicast = is_multicast_ether_addr(da);
+ ifp = fws->drvr->iflist[ifidx ? ifidx + 1 : 0];
+ if (WARN_ON(!ifp))
+ goto done;
+
+ /* Multicast destination and P2P clients get the interface entry.
+ * STA gets the interface entry if there is no exact match. For
+ * example, TDLS destinations have their own entry.
+ */
+ entry = NULL;
+ if (multicast && ifp->fws_desc)
+ entry = ifp->fws_desc;
+
+ if (entry != NULL && multicast)
+ goto done;
+
+ entry = brcmf_fws_mac_descriptor_lookup(fws, da);
+ if (IS_ERR(entry))
+ entry = &fws->desc.other;
+
+done:
+ brcmf_dbg(TRACE, "exit: entry=%p\n", entry);
+ return entry;
+}
+
+static bool brcmf_fws_mac_desc_ready(struct brcmf_fws_mac_descriptor *entry,
+ int fifo)
+{
+ bool ready;
+
+ /*
+ * destination entry is ready when firmware says it is OPEN
+ * and there are no packets enqueued for it.
+ */
+ ready = entry->state == BRCMF_FWS_STATE_OPEN &&
+ !entry->suppressed &&
+ brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0;
+
+ /*
+ * Or when the destination entry is CLOSED, but firmware has
+ * specifically requested packets for this entry.
+ */
+ ready = ready || (entry->state == BRCMF_FWS_STATE_CLOSE &&
+ (entry->requested_credit + entry->requested_packet));
+ return ready;
+}
+
+static void brcmf_fws_mac_desc_cleanup(struct brcmf_fws_info *fws,
+ struct brcmf_fws_mac_descriptor *entry,
+ int ifidx)
+{
+ brcmf_dbg(TRACE, "enter: entry=(ea=%pM, ifid=%d), ifidx=%d\n",
+ entry->ea, entry->interface_id, ifidx);
+ if (entry->occupied && (ifidx == -1 || ifidx == entry->interface_id)) {
+ brcmf_dbg(TRACE, "flush psq: ifidx=%d, qlen=%d\n",
+ ifidx, entry->psq.len);
+ brcmf_fws_psq_flush(fws, &entry->psq, ifidx);
+ entry->occupied = !!(entry->psq.len);
+ }
+}
+
+static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
+ bool (*fn)(struct sk_buff *, void *),
+ int ifidx)
+{
+ struct brcmf_fws_hanger_item *hi;
+ struct pktq *txq;
+ struct sk_buff *skb;
+ int prec;
+ u32 hslot;
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ txq = brcmf_bus_gettxq(fws->drvr->bus_if);
+ if (IS_ERR(txq)) {
+ brcmf_dbg(TRACE, "no txq to clean up\n");
+ return;
+ }
+
+ for (prec = 0; prec < txq->num_prec; prec++) {
+ skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
+ while (skb) {
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+ hi = &fws->hanger.items[hslot];
+ WARN_ON(skb != hi->pkt);
+ hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
+ brcmu_pkt_buf_free_skb(skb);
+ skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
+ }
+ }
+}
+
+static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
+{
+ int i;
+ struct brcmf_fws_mac_descriptor *table;
+ bool (*matchfn)(struct sk_buff *, void *) = NULL;
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ if (fws == NULL)
+ return;
+
+ if (ifidx != -1)
+ matchfn = brcmf_fws_ifidx_match;
+
+ /* cleanup individual nodes */
+ table = &fws->desc.nodes[0];
+ for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++)
+ brcmf_fws_mac_desc_cleanup(fws, &table[i], ifidx);
+
+ brcmf_fws_mac_desc_cleanup(fws, &fws->desc.other, ifidx);
+ brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx);
+ brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
+}
+
+static void brcmf_fws_tim_update(struct brcmf_fws_info *ctx,
+ struct brcmf_fws_mac_descriptor *entry,
+ int prec)
+{
+ brcmf_dbg(TRACE, "enter: ea=%pM\n", entry->ea);
+ if (entry->state == BRCMF_FWS_STATE_CLOSE) {
+ /* check delayedQ and suppressQ in one call using bitmap */
+ if (brcmu_pktq_mlen(&entry->psq, 3 << (prec * 2)) == 0)
+ entry->traffic_pending_bmp =
+ entry->traffic_pending_bmp & ~NBITVAL(prec);
+ else
+ entry->traffic_pending_bmp =
+ entry->traffic_pending_bmp | NBITVAL(prec);
+ }
+ /* request a TIM update to firmware at the next piggyback opportunity */
+ if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp)
+ entry->send_tim_signal = true;
+}
+
+static void
+brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
+ u8 if_id)
+{
+ struct brcmf_if *ifp = fws->drvr->iflist[if_id];
+
+ brcmf_dbg(TRACE,
+ "enter: bssidx=%d, ifidx=%d\n", ifp->bssidx, ifp->ifidx);
+ if (WARN_ON(!ifp))
+ return;
+
+ if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
+ pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
+ brcmf_txflowblock_if(ifp,
+ BRCMF_NETIF_STOP_REASON_FWS_FC, false);
+ if (!(ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
+ pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER)
+ brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FWS_FC, true);
+ return;
+}
+
static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
{
brcmf_dbg(CTL, "rssi %d\n", rssi);
return 0;
}
+static
+int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry, *existing;
+ u8 mac_handle;
+ u8 ifidx;
+ u8 *addr;
+
+ mac_handle = *data++;
+ ifidx = *data++;
+ addr = data;
+
+ entry = &fws->desc.nodes[mac_handle & 0x1F];
+ if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
+ brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx);
+ if (entry->occupied)
+ brcmf_fws_clear_mac_descriptor(entry);
+ else
+ fws->stats.mac_update_failed++;
+ return 0;
+ }
+
+ brcmf_dbg(TRACE,
+ "add mac %pM handle %u idx %d\n", addr, mac_handle, ifidx);
+ existing = brcmf_fws_mac_descriptor_lookup(fws, addr);
+ if (IS_ERR(existing)) {
+ if (!entry->occupied) {
+ entry->mac_handle = mac_handle;
+ brcmf_fws_init_mac_descriptor(entry, addr, ifidx);
+ brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
+ BRCMF_FWS_PSQ_LEN);
+ } else {
+ fws->stats.mac_update_failed++;
+ }
+ } else {
+ if (entry != existing) {
+ brcmf_dbg(TRACE, "relocate mac\n");
+ memcpy(entry, existing,
+ offsetof(struct brcmf_fws_mac_descriptor, psq));
+ entry->mac_handle = mac_handle;
+ brcmf_fws_clear_mac_descriptor(existing);
+ } else {
+ brcmf_dbg(TRACE, "use existing\n");
+ WARN_ON(entry->mac_handle != mac_handle);
+ /* TODO: what should we do here: continue, reinit, .. */
+ }
+ }
+ return 0;
+}
+
+static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
+ u8 type, u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+ u8 mac_handle;
+ int i;
+
+ mac_handle = data[0];
+ entry = &fws->desc.nodes[mac_handle & 0x1F];
+ if (!entry->occupied) {
+ fws->stats.mac_ps_update_failed++;
+ return -ESRCH;
+ }
+
+ /* a state update should wipe old credits? */
+ entry->requested_credit = 0;
+ if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
+ entry->state = BRCMF_FWS_STATE_OPEN;
+ } else {
+ entry->state = BRCMF_FWS_STATE_CLOSE;
+ for (i = BRCMF_FWS_FIFO_AC_BE; i < NL80211_NUM_ACS; i++)
+ brcmf_fws_tim_update(fws, entry, i);
+ }
+ return 0;
+}
+
+static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
+ u8 type, u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+ u8 ifidx;
+ int ret;
+
+ ifidx = data[0];
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ if (ifidx >= BRCMF_MAX_IFS) {
+ ret = -ERANGE;
+ goto fail;
+ }
+
+ entry = &fws->desc.iface[ifidx];
+ if (!entry->occupied) {
+ ret = -ESRCH;
+ goto fail;
+ }
+
+ switch (type) {
+ case BRCMF_FWS_TYPE_INTERFACE_OPEN:
+ entry->state = BRCMF_FWS_STATE_OPEN;
+ return 0;
+ case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
+ entry->state = BRCMF_FWS_STATE_CLOSE;
+ return 0;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+fail:
+ fws->stats.if_update_failed++;
+ return ret;
+}
+
+static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
+ u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+
+ entry = &fws->desc.nodes[data[1] & 0x1F];
+ if (!entry->occupied) {
+ if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
+ fws->stats.credit_request_failed++;
+ else
+ fws->stats.packet_request_failed++;
+ return -ESRCH;
+ }
+
+ if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
+ entry->requested_credit = data[0];
+ else
+ entry->requested_packet = data[0];
+
+ entry->ac_bitmap = data[2];
+ return 0;
+}
+
+static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
+ u8 fifo, u8 credits)
+{
+ if (!credits)
+ return;
+
+ fws->fifo_credit_map |= 1 << fifo;
+ fws->fifo_credit[fifo] += credits;
+}
+
+static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
+{
+ /* only schedule dequeue when there are credits for delayed traffic */
+ if (fws->fifo_credit_map & fws->fifo_delay_map)
+ queue_work(fws->fws_wq, &fws->fws_dequeue_work);
+}
+
+static void brcmf_skb_pick_up_credit(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *p)
+{
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(p)->mac;
+
+ if (brcmf_skbcb(p)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
+ if (fws->fcmode != BRCMF_FWS_FCMODE_IMPLIED_CREDIT)
+ return;
+ brcmf_fws_return_credits(fws, fifo, 1);
+ } else {
+ /*
+ * if this packet did not count against FIFO credit, it
+ * must have taken a requested_credit from the destination
+ * entry (for pspoll etc.)
+ */
+ if (!brcmf_skb_if_flags_get_field(p, REQUESTED))
+ entry->requested_credit++;
+ }
+ brcmf_fws_schedule_deq(fws);
+}
+
+static int brcmf_fws_enq(struct brcmf_fws_info *fws,
+ enum brcmf_fws_skb_state state, int fifo,
+ struct sk_buff *p)
+{
+ int prec = 2 * fifo;
+ u32 *qfull_stat = &fws->stats.delayq_full_error;
+
+ struct brcmf_fws_mac_descriptor *entry;
+
+ entry = brcmf_skbcb(p)->mac;
+ if (entry == NULL) {
+ brcmf_err("no mac descriptor found for skb %p\n", p);
+ return -ENOENT;
+ }
+
+ brcmf_dbg(TRACE, "enter: ea=%pM, qlen=%d\n", entry->ea, entry->psq.len);
+ if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
+ prec += 1;
+ qfull_stat = &fws->stats.supprq_full_error;
+ }
+
+ if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
+ *qfull_stat += 1;
+ return -ENFILE;
+ }
+
+ /* increment total enqueued packet count */
+ fws->fifo_delay_map |= 1 << fifo;
+ fws->fifo_enqpkt[fifo]++;
+
+ /* update the sk_buff state */
+ brcmf_skbcb(p)->state = state;
+ if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
+ entry->suppress_count++;
+
+ /*
+ * A packet has been pushed so update traffic
+ * availability bitmap, if applicable
+ */
+ brcmf_fws_tim_update(fws, entry, fifo);
+ brcmf_fws_flow_control_check(fws, &entry->psq,
+ brcmf_skb_if_flags_get_field(p, INDEX));
+ return 0;
+}
+
+static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
+{
+ struct brcmf_fws_mac_descriptor *table;
+ struct brcmf_fws_mac_descriptor *entry;
+ struct sk_buff *p;
+ int use_credit = 1;
+ int num_nodes;
+ int node_pos;
+ int prec_out;
+ int pmsk = 3;
+ int i;
+
+ table = (struct brcmf_fws_mac_descriptor *)&fws->desc;
+ num_nodes = sizeof(fws->desc) / sizeof(struct brcmf_fws_mac_descriptor);
+ node_pos = fws->deq_node_pos[fifo];
+
+ for (i = 0; i < num_nodes; i++) {
+ entry = &table[(node_pos + i) % num_nodes];
+ if (!entry->occupied)
+ continue;
+
+ if (entry->suppressed)
+ pmsk = 2;
+ p = brcmu_pktq_mdeq(&entry->psq, pmsk << (fifo * 2), &prec_out);
+ if (p == NULL) {
+ if (entry->suppressed) {
+ if (entry->suppr_transit_count >
+ entry->suppress_count)
+ return NULL;
+ entry->suppressed = false;
+ p = brcmu_pktq_mdeq(&entry->psq,
+ 1 << (fifo * 2), &prec_out);
+ }
+ }
+ if (p == NULL)
+ continue;
+
+ /* did the packet come from suppress sub-queue? */
+ if (entry->requested_credit > 0) {
+ entry->requested_credit--;
+ /*
+ * if the packet was pulled out while destination is in
+ * closed state but had a non-zero packets requested,
+ * then this should not count against the FIFO credit.
+ * That is due to the fact that the firmware will
+ * most likely hold onto this packet until a suitable
+ * time later to push it to the appropriate AC FIFO.
+ */
+ if (entry->state == BRCMF_FWS_STATE_CLOSE)
+ use_credit = 0;
+ } else if (entry->requested_packet > 0) {
+ entry->requested_packet--;
+ brcmf_skb_if_flags_set_field(p, REQUESTED, 1);
+ if (entry->state == BRCMF_FWS_STATE_CLOSE)
+ use_credit = 0;
+ }
+ brcmf_skb_if_flags_set_field(p, CREDITCHECK, use_credit);
+
+ /* move dequeue position to ensure fair round-robin */
+ fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
+ brcmf_fws_flow_control_check(fws, &entry->psq,
+ brcmf_skb_if_flags_get_field(p,
+ INDEX)
+ );
+ /*
+ * A packet has been picked up, update traffic
+ * availability bitmap, if applicable
+ */
+ brcmf_fws_tim_update(fws, entry, fifo);
+
+ /*
+ * decrement total enqueued fifo packets and
+ * clear delay bitmap if done.
+ */
+ fws->fifo_enqpkt[fifo]--;
+ if (fws->fifo_enqpkt[fifo] == 0)
+ fws->fifo_delay_map &= ~(1 << fifo);
+ goto done;
+ }
+ p = NULL;
+done:
+ brcmf_dbg(TRACE, "exit: fifo %d skb %p\n", fifo, p);
+ return p;
+}
+
+static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *skb, u32 genbit)
+{
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+ u32 hslot;
+ int ret;
+
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+
+ /* this packet was suppressed */
+ if (!entry->suppressed || entry->generation != genbit) {
+ entry->suppressed = true;
+ entry->suppress_count = brcmu_pktq_mlen(&entry->psq,
+ 1 << (fifo * 2 + 1));
+ entry->suppr_transit_count = entry->transit_count;
+ }
+
+ entry->generation = genbit;
+
+ ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb);
+ if (ret != 0) {
+ /* suppress q is full, drop this packet */
+ brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
+ true);
+ } else {
+ /*
+ * Mark suppressed to avoid a double free during
+ * wlfc cleanup
+ */
+ brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot,
+ genbit);
+ entry->suppress_count++;
+ }
+
+ return ret;
+}
+
+static int
+brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
+ u32 genbit)
+{
+ u32 fifo;
+ int ret;
+ bool remove_from_hanger = true;
+ struct sk_buff *skb;
+ struct brcmf_fws_mac_descriptor *entry = NULL;
+
+ brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n",
+ flags, hslot);
+
+ if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
+ fws->stats.txs_discard++;
+ else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) {
+ fws->stats.txs_supp_core++;
+ remove_from_hanger = false;
+ } else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
+ fws->stats.txs_supp_ps++;
+ remove_from_hanger = false;
+ } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
+ fws->stats.txs_tossed++;
+ else
+ brcmf_err("unexpected txstatus\n");
+
+ ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
+ remove_from_hanger);
+ if (ret != 0) {
+ brcmf_err("no packet in hanger slot: hslot=%d\n", hslot);
+ return ret;
+ }
+
+ entry = brcmf_skbcb(skb)->mac;
+ if (WARN_ON(!entry)) {
+ brcmu_pkt_buf_free_skb(skb);
+ return -EINVAL;
+ }
+
+ /* pick up the implicit credit from this packet */
+ fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
+ brcmf_skb_pick_up_credit(fws, fifo, skb);
+
+ if (!remove_from_hanger)
+ ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit);
+
+ if (remove_from_hanger || ret) {
+ entry->transit_count--;
+ if (entry->suppressed)
+ entry->suppr_transit_count--;
+
+ brcmf_txfinalize(fws->drvr, skb, true);
+ }
+ return 0;
+}
+
+static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
+ u8 *data)
+{
+ int i;
+
+ if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
+ brcmf_dbg(INFO, "ignored\n");
+ return 0;
+ }
+
+ brcmf_dbg(TRACE, "enter: data %pM\n", data);
+ for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
+ brcmf_fws_return_credits(fws, i, data[i]);
+
+ brcmf_dbg(INFO, "map: credit %x delay %x\n", fws->fifo_credit_map,
+ fws->fifo_delay_map);
+ brcmf_fws_schedule_deq(fws);
+ return 0;
+}
+
+static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
+{
+ __le32 status_le;
+ u32 status;
+ u32 hslot;
+ u32 genbit;
+ u8 flags;
+
+ fws->stats.txs_indicate++;
+ memcpy(&status_le, data, sizeof(status_le));
+ status = le32_to_cpu(status_le);
+ flags = brcmf_txstatus_get_field(status, FLAGS);
+ hslot = brcmf_txstatus_get_field(status, HSLOT);
+ genbit = brcmf_txstatus_get_field(status, GENERATION);
+
+ return brcmf_fws_txstatus_process(fws, flags, hslot, genbit);
+}
+
static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
{
__le32 timestamp;
@@ -213,51 +1306,32 @@ do { \
#define brcmf_fws_unlock(drvr, flags) \
spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags))
-int brcmf_fws_init(struct brcmf_pub *drvr)
+static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data)
{
- u32 tlv;
- int rc;
-
- /* enable rssi signals */
- tlv = drvr->fw_signals ? BRCMF_FWS_FLAGS_RSSI_SIGNALS : 0;
-
- spin_lock_init(&drvr->fws_spinlock);
+ struct brcmf_fws_info *fws = ifp->drvr->fws;
+ int i;
+ ulong flags;
+ u8 *credits = data;
- drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
- if (!drvr->fws) {
- rc = -ENOMEM;
- goto fail;
+ if (e->datalen < BRCMF_FWS_FIFO_COUNT) {
+ brcmf_err("event payload too small (%d)\n", e->datalen);
+ return -EINVAL;
}
- /* enable proptxtstatus signaling by default */
- rc = brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv);
- if (rc < 0) {
- brcmf_err("failed to set bdcv2 tlv signaling\n");
- goto fail;
+ brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
+ brcmf_fws_lock(ifp->drvr, flags);
+ for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) {
+ if (*credits)
+ fws->fifo_credit_map |= 1 << i;
+ else
+ fws->fifo_credit_map &= ~(1 << i);
+ fws->fifo_credit[i] = *credits++;
}
- /* set linkage back */
- drvr->fws->drvr = drvr;
-
- /* create debugfs file for statistics */
- brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats);
-
- /* TODO: remove upon feature delivery */
- brcmf_err("%s bdcv2 tlv signaling [%x]\n",
- drvr->fw_signals ? "enabled" : "disabled", tlv);
+ brcmf_fws_schedule_deq(fws);
+ brcmf_fws_unlock(ifp->drvr, flags);
return 0;
-
-fail:
- /* disable flow control entirely */
- drvr->fw_signals = false;
- brcmf_fws_deinit(drvr);
- return rc;
-}
-
-void brcmf_fws_deinit(struct brcmf_pub *drvr)
-{
- /* free top structure */
- kfree(drvr->fws);
- drvr->fws = NULL;
}
int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
@@ -304,57 +1378,50 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
len = signal_data[1];
data = signal_data + 2;
+ brcmf_dbg(INFO, "tlv type=%d (%s), len=%d, data[0]=%d\n", type,
+ brcmf_fws_get_tlv_name(type), len, *data);
+
/* abort parsing when length invalid */
if (data_len < len + 2)
break;
- brcmf_dbg(INFO, "tlv type=%d (%s), len=%d\n", type,
- brcmf_fws_get_tlv_name(type), len);
- switch (type) {
- case BRCMF_FWS_TYPE_MAC_OPEN:
- case BRCMF_FWS_TYPE_MAC_CLOSE:
- WARN_ON(len != BRCMF_FWS_TYPE_MAC_OPEN_LEN);
- break;
- case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
- WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT_LEN);
- break;
- case BRCMF_FWS_TYPE_TXSTATUS:
- WARN_ON(len != BRCMF_FWS_TYPE_TXSTATUS_LEN);
+ if (len != brcmf_fws_get_tlv_len(fws, type))
break;
- case BRCMF_FWS_TYPE_PKTTAG:
- WARN_ON(len != BRCMF_FWS_TYPE_PKTTAG_LEN);
+
+ switch (type) {
+ case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
+ case BRCMF_FWS_TYPE_COMP_TXSTATUS:
break;
case BRCMF_FWS_TYPE_MACDESC_ADD:
case BRCMF_FWS_TYPE_MACDESC_DEL:
- WARN_ON(len != BRCMF_FWS_TYPE_MACDESC_ADD_LEN);
+ brcmf_fws_macdesc_indicate(fws, type, data);
break;
- case BRCMF_FWS_TYPE_RSSI:
- WARN_ON(len != BRCMF_FWS_TYPE_RSSI_LEN);
- brcmf_fws_rssi_indicate(fws, *(s8 *)data);
+ case BRCMF_FWS_TYPE_MAC_OPEN:
+ case BRCMF_FWS_TYPE_MAC_CLOSE:
+ brcmf_fws_macdesc_state_indicate(fws, type, data);
break;
case BRCMF_FWS_TYPE_INTERFACE_OPEN:
case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
- WARN_ON(len != BRCMF_FWS_TYPE_INTERFACE_OPEN_LEN);
+ brcmf_fws_interface_state_indicate(fws, type, data);
break;
- case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
- WARN_ON(len != BRCMF_FWS_TYPE_FIFO_CREDITBACK_LEN);
+ case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
+ case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
+ brcmf_fws_request_indicate(fws, type, data);
break;
- case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
- WARN_ON(len != BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN);
+ case BRCMF_FWS_TYPE_TXSTATUS:
+ brcmf_fws_txstatus_indicate(fws, data);
break;
- case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
- WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_PACKET_LEN);
+ case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
+ brcmf_fws_fifocreditback_indicate(fws, data);
break;
- case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
- WARN_ON(len != BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS_LEN);
+ case BRCMF_FWS_TYPE_RSSI:
+ brcmf_fws_rssi_indicate(fws, *data);
break;
case BRCMF_FWS_TYPE_TRANS_ID:
- WARN_ON(len != BRCMF_FWS_TYPE_TRANS_ID_LEN);
brcmf_fws_dbg_seqnum_check(fws, data);
break;
- case BRCMF_FWS_TYPE_COMP_TXSTATUS:
- WARN_ON(len != BRCMF_FWS_TYPE_COMP_TXSTATUS_LEN);
- break;
+ case BRCMF_FWS_TYPE_PKTTAG:
+ case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
default:
fws->stats.tlv_invalid_type++;
break;
@@ -380,3 +1447,505 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
brcmf_fws_unlock(drvr, flags);
return 0;
}
+
+static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
+{
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+ u8 *wlh;
+ u16 data_offset = 0;
+ u8 fillers;
+ __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
+
+ brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u, pkttag=0x%08X\n",
+ entry->ea, entry->interface_id, le32_to_cpu(pkttag));
+ if (entry->send_tim_signal)
+ data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
+
+ /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
+ data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
+ fillers = round_up(data_offset, 4) - data_offset;
+ data_offset += fillers;
+
+ skb_push(skb, data_offset);
+ wlh = skb->data;
+
+ wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
+ wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
+ memcpy(&wlh[2], &pkttag, sizeof(pkttag));
+ wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
+
+ if (entry->send_tim_signal) {
+ entry->send_tim_signal = 0;
+ wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
+ wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
+ wlh[2] = entry->mac_handle;
+ wlh[3] = entry->traffic_pending_bmp;
+ wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
+ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
+ }
+ if (fillers)
+ memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
+
+ brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX),
+ data_offset >> 2, skb);
+ return 0;
+}
+
+static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *p)
+{
+ struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
+ struct brcmf_fws_mac_descriptor *entry = skcb->mac;
+ int rc = 0;
+ bool header_needed;
+ int hslot = BRCMF_FWS_HANGER_MAXITEMS;
+ u8 free_ctr;
+ u8 ifidx;
+ u8 flags;
+
+ header_needed = skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED;
+
+ if (header_needed) {
+ /* obtaining free slot may fail, but that will be caught
+ * by the hanger push. This assures the packet has a BDC
+ * header upon return.
+ */
+ hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
+ free_ctr = entry->seq[fifo];
+ brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
+ brcmf_skb_htod_tag_set_field(p, FREERUN, free_ctr);
+ brcmf_skb_htod_tag_set_field(p, GENERATION, 1);
+ entry->transit_count++;
+ }
+ brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
+ brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
+
+ flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
+ if (!(skcb->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)) {
+ /*
+ Indicate that this packet is being sent in response to an
+ explicit request from the firmware side.
+ */
+ flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
+ }
+ brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
+ if (header_needed) {
+ brcmf_fws_hdrpush(fws, p);
+ rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
+ if (rc)
+ brcmf_err("hanger push failed: rc=%d\n", rc);
+ } else {
+ int gen;
+
+ /* remove old header */
+ rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, p);
+ if (rc == 0) {
+ hslot = brcmf_skb_htod_tag_get_field(p, HSLOT);
+ brcmf_fws_hanger_get_genbit(&fws->hanger, p,
+ hslot, &gen);
+ brcmf_skb_htod_tag_set_field(p, GENERATION, gen);
+
+ /* push new header */
+ brcmf_fws_hdrpush(fws, p);
+ }
+ }
+
+ return rc;
+}
+
+static int
+brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, struct sk_buff *skb)
+{
+ /*
+ put the packet back to the head of queue
+
+ - suppressed packet goes back to suppress sub-queue
+ - pull out the header, if new or delayed packet
+
+ Note: hslot is used only when header removal is done.
+ */
+ struct brcmf_fws_mac_descriptor *entry;
+ enum brcmf_fws_skb_state state;
+ struct sk_buff *pktout;
+ int rc = 0;
+ int fifo;
+ int hslot;
+ u8 ifidx;
+
+ fifo = brcmf_skb_if_flags_get_field(skb, FIFO);
+ state = brcmf_skbcb(skb)->state;
+ entry = brcmf_skbcb(skb)->mac;
+
+ if (entry != NULL) {
+ if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
+ /* wl-header is saved for suppressed packets */
+ pktout = brcmu_pktq_penq_head(&entry->psq, 2 * fifo + 1,
+ skb);
+ if (pktout == NULL) {
+ brcmf_err("suppress queue full\n");
+ rc = -ENOSPC;
+ }
+ } else {
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+
+ /* remove header first */
+ rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
+ if (rc) {
+ brcmf_err("header removal failed\n");
+ /* free the hanger slot */
+ brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
+ &pktout, true);
+ brcmf_txfinalize(fws->drvr, skb, false);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ /* delay-q packets are going to delay-q */
+ pktout = brcmu_pktq_penq_head(&entry->psq,
+ 2 * fifo, skb);
+ if (pktout == NULL) {
+ brcmf_err("delay queue full\n");
+ rc = -ENOSPC;
+ }
+
+ /* free the hanger slot */
+ brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &pktout,
+ true);
+
+ /* decrement sequence count */
+ entry->seq[fifo]--;
+ }
+ /*
+ if this packet did not count against FIFO credit, it must have
+ taken a requested_credit from the firmware (for pspoll etc.)
+ */
+ if (!(brcmf_skbcb(skb)->if_flags &
+ BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK))
+ entry->requested_credit++;
+ } else {
+ brcmf_err("no mac entry linked\n");
+ rc = -ENOENT;
+ }
+
+
+fail:
+ if (rc)
+ fws->stats.rollback_failed++;
+ else
+ fws->stats.rollback_success++;
+ return rc;
+}
+
+static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *skb)
+{
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+ int *credit = &fws->fifo_credit[fifo];
+ int use_credit = 1;
+
+ brcmf_dbg(TRACE, "enter: ac=%d, credits=%d\n", fifo, *credit);
+
+ if (entry->requested_credit > 0) {
+ /*
+ * if the packet was pulled out while destination is in
+ * closed state but had a non-zero packets requested,
+ * then this should not count against the FIFO credit.
+ * That is due to the fact that the firmware will
+ * most likely hold onto this packet until a suitable
+ * time later to push it to the appropriate AC FIFO.
+ */
+ entry->requested_credit--;
+ if (entry->state == BRCMF_FWS_STATE_CLOSE)
+ use_credit = 0;
+ } else if (entry->requested_packet > 0) {
+ entry->requested_packet--;
+ brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
+ if (entry->state == BRCMF_FWS_STATE_CLOSE)
+ use_credit = 0;
+ }
+ brcmf_skb_if_flags_set_field(skb, CREDITCHECK, use_credit);
+ if (!use_credit) {
+ brcmf_dbg(TRACE, "exit: no creditcheck set\n");
+ return 0;
+ }
+
+ if (!(*credit)) {
+ brcmf_dbg(TRACE, "exit: credits depleted\n");
+ return -ENAVAIL;
+ }
+ (*credit)--;
+ if (!(*credit))
+ fws->fifo_credit_map &= ~(1 << fifo);
+ brcmf_dbg(TRACE, "exit: ac=%d, credits=%d\n", fifo, *credit);
+ return 0;
+}
+
+static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *skb)
+{
+ struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
+ struct brcmf_fws_mac_descriptor *entry;
+ struct brcmf_bus *bus = fws->drvr->bus_if;
+ int rc;
+
+ entry = skcb->mac;
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ rc = brcmf_fws_precommit_skb(fws, fifo, skb);
+ if (rc < 0) {
+ fws->stats.generic_error++;
+ goto rollback;
+ }
+
+ rc = brcmf_bus_txdata(bus, skb);
+ if (rc < 0)
+ goto rollback;
+
+ entry->seq[fifo]++;
+ fws->stats.pkt2bus++;
+ if (brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
+ fws->stats.send_pkts[fifo]++;
+ fws->stats.fifo_credits_sent[fifo]++;
+ }
+
+ return rc;
+
+rollback:
+ rc = brcmf_fws_rollback_toq(fws, skb);
+ return rc;
+}
+
+int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
+{
+ struct brcmf_pub *drvr = ifp->drvr;
+ struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
+ struct ethhdr *eh = (struct ethhdr *)(skb->data);
+ ulong flags;
+ u8 ifidx = ifp->ifidx;
+ int fifo = BRCMF_FWS_FIFO_BCMC;
+ bool multicast = is_multicast_ether_addr(eh->h_dest);
+
+ /* determine the priority */
+ if (!skb->priority)
+ skb->priority = cfg80211_classify8021d(skb);
+
+ drvr->tx_multicast += !!multicast;
+ if (ntohs(eh->h_proto) == ETH_P_PAE)
+ atomic_inc(&ifp->pend_8021x_cnt);
+
+ if (!brcmf_fws_fc_active(drvr->fws)) {
+ /* If the protocol uses a data header, apply it */
+ brcmf_proto_hdrpush(drvr, ifidx, 0, skb);
+
+ /* Use bus module to send data frame */
+ return brcmf_bus_txdata(drvr->bus_if, skb);
+ }
+
+ /* set control buffer information */
+ skcb->if_flags = 0;
+ skcb->mac = brcmf_fws_find_mac_desc(drvr->fws, ifidx, eh->h_dest);
+ skcb->state = BRCMF_FWS_SKBSTATE_NEW;
+ brcmf_skb_if_flags_set_field(skb, INDEX, ifidx);
+ if (!multicast)
+ fifo = brcmf_fws_prio2fifo[skb->priority];
+ brcmf_skb_if_flags_set_field(skb, FIFO, fifo);
+
+ brcmf_dbg(TRACE, "ea=%pM, multi=%d, fifo=%d\n", eh->h_dest,
+ multicast, fifo);
+
+ brcmf_fws_lock(drvr, flags);
+ if (!brcmf_fws_mac_desc_ready(skcb->mac, fifo) ||
+ (!multicast &&
+ brcmf_fws_consume_credit(drvr->fws, fifo, skb) < 0)) {
+ /* enqueue the packet in delayQ */
+ drvr->fws->fifo_delay_map |= 1 << fifo;
+ brcmf_fws_enq(drvr->fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
+ } else {
+ brcmf_fws_commit_skb(drvr->fws, fifo, skb);
+ }
+ brcmf_fws_unlock(drvr, flags);
+ return 0;
+}
+
+void brcmf_fws_reset_interface(struct brcmf_if *ifp)
+{
+ struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
+
+ brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
+ if (!entry)
+ return;
+
+ brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx);
+}
+
+void brcmf_fws_add_interface(struct brcmf_if *ifp)
+{
+ struct brcmf_fws_info *fws = ifp->drvr->fws;
+ struct brcmf_fws_mac_descriptor *entry;
+
+ brcmf_dbg(TRACE, "enter: idx=%d, mac=%pM\n",
+ ifp->bssidx, ifp->mac_addr);
+ if (!ifp->ndev || !ifp->drvr->fw_signals)
+ return;
+
+ entry = &fws->desc.iface[ifp->ifidx];
+ ifp->fws_desc = entry;
+ brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx);
+ brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
+ BRCMF_FWS_PSQ_LEN);
+}
+
+void brcmf_fws_del_interface(struct brcmf_if *ifp)
+{
+ struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
+
+ brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
+ if (!entry)
+ return;
+
+ ifp->fws_desc = NULL;
+ brcmf_fws_clear_mac_descriptor(entry);
+ brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
+}
+
+static void brcmf_fws_dequeue_worker(struct work_struct *worker)
+{
+ struct brcmf_fws_info *fws;
+ struct sk_buff *skb;
+ ulong flags;
+ int fifo;
+ int credit;
+
+ fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
+
+ brcmf_dbg(TRACE, "enter: fws=%p\n", fws);
+ brcmf_fws_lock(fws->drvr, flags);
+ for (fifo = NL80211_NUM_ACS; fifo >= 0; fifo--) {
+ brcmf_dbg(TRACE, "fifo %d credit %d\n", fifo,
+ fws->fifo_credit[fifo]);
+ for (credit = 0; credit < fws->fifo_credit[fifo]; /* nop */) {
+ skb = brcmf_fws_deq(fws, fifo);
+ if (!skb)
+ break;
+ if (!brcmf_fws_commit_skb(fws, fifo, skb) &&
+ brcmf_skbcb(skb)->if_flags &
+ BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
+ credit++;
+ }
+ fws->fifo_credit[fifo] -= credit;
+ }
+ brcmf_fws_unlock(fws->drvr, flags);
+}
+
+int brcmf_fws_init(struct brcmf_pub *drvr)
+{
+ u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
+ int rc;
+
+ if (!drvr->fw_signals)
+ return 0;
+
+ spin_lock_init(&drvr->fws_spinlock);
+
+ drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
+ if (!drvr->fws) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ /* set linkage back */
+ drvr->fws->drvr = drvr;
+ drvr->fws->fcmode = fcmode;
+
+ drvr->fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
+ if (drvr->fws->fws_wq == NULL) {
+ brcmf_err("workqueue creation failed\n");
+ rc = -EBADF;
+ goto fail;
+ }
+ INIT_WORK(&drvr->fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
+
+ /* enable firmware signalling if fcmode active */
+ if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE)
+ tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
+ BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
+ BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE;
+
+ rc = brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv);
+ if (rc < 0) {
+ brcmf_err("failed to set bdcv2 tlv signaling\n");
+ goto fail;
+ }
+
+ if (brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP,
+ brcmf_fws_notify_credit_map)) {
+ brcmf_err("register credit map handler failed\n");
+ goto fail;
+ }
+
+ brcmf_fws_hanger_init(&drvr->fws->hanger);
+ brcmf_fws_init_mac_descriptor(&drvr->fws->desc.other, NULL, 0);
+ brcmu_pktq_init(&drvr->fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
+ BRCMF_FWS_PSQ_LEN);
+
+ /* create debugfs file for statistics */
+ brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats);
+
+ /* TODO: remove upon feature delivery */
+ brcmf_err("%s bdcv2 tlv signaling [%x]\n",
+ drvr->fw_signals ? "enabled" : "disabled", tlv);
+ return 0;
+
+fail:
+ /* disable flow control entirely */
+ drvr->fw_signals = false;
+ brcmf_fws_deinit(drvr);
+ return rc;
+}
+
+void brcmf_fws_deinit(struct brcmf_pub *drvr)
+{
+ struct brcmf_fws_info *fws = drvr->fws;
+ ulong flags;
+
+ if (!fws)
+ return;
+
+ /* cleanup */
+ brcmf_fws_lock(drvr, flags);
+ brcmf_fws_cleanup(fws, -1);
+ drvr->fws = NULL;
+ brcmf_fws_unlock(drvr, flags);
+
+ /* free top structure */
+ kfree(fws);
+}
+
+bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
+{
+ if (!fws)
+ return false;
+
+ brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode);
+ return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
+}
+
+void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
+{
+ ulong flags;
+
+ brcmf_fws_lock(fws->drvr, flags);
+ brcmf_fws_txstatus_process(fws, BRCMF_FWS_TXSTATUS_FW_TOSSED,
+ brcmf_skb_htod_tag_get_field(skb, HSLOT), 0);
+ /* the packet never reached firmware so reclaim credit */
+ if (fws->fcmode == BRCMF_FWS_FCMODE_EXPLICIT_CREDIT &&
+ brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
+ brcmf_fws_return_credits(fws,
+ brcmf_skb_htod_tag_get_field(skb,
+ FIFO),
+ 1);
+ brcmf_fws_schedule_deq(fws);
+ }
+ brcmf_fws_unlock(fws->drvr, flags);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
index e728eea72bb4..fbe483d23752 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
@@ -20,6 +20,14 @@
int brcmf_fws_init(struct brcmf_pub *drvr);
void brcmf_fws_deinit(struct brcmf_pub *drvr);
+bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
struct sk_buff *skb);
+int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb);
+
+void brcmf_fws_reset_interface(struct brcmf_if *ifp);
+void brcmf_fws_add_interface(struct brcmf_if *ifp);
+void brcmf_fws_del_interface(struct brcmf_if *ifp);
+void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
+
#endif /* FWSIGNAL_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index 4166e642068b..94ff045df2b3 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -15,6 +15,7 @@
*/
#include <linux/slab.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <net/cfg80211.h>
#include <brcmu_wifi.h>
@@ -455,7 +456,9 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
{
s32 ret = 0;
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
brcmf_fil_iovar_int_set(ifp, "apsta", 1);
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
/* In case of COB type, firmware has default mac address
* After Initializing firmware, we have to set current mac address to
@@ -473,28 +476,35 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
* brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P.
*
* @p2p: P2P specific data.
+ * @dev_addr: optional device address.
*
- * P2P needs mac addresses for P2P device and interface. These are
- * derived from the primary net device, ie. the permanent ethernet
- * address of the device.
+ * P2P needs mac addresses for P2P device and interface. If no device
+ * address it specified, these are derived from the primary net device, ie.
+ * the permanent ethernet address of the device.
*/
-static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p)
+static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
{
struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
- struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
+ bool local_admin = false;
+
+ if (!dev_addr || is_zero_ether_addr(dev_addr)) {
+ dev_addr = pri_ifp->mac_addr;
+ local_admin = true;
+ }
/* Generate the P2P Device Address. This consists of the device's
* primary MAC address with the locally administered bit set.
*/
- memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN);
- p2p->dev_addr[0] |= 0x02;
- memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+ memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
+ if (local_admin)
+ p2p->dev_addr[0] |= 0x02;
/* Generate the P2P Interface Address. If the discovery and connection
* BSSCFGs need to simultaneously co-exist, then this address must be
* different from the P2P Device Address, but also locally administered.
*/
memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN);
+ p2p->int_addr[0] |= 0x02;
p2p->int_addr[4] ^= 0x80;
}
@@ -773,7 +783,7 @@ exit:
* validates the channels in the request.
*/
static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
+ struct brcmf_if *ifp,
struct cfg80211_scan_request *request,
u16 action)
{
@@ -1261,7 +1271,7 @@ static void
brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
{
struct brcmf_p2p_info *p2p = &cfg->p2p;
- struct net_device *ndev = cfg->escan_info.ndev;
+ struct brcmf_if *ifp = cfg->escan_info.ifp;
if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
(test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
@@ -1271,12 +1281,12 @@ brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
* So abort scan for off channel completion.
*/
if (p2p->af_sent_channel)
- brcmf_notify_escan_complete(cfg, ndev, true, true);
+ brcmf_notify_escan_complete(cfg, ifp, true, true);
} else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
&p2p->status)) {
brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n");
/* So abort scan to cancel listen */
- brcmf_notify_escan_complete(cfg, ndev, true, true);
+ brcmf_notify_escan_complete(cfg, ifp, true, true);
}
}
@@ -1384,7 +1394,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
/* After complete GO Negotiation, roll back to mpc mode */
if ((action == P2P_PAF_GON_CONF) ||
(action == P2P_PAF_PROVDIS_RSP))
- brcmf_set_mpc(ifp->ndev, 1);
+ brcmf_set_mpc(ifp, 1);
if (action == P2P_PAF_GON_CONF) {
brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
@@ -1421,7 +1431,8 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
CHSPEC_IS2G(chanspec) ?
IEEE80211_BAND_2GHZ :
IEEE80211_BAND_5GHZ);
- wdev = ifp->ndev->ieee80211_ptr;
+
+ wdev = &ifp->vif->wdev;
cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
GFP_ATOMIC);
@@ -1637,6 +1648,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
struct brcmf_fil_af_params_le *af_params)
{
struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_fil_action_frame_le *action_frame;
struct brcmf_config_af_params config_af_params;
struct afx_hdl *afx_hdl = &p2p->afx_hdl;
@@ -1725,7 +1737,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
/* To make sure to send successfully action frame, turn off mpc */
if (config_af_params.mpc_onoff == 0)
- brcmf_set_mpc(ndev, 0);
+ brcmf_set_mpc(ifp, 0);
/* set status and destination address before sending af */
if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
@@ -1753,7 +1765,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
* care of current piggback algo, lets abort the scan here
* itself.
*/
- brcmf_notify_escan_complete(cfg, ndev, true, true);
+ brcmf_notify_escan_complete(cfg, ifp, true, true);
/* update channel */
af_params->channel = cpu_to_le32(afx_hdl->peer_chan);
@@ -1820,7 +1832,7 @@ exit:
clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
/* if all done, turn mpc on again */
if (config_af_params.mpc_onoff == 1)
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
return ack;
}
@@ -1839,7 +1851,6 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
struct brcmf_p2p_info *p2p = &cfg->p2p;
struct afx_hdl *afx_hdl = &p2p->afx_hdl;
- struct wireless_dev *wdev;
struct brcmf_cfg80211_vif *vif = ifp->vif;
struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
u16 chanspec = be16_to_cpu(rxframe->chanspec);
@@ -1882,8 +1893,9 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
CHSPEC_IS2G(chanspec) ?
IEEE80211_BAND_2GHZ :
IEEE80211_BAND_5GHZ);
- wdev = ifp->ndev->ieee80211_ptr;
- cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len,
+ GFP_ATOMIC);
brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
mgmt_frame_len, e->datalen, chanspec, freq);
@@ -1934,7 +1946,8 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
- brcmf_p2p_generate_bss_mac(p2p);
+ brcmf_p2p_generate_bss_mac(p2p, NULL);
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
/* Initialize P2P Discovery in the firmware */
@@ -2040,13 +2053,13 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n");
return -EPERM;
}
- brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true);
+ brcmf_notify_escan_complete(cfg, vif->ifp, true, true);
vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
if (!vif) {
brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n");
return -EPERM;
}
- brcmf_set_mpc(vif->ifp->ndev, 0);
+ brcmf_set_mpc(vif->ifp, 0);
/* In concurrency case, STA may be already associated in a particular */
/* channel. so retrieve the current channel of primary interface and */
@@ -2124,13 +2137,105 @@ static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)
}
/**
+ * brcmf_p2p_create_p2pdev() - create a P2P_DEVICE virtual interface.
+ *
+ * @p2p: P2P specific data.
+ * @wiphy: wiphy device of new interface.
+ * @addr: mac address for this new interface.
+ */
+static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
+ struct wiphy *wiphy,
+ u8 *addr)
+{
+ struct brcmf_cfg80211_vif *p2p_vif;
+ struct brcmf_if *p2p_ifp;
+ struct brcmf_if *pri_ifp;
+ int err;
+ u32 bssidx;
+
+ if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+ return ERR_PTR(-ENOSPC);
+
+ p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE,
+ false);
+ if (IS_ERR(p2p_vif)) {
+ brcmf_err("could not create discovery vif\n");
+ return (struct wireless_dev *)p2p_vif;
+ }
+
+ pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+ brcmf_p2p_generate_bss_mac(p2p, addr);
+ brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, p2p_vif);
+
+ /* Initialize P2P Discovery in the firmware */
+ err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+ if (err < 0) {
+ brcmf_err("set p2p_disc error\n");
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
+ goto fail;
+ }
+
+ /* wait for firmware event */
+ err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD,
+ msecs_to_jiffies(1500));
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
+ if (!err) {
+ brcmf_err("timeout occurred\n");
+ err = -EIO;
+ goto fail;
+ }
+
+ /* discovery interface created */
+ p2p_ifp = p2p_vif->ifp;
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+ memcpy(&p2p_vif->wdev.address, p2p->dev_addr, sizeof(p2p->dev_addr));
+
+ /* verify bsscfg index for P2P discovery */
+ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+ if (err < 0) {
+ brcmf_err("retrieving discover bsscfg index failed\n");
+ goto fail;
+ }
+
+ WARN_ON(p2p_ifp->bssidx != bssidx);
+
+ init_completion(&p2p->send_af_done);
+ INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+ init_completion(&p2p->afx_hdl.act_frm_scan);
+ init_completion(&p2p->wait_next_af);
+
+ return &p2p_vif->wdev;
+
+fail:
+ brcmf_free_vif(p2p_vif);
+ return ERR_PTR(err);
+}
+
+/**
+ * brcmf_p2p_delete_p2pdev() - delete P2P_DEVICE virtual interface.
+ *
+ * @vif: virtual interface object to delete.
+ */
+static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_vif *vif)
+{
+ struct brcmf_p2p_info *p2p = &vif->ifp->drvr->config->p2p;
+
+ cfg80211_unregister_wdev(&vif->wdev);
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+ brcmf_free_vif(vif);
+}
+
+/**
* brcmf_p2p_add_vif() - create a new P2P virtual interface.
*
* @wiphy: wiphy device of new interface.
* @name: name of the new interface.
* @type: nl80211 interface type.
- * @flags: TBD
- * @params: TBD
+ * @flags: not used.
+ * @params: contains mac address for P2P device.
*/
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
enum nl80211_iftype type, u32 *flags,
@@ -2157,6 +2262,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
iftype = BRCMF_FIL_P2P_IF_GO;
mode = WL_MODE_AP;
break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy,
+ params->macaddr);
default:
return ERR_PTR(-EOPNOTSUPP);
}
@@ -2244,6 +2352,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
break;
case NL80211_IFTYPE_P2P_DEVICE:
+ brcmf_p2p_delete_p2pdev(vif);
+ return 0;
default:
return -ENOTSUPP;
break;
@@ -2275,3 +2385,33 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
return err;
}
+
+int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_cfg80211_vif *vif;
+ int err;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+ mutex_lock(&cfg->usr_sync);
+ err = brcmf_p2p_enable_discovery(p2p);
+ if (!err)
+ set_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+ mutex_lock(&cfg->usr_sync);
+ (void)brcmf_p2p_deinit_discovery(p2p);
+ brcmf_abort_scanning(cfg);
+ clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
+ mutex_unlock(&cfg->usr_sync);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h
index 35efc7a67644..9df1f7a681e0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h
@@ -73,6 +73,20 @@ TRACE_EVENT(brcmf_dbg,
TP_printk("%s: %s", __get_str(func), __get_str(msg))
);
+TRACE_EVENT(brcmf_hexdump,
+ TP_PROTO(void *data, size_t len),
+ TP_ARGS(data, len),
+ TP_STRUCT__entry(
+ __field(unsigned long, len)
+ __dynamic_array(u8, hdata, len)
+ ),
+ TP_fast_assign(
+ __entry->len = len;
+ memcpy(__get_dynamic_array(hdata), data, len);
+ ),
+ TP_printk("hexdump [length=%lu]", __entry->len)
+);
+
#ifdef CONFIG_BRCM_TRACING
#undef TRACE_INCLUDE_PATH
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 804473fc5c5e..62699203869d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -26,6 +26,7 @@
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
#include "fwil_types.h"
#include "p2p.h"
#include "wl_cfg80211.h"
@@ -182,64 +183,6 @@ static struct ieee80211_channel __wl_5ghz_a_channels[] = {
CHAN5G(216, 0),
};
-static struct ieee80211_channel __wl_5ghz_n_channels[] = {
- CHAN5G(32, 0), CHAN5G(34, 0),
- CHAN5G(36, 0), CHAN5G(38, 0),
- CHAN5G(40, 0), CHAN5G(42, 0),
- CHAN5G(44, 0), CHAN5G(46, 0),
- CHAN5G(48, 0), CHAN5G(50, 0),
- CHAN5G(52, 0), CHAN5G(54, 0),
- CHAN5G(56, 0), CHAN5G(58, 0),
- CHAN5G(60, 0), CHAN5G(62, 0),
- CHAN5G(64, 0), CHAN5G(66, 0),
- CHAN5G(68, 0), CHAN5G(70, 0),
- CHAN5G(72, 0), CHAN5G(74, 0),
- CHAN5G(76, 0), CHAN5G(78, 0),
- CHAN5G(80, 0), CHAN5G(82, 0),
- CHAN5G(84, 0), CHAN5G(86, 0),
- CHAN5G(88, 0), CHAN5G(90, 0),
- CHAN5G(92, 0), CHAN5G(94, 0),
- CHAN5G(96, 0), CHAN5G(98, 0),
- CHAN5G(100, 0), CHAN5G(102, 0),
- CHAN5G(104, 0), CHAN5G(106, 0),
- CHAN5G(108, 0), CHAN5G(110, 0),
- CHAN5G(112, 0), CHAN5G(114, 0),
- CHAN5G(116, 0), CHAN5G(118, 0),
- CHAN5G(120, 0), CHAN5G(122, 0),
- CHAN5G(124, 0), CHAN5G(126, 0),
- CHAN5G(128, 0), CHAN5G(130, 0),
- CHAN5G(132, 0), CHAN5G(134, 0),
- CHAN5G(136, 0), CHAN5G(138, 0),
- CHAN5G(140, 0), CHAN5G(142, 0),
- CHAN5G(144, 0), CHAN5G(145, 0),
- CHAN5G(146, 0), CHAN5G(147, 0),
- CHAN5G(148, 0), CHAN5G(149, 0),
- CHAN5G(150, 0), CHAN5G(151, 0),
- CHAN5G(152, 0), CHAN5G(153, 0),
- CHAN5G(154, 0), CHAN5G(155, 0),
- CHAN5G(156, 0), CHAN5G(157, 0),
- CHAN5G(158, 0), CHAN5G(159, 0),
- CHAN5G(160, 0), CHAN5G(161, 0),
- CHAN5G(162, 0), CHAN5G(163, 0),
- CHAN5G(164, 0), CHAN5G(165, 0),
- CHAN5G(166, 0), CHAN5G(168, 0),
- CHAN5G(170, 0), CHAN5G(172, 0),
- CHAN5G(174, 0), CHAN5G(176, 0),
- CHAN5G(178, 0), CHAN5G(180, 0),
- CHAN5G(182, 0), CHAN5G(184, 0),
- CHAN5G(186, 0), CHAN5G(188, 0),
- CHAN5G(190, 0), CHAN5G(192, 0),
- CHAN5G(194, 0), CHAN5G(196, 0),
- CHAN5G(198, 0), CHAN5G(200, 0),
- CHAN5G(202, 0), CHAN5G(204, 0),
- CHAN5G(206, 0), CHAN5G(208, 0),
- CHAN5G(210, 0), CHAN5G(212, 0),
- CHAN5G(214, 0), CHAN5G(216, 0),
- CHAN5G(218, 0), CHAN5G(220, 0),
- CHAN5G(222, 0), CHAN5G(224, 0),
- CHAN5G(226, 0), CHAN5G(228, 0),
-};
-
static struct ieee80211_supported_band __wl_band_2ghz = {
.band = IEEE80211_BAND_2GHZ,
.channels = __wl_2ghz_channels,
@@ -256,12 +199,28 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
.n_bitrates = wl_a_rates_size,
};
-static struct ieee80211_supported_band __wl_band_5ghz_n = {
- .band = IEEE80211_BAND_5GHZ,
- .channels = __wl_5ghz_n_channels,
- .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
- .bitrates = wl_a_rates,
- .n_bitrates = wl_a_rates_size,
+/* This is to override regulatory domains defined in cfg80211 module (reg.c)
+ * By default world regulatory domain defined in reg.c puts the flags
+ * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for
+ * 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't
+ * start p2p operations on 5GHz channels. All the changes in world regulatory
+ * domain are to be done here.
+ */
+static const struct ieee80211_regdomain brcmf_regdom = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
+ /* If any */
+ /* IEEE 802.11 channel 14 - Only JP enables
+ * this and for 802.11b only
+ */
+ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
+ /* IEEE 802.11a, channel 36..64 */
+ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
+ /* IEEE 802.11a, channel 100..165 */
+ REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
};
static const u32 __wl_cipher_suites[] = {
@@ -523,17 +482,16 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
return ERR_PTR(-EOPNOTSUPP);
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
- case NL80211_IFTYPE_P2P_DEVICE:
default:
return ERR_PTR(-EINVAL);
}
}
-void brcmf_set_mpc(struct net_device *ndev, int mpc)
+void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
{
- struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = 0;
if (check_vif_up(ifp->vif)) {
@@ -546,10 +504,9 @@ void brcmf_set_mpc(struct net_device *ndev, int mpc)
}
}
-s32
-brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
- bool aborted, bool fw_abort)
+s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp, bool aborted,
+ bool fw_abort)
{
struct brcmf_scan_params_le params_le;
struct cfg80211_scan_request *scan_request;
@@ -580,7 +537,7 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
/* Scan is aborted by setting channel_list[0] to -1 */
params_le.channel_list[0] = cpu_to_le16(-1);
/* E-Scan (or anyother type) can be aborted by SCAN */
- err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&params_le, sizeof(params_le));
if (err)
brcmf_err("Scan abort failed\n");
@@ -594,12 +551,12 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
cfg->sched_escan = false;
if (!aborted)
cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
} else if (scan_request) {
brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
aborted ? "Aborted" : "Done");
cfg80211_scan_done(scan_request, aborted);
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
}
if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
@@ -619,9 +576,9 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
if (ndev) {
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
- cfg->escan_info.ndev == ndev)
- brcmf_notify_escan_complete(cfg, ndev, true,
- true);
+ cfg->escan_info.ifp == netdev_priv(ndev))
+ brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
+ true, true);
brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
}
@@ -637,9 +594,9 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
return -EOPNOTSUPP;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
return brcmf_p2p_del_vif(wiphy, wdev);
case NL80211_IFTYPE_UNSPECIFIED:
- case NL80211_IFTYPE_P2P_DEVICE:
default:
return -EINVAL;
}
@@ -803,7 +760,7 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
}
static s32
-brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
+brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
struct cfg80211_scan_request *request, u16 action)
{
s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
@@ -832,8 +789,7 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
params->action = cpu_to_le16(action);
params->sync_id = cpu_to_le16(0x1234);
- err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
- params, params_size);
+ err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
if (err) {
if (err == -EBUSY)
brcmf_dbg(INFO, "system busy : escan canceled\n");
@@ -848,7 +804,7 @@ exit:
static s32
brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
- struct net_device *ndev, struct cfg80211_scan_request *request)
+ struct brcmf_if *ifp, struct cfg80211_scan_request *request)
{
s32 err;
u32 passive_scan;
@@ -856,35 +812,35 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
struct escan_info *escan = &cfg->escan_info;
brcmf_dbg(SCAN, "Enter\n");
- escan->ndev = ndev;
+ escan->ifp = ifp;
escan->wiphy = wiphy;
escan->escan_state = WL_ESCAN_STATE_SCANNING;
passive_scan = cfg->active_scan ? 0 : 1;
- err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
passive_scan);
if (err) {
brcmf_err("error (%d)\n", err);
return err;
}
- brcmf_set_mpc(ndev, 0);
+ brcmf_set_mpc(ifp, 0);
results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
results->version = 0;
results->count = 0;
results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
- err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
+ err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
if (err)
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
return err;
}
static s32
-brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
+brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
struct cfg80211_scan_request *request,
struct cfg80211_ssid *this_ssid)
{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
+ struct brcmf_if *ifp = vif->ifp;
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct cfg80211_ssid *ssids;
struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
u32 passive_scan;
@@ -910,10 +866,8 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
}
/* If scan req comes for p2p0, send it over primary I/F */
- if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) {
- ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
- ndev = ifp->ndev;
- }
+ if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+ vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
/* Arm scan timeout timer */
mod_timer(&cfg->escan_timeout, jiffies +
@@ -934,11 +888,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
if (escan_req) {
cfg->escan_info.run = brcmf_run_escan;
- err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif);
+ err = brcmf_p2p_scan_prep(wiphy, request, vif);
if (err)
goto scan_out;
- err = brcmf_do_escan(cfg, wiphy, ndev, request);
+ err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
if (err)
goto scan_out;
} else {
@@ -962,7 +916,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
goto scan_out;
}
- brcmf_set_mpc(ndev, 0);
+ brcmf_set_mpc(ifp, 0);
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&sr->ssid_le, sizeof(sr->ssid_le));
if (err) {
@@ -972,7 +926,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
else
brcmf_err("WLC_SCAN error (%d)\n", err);
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
goto scan_out;
}
}
@@ -990,16 +944,15 @@ scan_out:
static s32
brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
- struct net_device *ndev = request->wdev->netdev;
+ struct brcmf_cfg80211_vif *vif;
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
-
- if (!check_vif_up(container_of(request->wdev,
- struct brcmf_cfg80211_vif, wdev)))
+ vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
+ if (!check_vif_up(vif))
return -EIO;
- err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
+ err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
if (err)
brcmf_err("scan error (%d)\n", err);
@@ -1891,8 +1844,10 @@ static s32
brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, const u8 *mac_addr, struct key_params *params)
{
+ struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_wsec_key key;
s32 err = 0;
+ u8 keybuf[8];
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
@@ -1916,8 +1871,9 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
memcpy(key.data, params->key, key.len);
- if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
- u8 keybuf[8];
+ if ((ifp->vif->mode != WL_MODE_AP) &&
+ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
+ brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
memcpy(keybuf, &key.data[24], sizeof(keybuf));
memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
memcpy(&key.data[16], keybuf, sizeof(keybuf));
@@ -2013,7 +1969,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
break;
case WLAN_CIPHER_SUITE_TKIP:
if (ifp->vif->mode != WL_MODE_AP) {
- brcmf_dbg(CONN, "Swapping key\n");
+ brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
memcpy(keybuf, &key.data[24], sizeof(keybuf));
memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
memcpy(&key.data[16], keybuf, sizeof(keybuf));
@@ -2118,8 +2074,7 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
err = -EAGAIN;
goto done;
}
- switch (wsec & ~SES_OW_ENABLED) {
- case WEP_ENABLED:
+ if (wsec & WEP_ENABLED) {
sec = &profile->sec;
if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
params.cipher = WLAN_CIPHER_SUITE_WEP40;
@@ -2128,16 +2083,13 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
params.cipher = WLAN_CIPHER_SUITE_WEP104;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
}
- break;
- case TKIP_ENABLED:
+ } else if (wsec & TKIP_ENABLED) {
params.cipher = WLAN_CIPHER_SUITE_TKIP;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
- break;
- case AES_ENABLED:
+ } else if (wsec & AES_ENABLED) {
params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
- break;
- default:
+ } else {
brcmf_err("Invalid algo (0x%x)\n", wsec);
err = -EINVAL;
goto done;
@@ -2511,7 +2463,7 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
if (cfg->scan_request) {
escan->escan_state = WL_ESCAN_STATE_IDLE;
- brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
+ brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
}
clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
@@ -2523,7 +2475,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
container_of(work, struct brcmf_cfg80211_info,
escan_timeout_work);
- brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
}
static void brcmf_escan_timeout(unsigned long data)
@@ -2574,7 +2526,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- struct net_device *ndev = ifp->ndev;
s32 status;
s32 err = 0;
struct brcmf_escan_result_le *escan_result_le;
@@ -2587,9 +2538,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
status = e->status;
- if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
- brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
- !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
+ if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+ brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
return -EPERM;
}
@@ -2660,7 +2610,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
cfg->escan_info.escan_buf;
brcmf_inform_bss(cfg);
aborted = status != BRCMF_E_STATUS_SUCCESS;
- brcmf_notify_escan_complete(cfg, ndev, aborted,
+ brcmf_notify_escan_complete(cfg, ifp, aborted,
false);
} else
brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
@@ -2738,7 +2688,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
brcmf_abort_scanning(cfg);
/* Turn off watchdog timer */
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(netdev_priv(ndev), 1);
exit:
brcmf_dbg(TRACE, "Exit\n");
@@ -2896,7 +2846,6 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- struct net_device *ndev = ifp->ndev;
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
struct cfg80211_scan_request *request = NULL;
struct cfg80211_ssid *ssid = NULL;
@@ -2980,7 +2929,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
}
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
- err = brcmf_do_escan(cfg, wiphy, ndev, request);
+ err = brcmf_do_escan(cfg, wiphy, ifp, request);
if (err) {
clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
goto out_err;
@@ -3137,7 +3086,7 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
brcmf_dbg(SCAN, "enter\n");
brcmf_dev_pno_clean(ndev);
if (cfg->sched_escan)
- brcmf_notify_escan_complete(cfg, ndev, true, true);
+ brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
return 0;
}
@@ -3709,7 +3658,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
}
- brcmf_set_mpc(ndev, 0);
+ brcmf_set_mpc(ifp, 0);
/* find the RSN_IE */
rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
@@ -3817,15 +3766,16 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
exit:
if (err)
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
return err;
}
static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err = -EPERM;
+ s32 err;
struct brcmf_fil_bss_enable_le bss_enable;
+ struct brcmf_join_params join_params;
brcmf_dbg(TRACE, "Enter\n");
@@ -3833,16 +3783,21 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
/* Due to most likely deauths outstanding we sleep */
/* first to make sure they get processed by fw. */
msleep(400);
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
- if (err < 0) {
- brcmf_err("setting AP mode failed %d\n", err);
- goto exit;
- }
+
+ memset(&join_params, 0, sizeof(join_params));
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+ &join_params, sizeof(join_params));
+ if (err < 0)
+ brcmf_err("SET SSID error (%d)\n", err);
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
- if (err < 0) {
+ if (err < 0)
brcmf_err("BRCMF_C_UP error %d\n", err);
- goto exit;
- }
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
+ if (err < 0)
+ brcmf_err("setting AP mode failed %d\n", err);
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
+ if (err < 0)
+ brcmf_err("setting INFRA mode failed %d\n", err);
} else {
bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
bss_enable.enable = cpu_to_le32(0);
@@ -3851,11 +3806,10 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
if (err < 0)
brcmf_err("bss_enable config failed %d\n", err);
}
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
-exit:
return err;
}
@@ -3909,13 +3863,13 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
struct wireless_dev *wdev,
u16 frame_type, bool reg)
{
- struct brcmf_if *ifp = netdev_priv(wdev->netdev);
- struct brcmf_cfg80211_vif *vif = ifp->vif;
+ struct brcmf_cfg80211_vif *vif;
u16 mgmt_type;
brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
if (reg)
vif->mgmt_rx_reg |= BIT(mgmt_type);
else
@@ -3931,7 +3885,6 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
const struct ieee80211_mgmt *mgmt;
- struct brcmf_if *ifp;
struct brcmf_cfg80211_vif *vif;
s32 err = 0;
s32 ie_offset;
@@ -3967,8 +3920,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
ie_offset = DOT11_MGMT_HDR_LEN +
DOT11_BCN_PRB_FIXED_LEN;
ie_len = len - ie_offset;
- ifp = netdev_priv(wdev->netdev);
- vif = ifp->vif;
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
err = brcmf_vif_set_mgmt_ie(vif,
@@ -4003,7 +3955,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
*cookie, le16_to_cpu(action_frame->len),
chan->center_freq);
- ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev,
+ ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
af_params);
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
@@ -4075,6 +4027,8 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.mgmt_tx = brcmf_cfg80211_mgmt_tx,
.remain_on_channel = brcmf_p2p_remain_on_channel,
.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
+ .start_p2p_device = brcmf_p2p_start_device,
+ .stop_p2p_device = brcmf_p2p_stop_device,
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd = brcmf_cfg80211_testmode
#endif
@@ -4162,6 +4116,11 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_DEVICE] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
}
};
@@ -4188,13 +4147,6 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
wiphy->iface_combinations = brcmf_iface_combos;
wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
- wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
- * it as 11a by default.
- * This will be updated with
- * 11n phy tables in
- * "ifconfig up"
- * if phy has 11n capability
- */
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = __wl_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
@@ -4204,6 +4156,9 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;
brcmf_wiphy_pno_params(wiphy);
+ brcmf_dbg(INFO, "Registering custom regulatory\n");
+ wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
err = wiphy_register(wiphy);
if (err < 0) {
brcmf_err("Could not register wiphy device (%d)\n", err);
@@ -4622,9 +4577,11 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
ifp->vif = vif;
vif->ifp = ifp;
- vif->wdev.netdev = ifp->ndev;
- ifp->ndev->ieee80211_ptr = &vif->wdev;
- SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+ if (ifp->ndev) {
+ vif->wdev.netdev = ifp->ndev;
+ ifp->ndev->ieee80211_ptr = &vif->wdev;
+ SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+ }
mutex_unlock(&event->vif_event_lock);
wake_up(&event->vif_wq);
return 0;
@@ -4927,34 +4884,248 @@ dongle_scantime_out:
return err;
}
-static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
+
+static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
+{
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct ieee80211_channel *band_chan_arr;
+ struct brcmf_chanspec_list *list;
+ s32 err;
+ u8 *pbuf;
+ u32 i, j;
+ u32 total;
+ u16 chanspec;
+ enum ieee80211_band band;
+ u32 channel;
+ u32 *n_cnt;
+ bool ht40_allowed;
+ u32 index;
+ u32 ht40_flag;
+ bool update;
+ u32 array_size;
+
+ pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
+
+ if (pbuf == NULL)
+ return -ENOMEM;
+
+ list = (struct brcmf_chanspec_list *)pbuf;
+
+ err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
+ BRCMF_DCMD_MEDLEN);
+ if (err) {
+ brcmf_err("get chanspecs error (%d)\n", err);
+ goto exit;
+ }
+
+ __wl_band_2ghz.n_channels = 0;
+ __wl_band_5ghz_a.n_channels = 0;
+
+ total = le32_to_cpu(list->count);
+ for (i = 0; i < total; i++) {
+ chanspec = (u16)le32_to_cpu(list->element[i]);
+ channel = CHSPEC_CHANNEL(chanspec);
+
+ if (CHSPEC_IS40(chanspec)) {
+ if (CHSPEC_SB_UPPER(chanspec))
+ channel += CH_10MHZ_APART;
+ else
+ channel -= CH_10MHZ_APART;
+ } else if (CHSPEC_IS80(chanspec)) {
+ brcmf_dbg(INFO, "HT80 center channel : %d\n",
+ channel);
+ continue;
+ }
+ if (CHSPEC_IS2G(chanspec) && (channel >= CH_MIN_2G_CHANNEL) &&
+ (channel <= CH_MAX_2G_CHANNEL)) {
+ band_chan_arr = __wl_2ghz_channels;
+ array_size = ARRAY_SIZE(__wl_2ghz_channels);
+ n_cnt = &__wl_band_2ghz.n_channels;
+ band = IEEE80211_BAND_2GHZ;
+ ht40_allowed = (bw_cap == WLC_N_BW_40ALL);
+ } else if (CHSPEC_IS5G(chanspec) &&
+ channel >= CH_MIN_5G_CHANNEL) {
+ band_chan_arr = __wl_5ghz_a_channels;
+ array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
+ n_cnt = &__wl_band_5ghz_a.n_channels;
+ band = IEEE80211_BAND_5GHZ;
+ ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);
+ } else {
+ brcmf_err("Invalid channel Sepc. 0x%x.\n", chanspec);
+ continue;
+ }
+ if (!ht40_allowed && CHSPEC_IS40(chanspec))
+ continue;
+ update = false;
+ for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
+ if (band_chan_arr[j].hw_value == channel) {
+ update = true;
+ break;
+ }
+ }
+ if (update)
+ index = j;
+ else
+ index = *n_cnt;
+ if (index < array_size) {
+ band_chan_arr[index].center_freq =
+ ieee80211_channel_to_frequency(channel, band);
+ band_chan_arr[index].hw_value = channel;
+
+ if (CHSPEC_IS40(chanspec) && ht40_allowed) {
+ /* assuming the order is HT20, HT40 Upper,
+ * HT40 lower from chanspecs
+ */
+ ht40_flag = band_chan_arr[index].flags &
+ IEEE80211_CHAN_NO_HT40;
+ if (CHSPEC_SB_UPPER(chanspec)) {
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags &=
+ ~IEEE80211_CHAN_NO_HT40;
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_NO_HT40PLUS;
+ } else {
+ /* It should be one of
+ * IEEE80211_CHAN_NO_HT40 or
+ * IEEE80211_CHAN_NO_HT40PLUS
+ */
+ band_chan_arr[index].flags &=
+ ~IEEE80211_CHAN_NO_HT40;
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_NO_HT40MINUS;
+ }
+ } else {
+ band_chan_arr[index].flags =
+ IEEE80211_CHAN_NO_HT40;
+ if (band == IEEE80211_BAND_2GHZ)
+ channel |= WL_CHANSPEC_BAND_2G;
+ else
+ channel |= WL_CHANSPEC_BAND_5G;
+ channel |= WL_CHANSPEC_BW_20;
+ err = brcmf_fil_bsscfg_int_get(ifp,
+ "per_chan_info",
+ &channel);
+ if (!err) {
+ if (channel & WL_CHAN_RADAR)
+ band_chan_arr[index].flags |=
+ (IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_NO_IBSS);
+ if (channel & WL_CHAN_PASSIVE)
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_PASSIVE_SCAN;
+ }
+ }
+ if (!update)
+ (*n_cnt)++;
+ }
+ }
+exit:
+ kfree(pbuf);
+ return err;
+}
+
+
+static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
{
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
struct wiphy *wiphy;
s32 phy_list;
+ u32 band_list[3];
+ u32 nmode;
+ u32 bw_cap = 0;
s8 phy;
- s32 err = 0;
+ s32 err;
+ u32 nband;
+ s32 i;
+ struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
+ s32 index;
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
&phy_list, sizeof(phy_list));
if (err) {
- brcmf_err("error (%d)\n", err);
+ brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
return err;
}
phy = ((char *)&phy_list)[0];
- brcmf_dbg(INFO, "%c phy\n", phy);
- if (phy == 'n' || phy == 'a') {
- wiphy = cfg_to_wiphy(cfg);
- wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
+ brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
+
+
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
+ &band_list, sizeof(band_list));
+ if (err) {
+ brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
+ return err;
+ }
+ brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
+ band_list[0], band_list[1], band_list[2]);
+
+ err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
+ if (err) {
+ brcmf_err("nmode error (%d)\n", err);
+ } else {
+ err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap);
+ if (err)
+ brcmf_err("mimo_bw_cap error (%d)\n", err);
+ }
+ brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap);
+
+ err = brcmf_construct_reginfo(cfg, bw_cap);
+ if (err) {
+ brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
+ return err;
}
+ nband = band_list[0];
+ memset(bands, 0, sizeof(bands));
+
+ for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
+ index = -1;
+ if ((band_list[i] == WLC_BAND_5G) &&
+ (__wl_band_5ghz_a.n_channels > 0)) {
+ index = IEEE80211_BAND_5GHZ;
+ bands[index] = &__wl_band_5ghz_a;
+ if ((bw_cap == WLC_N_BW_40ALL) ||
+ (bw_cap == WLC_N_BW_20IN2G_40IN5G))
+ bands[index]->ht_cap.cap |=
+ IEEE80211_HT_CAP_SGI_40;
+ } else if ((band_list[i] == WLC_BAND_2G) &&
+ (__wl_band_2ghz.n_channels > 0)) {
+ index = IEEE80211_BAND_2GHZ;
+ bands[index] = &__wl_band_2ghz;
+ if (bw_cap == WLC_N_BW_40ALL)
+ bands[index]->ht_cap.cap |=
+ IEEE80211_HT_CAP_SGI_40;
+ }
+
+ if ((index >= 0) && nmode) {
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
+ bands[index]->ht_cap.ht_supported = true;
+ bands[index]->ht_cap.ampdu_factor =
+ IEEE80211_HT_MAX_AMPDU_64K;
+ bands[index]->ht_cap.ampdu_density =
+ IEEE80211_HT_MPDU_DENSITY_16;
+ /* An HT shall support all EQM rates for one spatial
+ * stream
+ */
+ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
+ }
+ }
+
+ wiphy = cfg_to_wiphy(cfg);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
+ wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
+ wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
+
return err;
}
+
static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
{
- return wl_update_wiphybands(cfg);
+ return brcmf_update_wiphybands(cfg);
}
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index 8b5d4989906c..2907437ef438 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -238,9 +238,8 @@ struct escan_info {
u32 escan_state;
u8 escan_buf[WL_ESCAN_BUF_SIZE];
struct wiphy *wiphy;
- struct net_device *ndev;
- s32 (*run)(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
+ struct brcmf_if *ifp;
+ s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
struct cfg80211_scan_request *request, u16 action);
};
@@ -493,9 +492,9 @@ bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
u8 action, ulong timeout);
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
- bool aborted, bool fw_abort);
-void brcmf_set_mpc(struct net_device *ndev, int mpc);
+ struct brcmf_if *ifp, bool aborted,
+ bool fw_abort);
+void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);
void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
index f0888a9ee32e..e4fd1ee3d690 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
@@ -318,12 +318,6 @@
#define IS_SIM(chippkg) \
((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
-#ifdef DEBUG
-#define SI_MSG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__)
-#else
-#define SI_MSG(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif /* DEBUG */
-
#define GOODCOREADDR(x, b) \
(((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \
IS_ALIGNED((x), SI_CORE_SIZE))
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/d11.h b/drivers/net/wireless/brcm80211/brcmsmac/d11.h
index 3f659e09f1cc..9035cc4d6ff3 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/d11.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/d11.h
@@ -457,6 +457,7 @@ struct d11regs {
/*== maccontrol register ==*/
#define MCTL_GMODE (1U << 31)
#define MCTL_DISCARD_PMQ (1 << 30)
+#define MCTL_TBTTHOLD (1 << 28)
#define MCTL_WAKE (1 << 26)
#define MCTL_HPS (1 << 25)
#define MCTL_PROMISC (1 << 24)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index c70cf7b654cd..cd837860cd42 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2010 Broadcom Corporation
+ * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -356,18 +357,26 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct brcms_info *wl = hw->priv;
- /* Just STA for now */
- if (vif->type != NL80211_IFTYPE_STATION) {
+ /* Just STA, AP and ADHOC for now */
+ if (vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_ADHOC) {
brcms_err(wl->wlc->hw->d11core,
- "%s: Attempt to add type %d, only STA for now\n",
+ "%s: Attempt to add type %d, only STA, AP and AdHoc for now\n",
__func__, vif->type);
return -EOPNOTSUPP;
}
spin_lock_bh(&wl->lock);
- memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr));
wl->mute_tx = false;
brcms_c_mute(wl->wlc, false);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ brcms_c_start_station(wl->wlc, vif->addr);
+ else if (vif->type == NL80211_IFTYPE_AP)
+ brcms_c_start_ap(wl->wlc, vif->addr, vif->bss_conf.bssid,
+ vif->bss_conf.ssid, vif->bss_conf.ssid_len);
+ else if (vif->type == NL80211_IFTYPE_ADHOC)
+ brcms_c_start_adhoc(wl->wlc, vif->addr);
spin_unlock_bh(&wl->lock);
return 0;
@@ -519,14 +528,43 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
spin_unlock_bh(&wl->lock);
}
- if (changed & BSS_CHANGED_BEACON)
+ if (changed & BSS_CHANGED_SSID) {
+ /* BSSID changed, for whatever reason (IBSS and managed mode) */
+ spin_lock_bh(&wl->lock);
+ brcms_c_set_ssid(wl->wlc, info->ssid, info->ssid_len);
+ spin_unlock_bh(&wl->lock);
+ }
+ if (changed & BSS_CHANGED_BEACON) {
/* Beacon data changed, retrieve new beacon (beaconing modes) */
- brcms_err(core, "%s: beacon changed\n", __func__);
+ struct sk_buff *beacon;
+ u16 tim_offset = 0;
+
+ spin_lock_bh(&wl->lock);
+ beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL);
+ brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset,
+ info->dtim_period);
+ spin_unlock_bh(&wl->lock);
+ }
+
+ if (changed & BSS_CHANGED_AP_PROBE_RESP) {
+ struct sk_buff *probe_resp;
+
+ spin_lock_bh(&wl->lock);
+ probe_resp = ieee80211_proberesp_get(hw, vif);
+ brcms_c_set_new_probe_resp(wl->wlc, probe_resp);
+ spin_unlock_bh(&wl->lock);
+ }
if (changed & BSS_CHANGED_BEACON_ENABLED) {
/* Beaconing should be enabled/disabled (beaconing modes) */
brcms_err(core, "%s: Beacon enabled: %s\n", __func__,
info->enable_beacon ? "true" : "false");
+ if (info->enable_beacon &&
+ hw->wiphy->flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) {
+ brcms_c_enable_probe_resp(wl->wlc, true);
+ } else {
+ brcms_c_enable_probe_resp(wl->wlc, false);
+ }
}
if (changed & BSS_CHANGED_CQM) {
@@ -724,7 +762,7 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl)
return result;
}
-static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
+static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct brcms_info *wl = hw->priv;
int ret;
@@ -739,6 +777,28 @@ static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
"ret=%d\n", jiffies_to_msecs(ret));
}
+static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct brcms_info *wl = hw->priv;
+ u64 tsf;
+
+ spin_lock_bh(&wl->lock);
+ tsf = brcms_c_tsf_get(wl->wlc);
+ spin_unlock_bh(&wl->lock);
+
+ return tsf;
+}
+
+static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u64 tsf)
+{
+ struct brcms_info *wl = hw->priv;
+
+ spin_lock_bh(&wl->lock);
+ brcms_c_tsf_set(wl->wlc, tsf);
+ spin_unlock_bh(&wl->lock);
+}
+
static const struct ieee80211_ops brcms_ops = {
.tx = brcms_ops_tx,
.start = brcms_ops_start,
@@ -755,6 +815,8 @@ static const struct ieee80211_ops brcms_ops = {
.ampdu_action = brcms_ops_ampdu_action,
.rfkill_poll = brcms_ops_rfkill_poll,
.flush = brcms_ops_flush,
+ .get_tsf = brcms_ops_get_tsf,
+ .set_tsf = brcms_ops_set_tsf,
};
void brcms_dpc(unsigned long data)
@@ -996,7 +1058,16 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
/* channel change time is dependent on chip and band */
hw->channel_change_time = 7 * 1000;
- hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_ADHOC);
+
+ /*
+ * deactivate sending probe responses by ucude, because this will
+ * cause problems when WPS is used.
+ *
+ * hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+ */
hw->rate_control_algorithm = "minstrel_ht";
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 0c8e998bfb1e..59d438409dfb 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2010 Broadcom Corporation
+ * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -448,6 +449,10 @@ static void brcms_c_detach_mfree(struct brcms_c_info *wlc)
kfree(wlc->corestate);
kfree(wlc->hw->bandstate[0]);
kfree(wlc->hw);
+ if (wlc->beacon)
+ dev_kfree_skb_any(wlc->beacon);
+ if (wlc->probe_resp)
+ dev_kfree_skb_any(wlc->probe_resp);
/* free the wlc */
kfree(wlc);
@@ -1069,7 +1074,7 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
static void brcms_c_tbtt(struct brcms_c_info *wlc)
{
- if (!wlc->bsscfg->BSS)
+ if (wlc->bsscfg->type == BRCMS_TYPE_ADHOC)
/*
* DirFrmQ is now valid...defer setting until end
* of ATIM window
@@ -2163,6 +2168,32 @@ void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode)
}
}
+void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr)
+{
+ memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
+ wlc->bsscfg->type = BRCMS_TYPE_STATION;
+}
+
+void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr, const u8 *bssid,
+ u8 *ssid, size_t ssid_len)
+{
+ brcms_c_set_ssid(wlc, ssid, ssid_len);
+
+ memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
+ memcpy(wlc->bsscfg->BSSID, bssid, sizeof(wlc->bsscfg->BSSID));
+ wlc->bsscfg->type = BRCMS_TYPE_AP;
+
+ brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, MCTL_AP | MCTL_INFRA);
+}
+
+void brcms_c_start_adhoc(struct brcms_c_info *wlc, u8 *addr)
+{
+ memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
+ wlc->bsscfg->type = BRCMS_TYPE_ADHOC;
+
+ brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, 0);
+}
+
/* Initialize GPIOs that are controlled by D11 core */
static void brcms_c_gpio_init(struct brcms_c_info *wlc)
{
@@ -3043,8 +3074,6 @@ static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
*/
static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
{
- struct brcms_bss_cfg *cfg = wlc->bsscfg;
-
/* disallow PS when one of the following global conditions meets */
if (!wlc->pub->associated)
return false;
@@ -3053,16 +3082,11 @@ static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
return false;
- if (cfg->associated) {
- /*
- * disallow PS when one of the following
- * bsscfg specific conditions meets
- */
- if (!cfg->BSS)
- return false;
+ if (wlc->bsscfg->type == BRCMS_TYPE_AP)
+ return false;
+ if (wlc->bsscfg->type == BRCMS_TYPE_ADHOC)
return false;
- }
return true;
}
@@ -3771,7 +3795,7 @@ static int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
struct brcms_c_info *wlc = bsscfg->wlc;
/* enter the MAC addr into the RXE match registers */
- brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, bsscfg->cur_etheraddr);
+ brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, wlc->pub->cur_etheraddr);
brcms_c_ampdu_macaddr_upd(wlc);
@@ -3787,6 +3811,15 @@ static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)
brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);
}
+void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid, size_t ssid_len)
+{
+ u8 len = min_t(u8, sizeof(wlc->bsscfg->SSID), ssid_len);
+ memset(wlc->bsscfg->SSID, 0, sizeof(wlc->bsscfg->SSID));
+
+ memcpy(wlc->bsscfg->SSID, ssid, len);
+ wlc->bsscfg->SSID_len = len;
+}
+
static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
{
wlc_hw->shortslot = shortslot;
@@ -3821,7 +3854,7 @@ static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
if (wlc->home_chanspec != chanspec) {
wlc->home_chanspec = chanspec;
- if (wlc->bsscfg->associated)
+ if (wlc->pub->associated)
wlc->bsscfg->current_bss->chanspec = chanspec;
}
}
@@ -4091,10 +4124,14 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
*shm_entry++);
}
- if (suspend) {
+ if (suspend)
brcms_c_suspend_mac_and_wait(wlc);
+
+ brcms_c_update_beacon(wlc);
+ brcms_c_update_probe_resp(wlc, false);
+
+ if (suspend)
brcms_c_enable_mac(wlc);
- }
}
static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
@@ -4332,7 +4369,6 @@ static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
/* WME QoS mode is Auto by default */
wlc->pub->_ampdu = AMPDU_AGG_HOST;
- wlc->pub->bcmerror = 0;
}
static uint brcms_c_attach_module(struct brcms_c_info *wlc)
@@ -5072,8 +5108,8 @@ int brcms_c_up(struct brcms_c_info *wlc)
struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
mboolset(wlc->pub->radio_disabled,
WL_RADIO_HW_DISABLE);
-
- if (bsscfg->enable && bsscfg->BSS)
+ if (bsscfg->type == BRCMS_TYPE_STATION ||
+ bsscfg->type == BRCMS_TYPE_ADHOC)
brcms_err(wlc->hw->d11core,
"wl%d: up: rfdisable -> "
"bsscfg_disable()\n",
@@ -5434,7 +5470,7 @@ static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
u8 r;
bool war = false;
- if (wlc->bsscfg->associated)
+ if (wlc->pub->associated)
r = wlc->bsscfg->current_bss->rateset.rates[0];
else
r = wlc->default_bss->rateset.rates[0];
@@ -5528,7 +5564,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
/* merge rateset coming in with the current mcsset */
if (wlc->pub->_n_enab & SUPPORT_11N) {
struct brcms_bss_info *mcsset_bss;
- if (wlc->bsscfg->associated)
+ if (wlc->pub->associated)
mcsset_bss = wlc->bsscfg->current_bss;
else
mcsset_bss = wlc->default_bss;
@@ -5543,12 +5579,36 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
return bcmerror;
}
+static void brcms_c_time_lock(struct brcms_c_info *wlc)
+{
+ bcma_set32(wlc->hw->d11core, D11REGOFFS(maccontrol), MCTL_TBTTHOLD);
+ /* Commit the write */
+ bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
+}
+
+static void brcms_c_time_unlock(struct brcms_c_info *wlc)
+{
+ bcma_mask32(wlc->hw->d11core, D11REGOFFS(maccontrol), ~MCTL_TBTTHOLD);
+ /* Commit the write */
+ bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
+}
+
int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
{
+ u32 bcnint_us;
+
if (period == 0)
return -EINVAL;
wlc->default_bss->beacon_period = period;
+
+ bcnint_us = period << 10;
+ brcms_c_time_lock(wlc);
+ bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfprep),
+ (bcnint_us << CFPREP_CBI_SHIFT));
+ bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfpstart), bcnint_us);
+ brcms_c_time_unlock(wlc);
+
return 0;
}
@@ -7291,72 +7351,110 @@ brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
}
}
-/* Max buffering needed for beacon template/prb resp template is 142 bytes.
- *
- * PLCP header is 6 bytes.
- * 802.11 A3 header is 24 bytes.
- * Max beacon frame body template length is 112 bytes.
- * Max probe resp frame body template length is 110 bytes.
- *
- * *len on input contains the max length of the packet available.
- *
- * The *len value is set to the number of bytes in buf used, and starts
- * with the PLCP and included up to, but not including, the 4 byte FCS.
- */
-static void
-brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
- u32 bcn_rspec,
- struct brcms_bss_cfg *cfg, u16 *buf, int *len)
+int brcms_c_get_header_len(void)
{
- static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
- struct cck_phy_hdr *plcp;
- struct ieee80211_mgmt *h;
- int hdr_len, body_len;
-
- hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
+ return TXOFF;
+}
- /* calc buffer size provided for frame body */
- body_len = *len - hdr_len;
- /* return actual size */
- *len = hdr_len + body_len;
+static void brcms_c_beacon_write(struct brcms_c_info *wlc,
+ struct sk_buff *beacon, u16 tim_offset,
+ u16 dtim_period, bool bcn0, bool bcn1)
+{
+ size_t len;
+ struct ieee80211_tx_info *tx_info;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct ieee80211_hw *ieee_hw = brcms_c_pub(wlc)->ieee_hw;
- /* format PHY and MAC headers */
- memset(buf, 0, hdr_len);
+ /* Get tx_info */
+ tx_info = IEEE80211_SKB_CB(beacon);
- plcp = (struct cck_phy_hdr *) buf;
+ len = min_t(size_t, beacon->len, BCN_TMPL_LEN);
+ wlc->bcn_rspec = ieee80211_get_tx_rate(ieee_hw, tx_info)->hw_value;
- /*
- * PLCP for Probe Response frames are filled in from
- * core's rate table
- */
- if (type == IEEE80211_STYPE_BEACON)
- /* fill in PLCP */
- brcms_c_compute_plcp(wlc, bcn_rspec,
- (DOT11_MAC_HDR_LEN + body_len + FCS_LEN),
- (u8 *) plcp);
+ brcms_c_compute_plcp(wlc, wlc->bcn_rspec,
+ len + FCS_LEN - D11_PHY_HDR_LEN, beacon->data);
/* "Regular" and 16 MBSS but not for 4 MBSS */
/* Update the phytxctl for the beacon based on the rspec */
- brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
+ brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);
- h = (struct ieee80211_mgmt *)&plcp[1];
+ if (bcn0) {
+ /* write the probe response into the template region */
+ brcms_b_write_template_ram(wlc_hw, T_BCN0_TPL_BASE,
+ (len + 3) & ~3, beacon->data);
- /* fill in 802.11 header */
- h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type);
+ /* write beacon length to SCR */
+ brcms_b_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len);
+ }
+ if (bcn1) {
+ /* write the probe response into the template region */
+ brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE,
+ (len + 3) & ~3, beacon->data);
- /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */
- /* A1 filled in by MAC for prb resp, broadcast for bcn */
- if (type == IEEE80211_STYPE_BEACON)
- memcpy(&h->da, &ether_bcast, ETH_ALEN);
- memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN);
- memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
+ /* write beacon length to SCR */
+ brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
+ }
- /* SEQ filled in by MAC */
+ if (tim_offset != 0) {
+ brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
+ tim_offset + D11B_PHY_HDR_LEN);
+ brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, dtim_period);
+ } else {
+ brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
+ len + D11B_PHY_HDR_LEN);
+ brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, 0);
+ }
}
-int brcms_c_get_header_len(void)
+static void brcms_c_update_beacon_hw(struct brcms_c_info *wlc,
+ struct sk_buff *beacon, u16 tim_offset,
+ u16 dtim_period)
{
- return TXOFF;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct bcma_device *core = wlc_hw->d11core;
+
+ /* Hardware beaconing for this config */
+ u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;
+
+ /* Check if both templates are in use, if so sched. an interrupt
+ * that will call back into this routine
+ */
+ if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid)
+ /* clear any previous status */
+ bcma_write32(core, D11REGOFFS(macintstatus), MI_BCNTPL);
+
+ if (wlc->beacon_template_virgin) {
+ wlc->beacon_template_virgin = false;
+ brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
+ true);
+ /* mark beacon0 valid */
+ bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
+ return;
+ }
+
+ /* Check that after scheduling the interrupt both of the
+ * templates are still busy. if not clear the int. & remask
+ */
+ if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid) {
+ wlc->defmacintmask |= MI_BCNTPL;
+ return;
+ }
+
+ if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN0VLD)) {
+ brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
+ false);
+ /* mark beacon0 valid */
+ bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
+ return;
+ }
+ if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN1VLD)) {
+ brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period,
+ false, true);
+ /* mark beacon0 valid */
+ bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN1VLD);
+ return;
+ }
+ return;
}
/*
@@ -7366,9 +7464,57 @@ void brcms_c_update_beacon(struct brcms_c_info *wlc)
{
struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
- if (bsscfg->up && !bsscfg->BSS)
+ if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||
+ bsscfg->type == BRCMS_TYPE_ADHOC)) {
/* Clear the soft intmask */
wlc->defmacintmask &= ~MI_BCNTPL;
+ if (!wlc->beacon)
+ return;
+ brcms_c_update_beacon_hw(wlc, wlc->beacon,
+ wlc->beacon_tim_offset,
+ wlc->beacon_dtim_period);
+ }
+}
+
+void brcms_c_set_new_beacon(struct brcms_c_info *wlc, struct sk_buff *beacon,
+ u16 tim_offset, u16 dtim_period)
+{
+ if (!beacon)
+ return;
+ if (wlc->beacon)
+ dev_kfree_skb_any(wlc->beacon);
+ wlc->beacon = beacon;
+
+ /* add PLCP */
+ skb_push(wlc->beacon, D11_PHY_HDR_LEN);
+ wlc->beacon_tim_offset = tim_offset;
+ wlc->beacon_dtim_period = dtim_period;
+ brcms_c_update_beacon(wlc);
+}
+
+void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc,
+ struct sk_buff *probe_resp)
+{
+ if (!probe_resp)
+ return;
+ if (wlc->probe_resp)
+ dev_kfree_skb_any(wlc->probe_resp);
+ wlc->probe_resp = probe_resp;
+
+ /* add PLCP */
+ skb_push(wlc->probe_resp, D11_PHY_HDR_LEN);
+ brcms_c_update_probe_resp(wlc, false);
+}
+
+void brcms_c_enable_probe_resp(struct brcms_c_info *wlc, bool enable)
+{
+ /*
+ * prevent ucode from sending probe responses by setting the timeout
+ * to 1, it can not send it in that time frame.
+ */
+ wlc->prb_resp_timeout = enable ? BRCMS_PRB_RESP_TIMEOUT : 1;
+ brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
+ /* TODO: if (enable) => also deactivate receiving of probe request */
}
/* Write ssid into shared memory */
@@ -7390,30 +7536,19 @@ brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
static void
brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
struct brcms_bss_cfg *cfg,
+ struct sk_buff *probe_resp,
bool suspend)
{
- u16 *prb_resp;
- int len = BCN_TMPL_LEN;
-
- prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC);
- if (!prb_resp)
- return;
-
- /*
- * write the probe response to hardware, or save in
- * the config structure
- */
+ int len;
- /* create the probe response template */
- brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
- cfg, prb_resp, &len);
+ len = min_t(size_t, probe_resp->len, BCN_TMPL_LEN);
if (suspend)
brcms_c_suspend_mac_and_wait(wlc);
/* write the probe response into the template region */
brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
- (len + 3) & ~3, prb_resp);
+ (len + 3) & ~3, probe_resp->data);
/* write the length of the probe response frame (+PLCP/-FCS) */
brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
@@ -7427,13 +7562,11 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
* PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
* by subtracting the PLCP len and adding the FCS.
*/
- len += (-D11_PHY_HDR_LEN + FCS_LEN);
- brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
+ brcms_c_mod_prb_rsp_rate_table(wlc,
+ (u16)len + FCS_LEN - D11_PHY_HDR_LEN);
if (suspend)
brcms_c_enable_mac(wlc);
-
- kfree(prb_resp);
}
void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
@@ -7441,8 +7574,13 @@ void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
/* update AP or IBSS probe responses */
- if (bsscfg->up && !bsscfg->BSS)
- brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
+ if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||
+ bsscfg->type == BRCMS_TYPE_ADHOC)) {
+ if (!wlc->probe_resp)
+ return;
+ brcms_c_bss_update_probe_resp(wlc, bsscfg, wlc->probe_resp,
+ suspend);
+ }
}
int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
@@ -7481,7 +7619,6 @@ void brcms_c_scan_stop(struct brcms_c_info *wlc)
void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
{
wlc->pub->associated = state;
- wlc->bsscfg->associated = state;
}
/*
@@ -7526,6 +7663,36 @@ void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
brcms_c_bcn_li_upd(wlc);
}
+u64 brcms_c_tsf_get(struct brcms_c_info *wlc)
+{
+ u32 tsf_h, tsf_l;
+ u64 tsf;
+
+ brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);
+
+ tsf = tsf_h;
+ tsf <<= 32;
+ tsf |= tsf_l;
+
+ return tsf;
+}
+
+void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf)
+{
+ u32 tsf_h, tsf_l;
+
+ brcms_c_time_lock(wlc);
+
+ tsf_l = tsf;
+ tsf_h = (tsf >> 32);
+
+ /* read the tsf timer low, then high to get an atomic read */
+ bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerlow), tsf_l);
+ bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerhigh), tsf_h);
+
+ brcms_c_time_unlock(wlc);
+}
+
int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
{
uint qdbm;
@@ -7737,6 +7904,10 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
brcms_rfkill_set_hw_state(wlc->wl);
}
+ /* BCN template is available */
+ if (macintstatus & MI_BCNTPL)
+ brcms_c_update_beacon(wlc);
+
/* it isn't done and needs to be resched if macintstatus is non-zero */
return wlc->macintstatus != 0;
@@ -7765,7 +7936,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
brcms_c_set_bssid(wlc->bsscfg);
/* Update tsf_cfprep if associated and up */
- if (wlc->pub->associated && wlc->bsscfg->up) {
+ if (wlc->pub->associated && wlc->pub->up) {
u32 bi;
/* get beacon period and convert to uS */
@@ -7873,6 +8044,7 @@ brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit,
pub->unit = unit;
pub->_piomode = piomode;
wlc->bandinit_pending = false;
+ wlc->beacon_template_virgin = true;
/* populate struct brcms_c_info with default values */
brcms_c_info_init(wlc, unit);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h
index fb447747c2c6..b5d7a38b53fe 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
@@ -492,6 +492,8 @@ struct brcms_c_info {
bool radio_monitor;
bool going_down;
+ bool beacon_template_virgin;
+
struct brcms_timer *wdtimer;
struct brcms_timer *radio_timer;
@@ -561,6 +563,11 @@ struct brcms_c_info {
struct wiphy *wiphy;
struct scb pri_scb;
+
+ struct sk_buff *beacon;
+ u16 beacon_tim_offset;
+ u16 beacon_dtim_period;
+ struct sk_buff *probe_resp;
};
/* antsel module specific state */
@@ -576,14 +583,17 @@ struct antsel_info {
struct brcms_antselcfg antcfg_cur; /* current antenna config (auto) */
};
+enum brcms_bss_type {
+ BRCMS_TYPE_STATION,
+ BRCMS_TYPE_AP,
+ BRCMS_TYPE_ADHOC,
+};
+
/*
* BSS configuration state
*
* wlc: wlc to which this bsscfg belongs to.
- * up: is this configuration up operational
- * enable: is this configuration enabled
- * associated: is BSS in ASSOCIATED state
- * BSS: infraustructure or adhoc
+ * type: interface type
* SSID_len: the length of SSID
* SSID: SSID string
*
@@ -599,14 +609,10 @@ struct antsel_info {
*/
struct brcms_bss_cfg {
struct brcms_c_info *wlc;
- bool up;
- bool enable;
- bool associated;
- bool BSS;
+ enum brcms_bss_type type;
u8 SSID_len;
u8 SSID[IEEE80211_MAX_SSID_LEN];
u8 BSSID[ETH_ALEN];
- u8 cur_etheraddr[ETH_ALEN];
struct brcms_bss_info *current_bss;
};
@@ -631,7 +637,6 @@ extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
struct ieee80211_sta *sta,
void (*dma_callback_fn));
-extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend);
extern int brcms_c_set_nmode(struct brcms_c_info *wlc);
extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
index 91937c5025ce..b0fd807f2b2b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
@@ -198,8 +198,6 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
{
- struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub);
-
if ((D11REV_GE(pi->sh->corerev, 24)) ||
(D11REV_IS(pi->sh->corerev, 22)
&& (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
@@ -211,7 +209,7 @@ void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val);
}
- if ((sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) &&
+ if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&
(++pi->phy_wreg >= pi->phy_wreg_limit)) {
(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
pi->phy_wreg = 0;
@@ -297,10 +295,8 @@ void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
if (addr == 0x72)
(void)bcma_read16(pi->d11core, D11REGOFFS(phyregdata));
#else
- struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub);
-
bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16));
- if ((sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) &&
+ if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&
(++pi->phy_wreg >= pi->phy_wreg_limit)) {
pi->phy_wreg = 0;
(void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
@@ -374,7 +370,6 @@ struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
if (sh == NULL)
return NULL;
- sh->sih = shp->sih;
sh->physhim = shp->physhim;
sh->unit = shp->unit;
sh->corerev = shp->corerev;
@@ -2911,29 +2906,24 @@ void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
}
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpiocontrol),
- ~0x0, 0x0);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpioout),
- 0x40, 0x40);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpioouten),
- 0x40, 0x40);
+
+ bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
+ 0x0, 0x0);
+ bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
+ ~0x40, 0x40);
+ bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
+ ~0x40, 0x40);
} else {
mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpioout),
- 0x40, 0x00);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpioouten),
- 0x40, 0x0);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpiocontrol),
- ~0x0, 0x40);
+ bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
+ ~0x40, 0x00);
+ bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
+ ~0x40, 0x00);
+ bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
+ 0x0, 0x40);
}
}
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
index af00e2c2b266..1dc767c31653 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
@@ -488,7 +488,6 @@ struct lcnphy_cal_results {
struct shared_phy {
struct brcms_phy *phy_head;
uint unit;
- struct si_pub *sih;
struct phy_shim_info *physhim;
uint corerev;
u32 machwcap;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
index 18d37645e2cd..3d6b16ce4687 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -1595,11 +1595,15 @@ wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
if (channel == 1 || channel == 2 || channel == 3 ||
channel == 4 || channel == 9 ||
channel == 10 || channel == 11 || channel == 12) {
- si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
- si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
- si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
-
- si_pmu_pllupd(pi->sh->sih);
+ bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
+ 0x03000c04);
+ bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
+ ~0x00ffffff, 0x0);
+ bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
+ 0x200005c0);
+
+ bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
+ BCMA_CC_PMU_CTL_PLL_UPD);
write_phy_reg(pi, 0x942, 0);
wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
pi_lcn->lcnphy_spurmod = false;
@@ -1607,11 +1611,15 @@ wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
write_phy_reg(pi, 0x425, 0x5907);
} else {
- si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
- si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
- si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
-
- si_pmu_pllupd(pi->sh->sih);
+ bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
+ 0x03140c04);
+ bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
+ ~0x00ffffff, 0x333333);
+ bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
+ 0x202c2820);
+
+ bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
+ BCMA_CC_PMU_CTL_PLL_UPD);
write_phy_reg(pi, 0x942, 0);
wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
@@ -4755,9 +4763,10 @@ void wlc_phy_init_lcnphy(struct brcms_phy *pi)
wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
- si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
+ bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
- si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
+ bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
+ 0x03CDDDDD);
if ((pi->sh->boardflags & BFL_FEM)
&& wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
@@ -4968,7 +4977,7 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
pi->hwpwrctrl_capable = true;
}
- pi->xtalfreq = si_pmu_alp_clock(pi->sh->sih);
+ pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
pi->pi_fptr.init = wlc_phy_init_lcnphy;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index 65db9b7458dc..3e9f5b25be63 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -19321,14 +19321,13 @@ void wlc_phy_init_nphy(struct brcms_phy *pi)
(pi->sh->chippkg == BCMA_PKG_ID_BCM4718))) {
if ((pi->sh->boardflags & BFL_EXTLNA) &&
(CHSPEC_IS2G(pi->radio_chanspec)))
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, chipcontrol),
- 0x40, 0x40);
+ bcma_cc_set32(&pi->d11core->bus->drv_cc,
+ BCMA_CC_CHIPCTL, 0x40);
}
if ((!PHY_IPA(pi)) && (pi->sh->chip == BCMA_CHIP_ID_BCM5357))
- si_pmu_chipcontrol(pi->sh->sih, 1, CCTRL5357_EXTPA,
- CCTRL5357_EXTPA);
+ bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 1,
+ ~CCTRL5357_EXTPA, CCTRL5357_EXTPA);
if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) &&
CHSPEC_IS40(pi->radio_chanspec)) {
@@ -21133,7 +21132,6 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec,
const struct nphy_sfo_cfg *ci)
{
u16 val;
- struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub);
val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
if (CHSPEC_IS5G(chanspec) && !val) {
@@ -21221,11 +21219,11 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec,
if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) ||
(pi->sh->chip == BCMA_CHIP_ID_BCM43225)) {
- bcma_pmu_spuravoid_pllupdate(&sii->icbus->drv_cc,
+ bcma_pmu_spuravoid_pllupdate(&pi->d11core->bus->drv_cc,
spuravoid);
} else {
wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false);
- bcma_pmu_spuravoid_pllupdate(&sii->icbus->drv_cc,
+ bcma_pmu_spuravoid_pllupdate(&pi->d11core->bus->drv_cc,
spuravoid);
wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true);
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c
index 7e9df566c733..71b80381f3ad 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c
@@ -115,60 +115,6 @@ u16 si_pmu_fast_pwrup_delay(struct si_pub *sih)
return (u16) delay;
}
-/* Read/write a chipcontrol reg */
-u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
-{
- ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol_addr), ~0, reg);
- return ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol_data),
- mask, val);
-}
-
-/* Read/write a regcontrol reg */
-u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
-{
- ai_cc_reg(sih, offsetof(struct chipcregs, regcontrol_addr), ~0, reg);
- return ai_cc_reg(sih, offsetof(struct chipcregs, regcontrol_data),
- mask, val);
-}
-
-/* Read/write a pllcontrol reg */
-u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
-{
- ai_cc_reg(sih, offsetof(struct chipcregs, pllcontrol_addr), ~0, reg);
- return ai_cc_reg(sih, offsetof(struct chipcregs, pllcontrol_data),
- mask, val);
-}
-
-/* PMU PLL update */
-void si_pmu_pllupd(struct si_pub *sih)
-{
- ai_cc_reg(sih, offsetof(struct chipcregs, pmucontrol),
- PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD);
-}
-
-/* query alp/xtal clock frequency */
-u32 si_pmu_alp_clock(struct si_pub *sih)
-{
- u32 clock = ALP_CLOCK;
-
- /* bail out with default */
- if (!(ai_get_cccaps(sih) & CC_CAP_PMU))
- return clock;
-
- switch (ai_get_chip_id(sih)) {
- case BCMA_CHIP_ID_BCM43224:
- case BCMA_CHIP_ID_BCM43225:
- case BCMA_CHIP_ID_BCM4313:
- /* always 20Mhz */
- clock = 20000 * 1000;
- break;
- default:
- break;
- }
-
- return clock;
-}
-
u32 si_pmu_measure_alpclk(struct si_pub *sih)
{
struct si_info *sii = container_of(sih, struct si_info, pub);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h
index f7cff873578b..20e2012d5a3a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h
@@ -21,12 +21,6 @@
#include "types.h"
extern u16 si_pmu_fast_pwrup_delay(struct si_pub *sih);
-extern void si_pmu_sprom_enable(struct si_pub *sih, bool enable);
-extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
-extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
-extern u32 si_pmu_alp_clock(struct si_pub *sih);
-extern void si_pmu_pllupd(struct si_pub *sih);
-extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
extern u32 si_pmu_measure_alpclk(struct si_pub *sih);
#endif /* _BRCM_PMU_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
index b0f14b7b8616..d36ea5e1cc49 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
@@ -164,8 +164,6 @@ struct brcms_pub {
u8 cur_etheraddr[ETH_ALEN]; /* our local ethernet address */
- int bcmerror; /* last bcm error */
-
u32 radio_disabled; /* bit vector for radio disabled reasons */
u16 boardrev; /* version # of particular board */
@@ -326,10 +324,25 @@ extern void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,
s8 sslot_override);
extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
u8 interval);
+extern u64 brcms_c_tsf_get(struct brcms_c_info *wlc);
+extern void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf);
extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
+extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr);
+extern void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr,
+ const u8 *bssid, u8 *ssid, size_t ssid_len);
+extern void brcms_c_start_adhoc(struct brcms_c_info *wlc, u8 *addr);
+extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
+extern void brcms_c_set_new_beacon(struct brcms_c_info *wlc,
+ struct sk_buff *beacon, u16 tim_offset,
+ u16 dtim_period);
+extern void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc,
+ struct sk_buff *probe_resp);
+extern void brcms_c_enable_probe_resp(struct brcms_c_info *wlc, bool enable);
+extern void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid,
+ size_t ssid_len);
#endif /* _BRCM_PUB_H_ */
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
index c11a290a1edf..0505cc065e0d 100644
--- a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
+++ b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
@@ -32,8 +32,9 @@
#define CH_20MHZ_APART 4
#define CH_10MHZ_APART 2
#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
+#define CH_MIN_2G_CHANNEL 1
#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
-#define BRCM_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL /* legacy define */
+#define CH_MIN_5G_CHANNEL 34
/* bandstate array indices */
#define BAND_2G_INDEX 0 /* wlc->bandstate[x] index */
@@ -60,6 +61,7 @@
#define WL_CHANSPEC_BW_10 0x0400
#define WL_CHANSPEC_BW_20 0x0800
#define WL_CHANSPEC_BW_40 0x0C00
+#define WL_CHANSPEC_BW_80 0x2000
#define WL_CHANSPEC_BAND_MASK 0xf000
#define WL_CHANSPEC_BAND_SHIFT 12
@@ -67,6 +69,25 @@
#define WL_CHANSPEC_BAND_2G 0x2000
#define INVCHANSPEC 255
+#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */
+#define WL_CHAN_VALID_SW (1 << 1) /* valid with country sett. */
+#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */
+#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */
+#define WL_CHAN_INACTIVE (1 << 4) /* inactive due to radar */
+#define WL_CHAN_PASSIVE (1 << 5) /* channel in passive mode */
+#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */
+
+/* values for band specific 40MHz capabilities */
+#define WLC_N_BW_20ALL 0
+#define WLC_N_BW_40ALL 1
+#define WLC_N_BW_20IN2G_40IN5G 2
+
+/* band types */
+#define WLC_BAND_AUTO 0 /* auto-select */
+#define WLC_BAND_5G 1 /* 5 Ghz */
+#define WLC_BAND_2G 2 /* 2.4 Ghz */
+#define WLC_BAND_ALL 3 /* all bands */
+
#define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
@@ -79,10 +100,11 @@
#define CHSPEC_IS20(chspec) \
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
-#ifndef CHSPEC_IS40
#define CHSPEC_IS40(chspec) \
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
-#endif
+
+#define CHSPEC_IS80(chspec) \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80)
#define CHSPEC_IS5G(chspec) \
(((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index 5b79819d7bed..3613b3a81ad2 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -4701,8 +4701,7 @@ out:
}
EXPORT_SYMBOL(il_mac_change_interface);
-void
-il_mac_flush(struct ieee80211_hw *hw, bool drop)
+void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct il_priv *il = hw->priv;
unsigned long timeout = jiffies + msecs_to_jiffies(500);
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index 10986aaf9085..f8246f2d88f9 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -1720,7 +1720,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum nl80211_iftype newtype, bool newp2p);
-void il_mac_flush(struct ieee80211_hw *hw, bool drop);
+void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
int il_alloc_txq_mem(struct il_priv *il);
void il_free_txq_mem(struct il_priv *il);
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index c7cd2dffa5cd..a7294fa4d7e5 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1100,7 +1100,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
-static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 3ce4e9d5082d..498300577ac0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -1266,7 +1266,3 @@ module_param_named(auto_agg, iwlwifi_mod_params.auto_agg,
bool, S_IRUGO);
MODULE_PARM_DESC(auto_agg,
"enable agg w/o check traffic load (default: enable)");
-
-module_param_named(5ghz_disable, iwlwifi_mod_params.disable_5ghz,
- bool, S_IRUGO);
-MODULE_PARM_DESC(5ghz_disable, "disable 5GHz band (default: 0 [enabled])");
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 435618574240..c4c446d41eb0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -154,6 +154,19 @@ struct iwl_tlv_calib_ctrl {
__le32 event_trigger;
} __packed;
+enum iwl_fw_phy_cfg {
+ FW_PHY_CFG_RADIO_TYPE_POS = 0,
+ FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS,
+ FW_PHY_CFG_RADIO_STEP_POS = 2,
+ FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS,
+ FW_PHY_CFG_RADIO_DASH_POS = 4,
+ FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS,
+ FW_PHY_CFG_TX_CHAIN_POS = 16,
+ FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS,
+ FW_PHY_CFG_RX_CHAIN_POS = 20,
+ FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
+};
+
/**
* struct iwl_fw - variables associated with the firmware
*
@@ -190,4 +203,16 @@ struct iwl_fw {
bool mvm_fw;
};
+static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
+{
+ return (fw->phy_config & FW_PHY_CFG_TX_CHAIN) >>
+ FW_PHY_CFG_TX_CHAIN_POS;
+}
+
+static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw)
+{
+ return (fw->phy_config & FW_PHY_CFG_RX_CHAIN) >>
+ FW_PHY_CFG_RX_CHAIN_POS;
+}
+
#endif /* __iwl_fw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index 3cc39ffe8ba5..d6f6c37c09fd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -103,7 +103,6 @@ enum iwl_power_level {
* @ant_coupling: antenna coupling in dB, default = 0
* @bt_ch_announce: BT channel inhibition, default = enable
* @auto_agg: enable agg. without check, default = true
- * @disable_5ghz: disable 5GHz capability, default = false
*/
struct iwl_mod_params {
int sw_crypto;
@@ -120,7 +119,6 @@ struct iwl_mod_params {
int ant_coupling;
bool bt_ch_announce;
bool auto_agg;
- bool disable_5ghz;
};
#endif /* #__iwl_modparams_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
index efff2986b5b4..5cfd55b86ed3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.c
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -272,7 +272,7 @@ static int iwl_test_fw_cmd(struct iwl_test *tst, struct nlattr **tb)
reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
skb = iwl_test_alloc_reply(tst, reply_len + 20);
- reply_buf = kmalloc(reply_len, GFP_KERNEL);
+ reply_buf = kmemdup(&pkt->hdr, reply_len, GFP_KERNEL);
if (!skb || !reply_buf) {
kfree_skb(skb);
kfree(reply_buf);
@@ -280,7 +280,6 @@ static int iwl_test_fw_cmd(struct iwl_test *tst, struct nlattr **tb)
}
/* The reply is in a page, that we cannot send to user space. */
- memcpy(reply_buf, &(pkt->hdr), reply_len);
iwl_free_resp(&cmd);
if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
index 47954deb6493..1700232aa166 100644
--- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
@@ -125,15 +125,15 @@ enum iwl_bt_kill_msk {
};
static const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = {
- 0xffffffff,
- 0xfffffc00,
- 0,
+ [BT_KILL_MSK_DEFAULT] = 0xffff0000,
+ [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
+ [BT_KILL_MSK_REDUCED_TXPOW] = 0,
};
static const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = {
- 0xffffffff,
- 0xfffffc00,
- 0,
+ [BT_KILL_MSK_DEFAULT] = 0xffff0000,
+ [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
+ [BT_KILL_MSK_REDUCED_TXPOW] = 0,
};
#define IWL_BT_DEFAULT_BOOST (0xf0f0f0f0)
@@ -188,6 +188,8 @@ static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = {
/* BT Antenna Coupling Threshold (dB) */
#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
+#define IWL_BT_LOAD_FORCE_SISO_THRESHOLD (3)
+
int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
{
@@ -201,8 +203,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
cmd.flags = iwlwifi_mod_params.bt_coex_active ?
BT_COEX_NW : BT_COEX_DISABLE;
- cmd.flags |= iwlwifi_mod_params.bt_ch_announce ?
- BT_CH_PRIMARY_EN | BT_CH_SECONDARY_EN : 0;
+ cmd.flags |= iwlwifi_mod_params.bt_ch_announce ? BT_CH_PRIMARY_EN : 0;
cmd.flags |= BT_SYNC_2_BT_DISABLE;
cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE |
@@ -275,7 +276,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (data->notif->bt_status)
smps_mode = IEEE80211_SMPS_DYNAMIC;
- if (data->notif->bt_traffic_load)
+ if (data->notif->bt_traffic_load >= IWL_BT_LOAD_FORCE_SISO_THRESHOLD)
smps_mode = IEEE80211_SMPS_STATIC;
IWL_DEBUG_COEX(data->mvm,
@@ -327,7 +328,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
return 0;
IWL_DEBUG_COEX(mvm,
- "Udpate kill_msk: %d\n\t SCO %sactive A2DP %sactive SNIFF %sactive\n",
+ "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n",
bt_kill_msk,
BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index d4578cefe445..bf087abe39f3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -866,17 +866,13 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
if (wowlan->rfkill_release)
- d3_cfg_cmd.wakeup_flags |=
+ wowlan_config_cmd.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
if (wowlan->tcp) {
/*
- * The firmware currently doesn't really look at these, only
- * the IWL_WOWLAN_WAKEUP_LINK_CHANGE bit. We have to set that
- * reason bit since losing the connection to the AP implies
- * losing the TCP connection.
- * Set the flags anyway as long as they exist, in case this
- * will be changed in the firmware.
+ * Set the "link change" (really "link lost") flag as well
+ * since that implies losing the TCP connection.
*/
wowlan_config_cmd.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
index 6d53850c5448..007a93b25bd7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -537,6 +537,12 @@ struct iwl_mac_beacon_cmd {
struct ieee80211_hdr frame[0];
} __packed;
+struct iwl_beacon_notif {
+ struct iwl_mvm_tx_resp beacon_notify_hdr;
+ __le64 tsf;
+ __le32 ibss_mgr_status;
+} __packed;
+
/**
* enum iwl_dump_control - dump (flush) control flags
* @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index f8d7e88234e4..1073f2682221 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -151,6 +151,7 @@ enum {
SET_CALIB_DEFAULT_CMD = 0x8e,
+ BEACON_NOTIFICATION = 0x90,
BEACON_TEMPLATE_CMD = 0x91,
TX_ANT_CONFIGURATION_CMD = 0x98,
BT_CONFIG = 0x9b,
@@ -278,38 +279,7 @@ enum {
NVM_ACCESS_TARGET_EEPROM = 2,
};
-/**
- * struct iwl_nvm_access_cmd_ver1 - Request the device to send the NVM.
- * @op_code: 0 - read, 1 - write.
- * @target: NVM_ACCESS_TARGET_*. should be 0 for read.
- * @cache_refresh: 0 - None, 1- NVM.
- * @offset: offset in the nvm data.
- * @length: of the chunk.
- * @data: empty on read, the NVM chunk on write
- */
-struct iwl_nvm_access_cmd_ver1 {
- u8 op_code;
- u8 target;
- u8 cache_refresh;
- u8 reserved;
- __le16 offset;
- __le16 length;
- u8 data[];
-} __packed; /* NVM_ACCESS_CMD_API_S_VER_1 */
-
-/**
- * struct iwl_nvm_access_resp_ver1 - response to NVM_ACCESS_CMD
- * @offset: the offset in the nvm data
- * @length: of the chunk
- * @data: the nvm chunk on when NVM_ACCESS_CMD was read, nothing on write
- */
-struct iwl_nvm_access_resp_ver1 {
- __le16 offset;
- __le16 length;
- u8 data[];
-} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_1 */
-
-/* Section types for NVM_ACCESS_CMD version 2 */
+/* Section types for NVM_ACCESS_CMD */
enum {
NVM_SECTION_TYPE_HW = 0,
NVM_SECTION_TYPE_SW,
@@ -330,7 +300,7 @@ enum {
* @length: in bytes, to read/write
* @data: if write operation, the data to write. On read its empty
*/
-struct iwl_nvm_access_cmd_ver2 {
+struct iwl_nvm_access_cmd {
u8 op_code;
u8 target;
__le16 type;
@@ -347,7 +317,7 @@ struct iwl_nvm_access_cmd_ver2 {
* @status: 0 for success, fail otherwise
* @data: if read operation, the data returned. Empty on write.
*/
-struct iwl_nvm_access_resp_ver2 {
+struct iwl_nvm_access_resp {
__le16 offset;
__le16 length;
__le16 type;
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 1006b3204e7b..e18c92dd60ec 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -114,7 +114,7 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)
.valid = cpu_to_le32(valid_tx_ant),
};
- IWL_DEBUG_HC(mvm, "select valid tx ant: %u\n", valid_tx_ant);
+ IWL_DEBUG_FW(mvm, "select valid tx ant: %u\n", valid_tx_ant);
return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC,
sizeof(tx_ant_cmd), &tx_ant_cmd);
}
@@ -134,9 +134,10 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK;
- IWL_DEBUG_FW(mvm, "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n",
+ IWL_DEBUG_FW(mvm,
+ "Alive ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
le16_to_cpu(palive->status), palive->ver_type,
- palive->ver_subtype);
+ palive->ver_subtype, palive->flags);
return true;
}
@@ -326,16 +327,14 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
WARN_ON(ret);
/* Send TX valid antennas before triggering calibrations */
- ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret)
goto error;
- /* WkP doesn't have all calibrations, need to set default values */
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- ret = iwl_set_default_calibrations(mvm);
- if (ret)
- goto error;
- }
+ /* need to set default values */
+ ret = iwl_set_default_calibrations(mvm);
+ if (ret)
+ goto error;
/*
* Send phy configurations command to init uCode
@@ -414,7 +413,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
- ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret)
goto error;
@@ -468,7 +467,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
goto error;
}
- ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret)
goto error;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 2779235daa35..86e312a4f629 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -196,7 +196,7 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
u32 qmask, ac;
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
- return BIT(IWL_OFFCHANNEL_QUEUE);
+ return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ?
BIT(vif->cab_queue) : 0;
@@ -692,7 +692,12 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
- /* No other data to be filled */
+
+ cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |
+ MAC_FILTER_IN_CONTROL_AND_MGMT |
+ MAC_FILTER_IN_BEACON |
+ MAC_FILTER_IN_PROBE_REQUEST);
+
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@@ -798,7 +803,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
TX_CMD_FLG_TSF);
mvm->mgmt_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+ iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
mvm->mgmt_last_antenna_idx);
beacon_cmd.tx.rate_n_flags =
@@ -1013,3 +1018,22 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif->uploaded = false;
return 0;
}
+
+int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_beacon_notif *beacon = (void *)pkt->data;
+ u16 status __maybe_unused =
+ le16_to_cpu(beacon->beacon_notify_hdr.status.status);
+ u32 rate __maybe_unused =
+ le32_to_cpu(beacon->beacon_notify_hdr.initial_rate);
+
+ IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n",
+ status & TX_STATUS_MSK,
+ beacon->beacon_notify_hdr.failure_frame,
+ le64_to_cpu(beacon->tsf),
+ rate);
+ return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 14dd5ee9a01e..3d193f8c33b6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -143,8 +143,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TIMING_BEACON_ONLY;
- hw->queues = IWL_FIRST_AMPDU_QUEUE;
- hw->offchannel_tx_hw_queue = IWL_OFFCHANNEL_QUEUE;
+ hw->queues = IWL_MVM_FIRST_AGG_QUEUE;
+ hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
hw->rate_control_algorithm = "iwl-mvm-rs";
/*
@@ -174,7 +174,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->n_iface_combinations =
ARRAY_SIZE(iwl_mvm_iface_combinations);
- hw->wiphy->max_remain_on_channel_duration = 500;
+ hw->wiphy->max_remain_on_channel_duration = 10000;
hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
/* Extract MAC address */
@@ -257,7 +257,7 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
goto drop;
}
- if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_OFFCHANNEL_QUEUE &&
+ if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
!test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
goto drop;
@@ -1087,6 +1087,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
+ if (vif->type == NL80211_IFTYPE_AP && !sta) {
+ /* GTK on AP interface is a TX-only key, return 0 */
+ ret = 0;
+ key->hw_key_idx = STA_KEY_IDX_INVALID;
+ break;
+ }
+
IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false);
if (ret) {
@@ -1095,11 +1102,17 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
* can't add key for RX, but we don't need it
* in the device for TX so still return 0
*/
+ key->hw_key_idx = STA_KEY_IDX_INVALID;
ret = 0;
}
break;
case DISABLE_KEY:
+ if (key->hw_key_idx == STA_KEY_IDX_INVALID) {
+ ret = 0;
+ break;
+ }
+
IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");
ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
break;
@@ -1148,7 +1161,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
&chandef, 1, 1);
/* Schedule the time events */
- ret = iwl_mvm_start_p2p_roc(mvm, vif, duration);
+ ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type);
mutex_unlock(&mvm->mutex);
IWL_DEBUG_MAC80211(mvm, "leave\n");
@@ -1252,6 +1265,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
* will handle quota settings.
*/
if (vif->type == NL80211_IFTYPE_MONITOR) {
+ mvmvif->monitor_active = true;
ret = iwl_mvm_update_quotas(mvm, vif);
if (ret)
goto out_remove_binding;
@@ -1282,15 +1296,16 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_AP)
goto out_unlock;
- iwl_mvm_binding_remove_vif(mvm, vif);
switch (vif->type) {
case NL80211_IFTYPE_MONITOR:
- iwl_mvm_update_quotas(mvm, vif);
+ mvmvif->monitor_active = false;
+ iwl_mvm_update_quotas(mvm, NULL);
break;
default:
break;
}
+ iwl_mvm_binding_remove_vif(mvm, vif);
out_unlock:
mvmvif->phy_ctxt = NULL;
mutex_unlock(&mvm->mutex);
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 203eb85e03d3..53d58968e30a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -90,10 +90,6 @@ enum iwl_mvm_tx_fifo {
IWL_MVM_TX_FIFO_VO,
};
-/* Placeholder */
-#define IWL_OFFCHANNEL_QUEUE 8
-#define IWL_FIRST_AMPDU_QUEUE 11
-
extern struct ieee80211_ops iwl_mvm_hw_ops;
/**
* struct iwl_mvm_mod_params - module parameters for iwlmvm
@@ -161,6 +157,8 @@ enum iwl_power_scheme {
* @uploaded: indicates the MAC context has been added to the device
* @ap_active: indicates that ap context is configured, and that the interface
* should get quota etc.
+ * @monitor_active: indicates that monitor context is configured, and that the
+ * interface should get quota etc.
* @queue_params: QoS params for this MAC
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
@@ -173,6 +171,7 @@ struct iwl_mvm_vif {
bool uploaded;
bool ap_active;
+ bool monitor_active;
u32 ap_beacon_time;
@@ -281,10 +280,7 @@ struct iwl_mvm {
atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
struct iwl_nvm_data *nvm_data;
- /* eeprom blob for debugfs/testmode */
- u8 *eeprom_blob;
- size_t eeprom_blob_size;
- /* NVM sections for 7000 family */
+ /* NVM sections */
struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS];
/* EEPROM MAC addresses */
@@ -451,6 +447,9 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
+int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
/* Bindings */
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 93e3d0f174cc..b8ec02f89acc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -77,26 +77,8 @@ static const int nvm_to_read[] = {
/* Default NVM size to read */
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024);
-/* used to simplify the shared operations on NCM_ACCESS_CMD versions */
-union iwl_nvm_access_cmd {
- struct iwl_nvm_access_cmd_ver1 ver1;
- struct iwl_nvm_access_cmd_ver2 ver2;
-};
-union iwl_nvm_access_resp {
- struct iwl_nvm_access_resp_ver1 ver1;
- struct iwl_nvm_access_resp_ver2 ver2;
-};
-
-static inline void iwl_nvm_fill_read_ver1(struct iwl_nvm_access_cmd_ver1 *cmd,
- u16 offset, u16 length)
-{
- cmd->offset = cpu_to_le16(offset);
- cmd->length = cpu_to_le16(length);
- cmd->cache_refresh = 1;
-}
-
-static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd,
- u16 offset, u16 length, u16 section)
+static inline void iwl_nvm_fill_read(struct iwl_nvm_access_cmd *cmd,
+ u16 offset, u16 length, u16 section)
{
cmd->offset = cpu_to_le16(offset);
cmd->length = cpu_to_le16(length);
@@ -106,8 +88,8 @@ static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd,
static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
u16 offset, u16 length, u8 *data)
{
- union iwl_nvm_access_cmd nvm_access_cmd;
- union iwl_nvm_access_resp *nvm_resp;
+ struct iwl_nvm_access_cmd nvm_access_cmd = {};
+ struct iwl_nvm_access_resp *nvm_resp;
struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = {
.id = NVM_ACCESS_CMD,
@@ -117,18 +99,8 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
int ret, bytes_read, offset_read;
u8 *resp_data;
- memset(&nvm_access_cmd, 0, sizeof(nvm_access_cmd));
-
- /* TODO: not sure family should be the decider, maybe FW version? */
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- iwl_nvm_fill_read_ver2(&(nvm_access_cmd.ver2),
- offset, length, section);
- cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver2);
- } else {
- iwl_nvm_fill_read_ver1(&(nvm_access_cmd.ver1),
- offset, length);
- cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver1);
- }
+ iwl_nvm_fill_read(&nvm_access_cmd, offset, length, section);
+ cmd.len[0] = sizeof(struct iwl_nvm_access_cmd);
ret = iwl_mvm_send_cmd(mvm, &cmd);
if (ret)
@@ -144,17 +116,10 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
/* Extract NVM response */
nvm_resp = (void *)pkt->data;
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- ret = le16_to_cpu(nvm_resp->ver2.status);
- bytes_read = le16_to_cpu(nvm_resp->ver2.length);
- offset_read = le16_to_cpu(nvm_resp->ver2.offset);
- resp_data = nvm_resp->ver2.data;
- } else {
- ret = le16_to_cpu(nvm_resp->ver1.length) <= 0;
- bytes_read = le16_to_cpu(nvm_resp->ver1.length);
- offset_read = le16_to_cpu(nvm_resp->ver1.offset);
- resp_data = nvm_resp->ver1.data;
- }
+ ret = le16_to_cpu(nvm_resp->status);
+ bytes_read = le16_to_cpu(nvm_resp->length);
+ offset_read = le16_to_cpu(nvm_resp->offset);
+ resp_data = nvm_resp->data;
if (ret) {
IWL_ERR(mvm,
"NVM access command failed with status %d (device: %s)\n",
@@ -194,17 +159,10 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
{
u16 length, offset = 0;
int ret;
- bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000;
/* Set nvm section read length */
length = IWL_NVM_DEFAULT_CHUNK_SIZE;
- /*
- * if length is greater than EEPROM size, truncate it because uCode
- * doesn't check it by itself, and exit the loop when reached.
- */
- if (old_eeprom && length > mvm->cfg->base_params->eeprom_size)
- length = mvm->cfg->base_params->eeprom_size;
ret = length;
/* Read the NVM until exhausted (reading less than requested) */
@@ -217,8 +175,6 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
return ret;
}
offset += ret;
- if (old_eeprom && offset == mvm->cfg->base_params->eeprom_size)
- break;
}
IWL_INFO(mvm, "NVM section %d read completed\n", section);
@@ -252,63 +208,31 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
int ret, i, section;
u8 *nvm_buffer, *temp;
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- /* TODO: find correct NVM max size for a section */
- nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
- GFP_KERNEL);
- if (!nvm_buffer)
- return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
- section = nvm_to_read[i];
- /* we override the constness for initial read */
- ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
- if (ret < 0)
- break;
- temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
- if (!temp) {
- ret = -ENOMEM;
- break;
- }
- mvm->nvm_sections[section].data = temp;
- mvm->nvm_sections[section].length = ret;
- }
- kfree(nvm_buffer);
+ /* TODO: find correct NVM max size for a section */
+ nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
+ GFP_KERNEL);
+ if (!nvm_buffer)
+ return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
+ section = nvm_to_read[i];
+ /* we override the constness for initial read */
+ ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
if (ret < 0)
- return ret;
- } else {
- /* allocate eeprom */
- mvm->eeprom_blob_size = mvm->cfg->base_params->eeprom_size;
- IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM size = %zd\n",
- mvm->eeprom_blob_size);
- mvm->eeprom_blob = kzalloc(mvm->eeprom_blob_size, GFP_KERNEL);
- if (!mvm->eeprom_blob)
- return -ENOMEM;
-
- ret = iwl_nvm_read_section(mvm, 0, mvm->eeprom_blob);
- if (ret != mvm->eeprom_blob_size) {
- IWL_ERR(mvm, "Read partial NVM %d/%zd\n",
- ret, mvm->eeprom_blob_size);
- kfree(mvm->eeprom_blob);
- mvm->eeprom_blob = NULL;
- return -EINVAL;
+ break;
+ temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
+ if (!temp) {
+ ret = -ENOMEM;
+ break;
}
+ mvm->nvm_sections[section].data = temp;
+ mvm->nvm_sections[section].length = ret;
}
+ kfree(nvm_buffer);
+ if (ret < 0)
+ return ret;
ret = 0;
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
- mvm->nvm_data = iwl_parse_nvm_sections(mvm);
- else
- mvm->nvm_data =
- iwl_parse_eeprom_data(mvm->trans->dev,
- mvm->cfg,
- mvm->eeprom_blob,
- mvm->eeprom_blob_size);
-
- if (!mvm->nvm_data) {
- kfree(mvm->eeprom_blob);
- mvm->eeprom_blob = NULL;
- ret = -ENOMEM;
- }
+ mvm->nvm_data = iwl_parse_nvm_sections(mvm);
return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 828bdddd07e9..fe031d304d1e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -143,21 +143,12 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash;
u32 reg_val = 0;
- /*
- * We can't upload the correct value to the INIT image
- * as we don't have nvm_data by that time.
- *
- * TODO: Figure out what we should do here
- */
- if (mvm->nvm_data) {
- radio_cfg_type = mvm->nvm_data->radio_cfg_type;
- radio_cfg_step = mvm->nvm_data->radio_cfg_step;
- radio_cfg_dash = mvm->nvm_data->radio_cfg_dash;
- } else {
- radio_cfg_type = 0;
- radio_cfg_step = 0;
- radio_cfg_dash = 0;
- }
+ radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >>
+ FW_PHY_CFG_RADIO_TYPE_POS;
+ radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >>
+ FW_PHY_CFG_RADIO_STEP_POS;
+ radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >>
+ FW_PHY_CFG_RADIO_DASH_POS;
/* SKU control */
reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) <<
@@ -175,7 +166,6 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
/* silicon bits */
reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI;
- reg_val |= CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
@@ -231,6 +221,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
+ RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false),
RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
@@ -276,6 +267,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(WEP_KEY),
CMD(REPLY_RX_PHY_CMD),
CMD(REPLY_RX_MPDU_CMD),
+ CMD(BEACON_NOTIFICATION),
CMD(BEACON_TEMPLATE_CMD),
CMD(STATISTICS_NOTIFICATION),
CMD(TX_ANT_CONFIGURATION_CMD),
@@ -319,16 +311,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
};
int err, scan_size;
- switch (cfg->device_family) {
- case IWL_DEVICE_FAMILY_6030:
- case IWL_DEVICE_FAMILY_6005:
- case IWL_DEVICE_FAMILY_7000:
- break;
- default:
- IWL_ERR(trans, "Trying to load mvm on an unsupported device\n");
- return NULL;
- }
-
/********************************
* 1. Allocating and configuring HW data
********************************/
@@ -444,7 +426,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
out_free:
iwl_phy_db_free(mvm->phy_db);
kfree(mvm->scan_cmd);
- kfree(mvm->eeprom_blob);
iwl_trans_stop_hw(trans, true);
ieee80211_free_hw(mvm->hw);
return NULL;
@@ -466,7 +447,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
iwl_phy_db_free(mvm->phy_db);
mvm->phy_db = NULL;
- kfree(mvm->eeprom_blob);
iwl_free_nvm_data(mvm->nvm_data);
for (i = 0; i < NVM_NUM_OF_SECTIONS; i++)
kfree(mvm->nvm_sections[i].data);
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index 0d537e035ef0..0f0b44eabd93 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -142,7 +142,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
struct cfg80211_chan_def *chandef,
u8 chains_static, u8 chains_dynamic)
{
- u8 valid_rx_chains, active_cnt, idle_cnt;
+ u8 active_cnt, idle_cnt;
/* Set the channel info data */
cmd->ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ?
@@ -158,17 +158,16 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
* Need to add on chain noise calibration limitations, and
* BT coex considerations.
*/
- valid_rx_chains = mvm->nvm_data->valid_rx_ant;
idle_cnt = chains_static;
active_cnt = chains_dynamic;
- cmd->rxchain_info = cpu_to_le32(valid_rx_chains <<
+ cmd->rxchain_info = cpu_to_le32(iwl_fw_valid_rx_ant(mvm->fw) <<
PHY_RX_CHAIN_VALID_POS);
cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
cmd->rxchain_info |= cpu_to_le32(active_cnt <<
PHY_RX_CHAIN_MIMO_CNT_POS);
- cmd->txchain_info = cpu_to_le32(mvm->nvm_data->valid_tx_ant);
+ cmd->txchain_info = cpu_to_le32(iwl_fw_valid_tx_ant(mvm->fw));
}
/*
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c
index df85c49dc599..a1e3e923ea3e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/quota.c
+++ b/drivers/net/wireless/iwlwifi/mvm/quota.c
@@ -114,7 +114,8 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
data->n_interfaces[id]++;
break;
case NL80211_IFTYPE_MONITOR:
- data->n_interfaces[id]++;
+ if (mvmvif->monitor_active)
+ data->n_interfaces[id]++;
break;
case NL80211_IFTYPE_P2P_DEVICE:
break;
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 0d3c76b29242..2157b0f8ced5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -74,7 +74,7 @@
static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
{
u16 rx_chain;
- u8 rx_ant = mvm->nvm_data->valid_rx_ant;
+ u8 rx_ant = iwl_fw_valid_rx_ant(mvm->fw);
rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS;
rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
@@ -115,7 +115,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
u32 tx_ant;
mvm->scan_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+ iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
mvm->scan_last_antenna_idx);
tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index c2c7f5176027..4dc934bed055 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -76,14 +76,12 @@
#define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024))
#define MSEC_TO_TU(_msec) (_msec*1000/1024)
-/* For ROC use a TE type which has priority high enough to be scheduled when
- * there is a concurrent BSS or GO/AP. Currently, use a TE type that has
- * priority similar to the TE priority used for action scans by the FW.
- * TODO: This needs to be changed, based on the reason for the ROC, i.e., use
- * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use
- * TE_P2P_DEVICE_ACTION_SCAN
+/*
+ * For the high priority TE use a time event type that has similar priority to
+ * the FW's action scan priority.
*/
-#define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN
+#define IWL_MVM_ROC_TE_TYPE_NORMAL TE_P2P_DEVICE_DISCOVERABLE
+#define IWL_MVM_ROC_TE_TYPE_MGMT_TX TE_P2P_CLIENT_ASSOC
void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
struct iwl_mvm_time_event_data *te_data)
@@ -116,7 +114,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
* issue as it will have to complete before the next command is
* executed, and a new time event means a new command.
*/
- iwl_mvm_flush_tx_path(mvm, BIT(IWL_OFFCHANNEL_QUEUE), false);
+ iwl_mvm_flush_tx_path(mvm, BIT(IWL_MVM_OFFCHANNEL_QUEUE), false);
}
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
@@ -438,7 +436,7 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
}
int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- int duration)
+ int duration, enum ieee80211_roc_type type)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
@@ -459,21 +457,29 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
time_cmd.id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
- time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE);
+
+ switch (type) {
+ case IEEE80211_ROC_TYPE_NORMAL:
+ time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_NORMAL);
+ break;
+ case IEEE80211_ROC_TYPE_MGMT_TX:
+ time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_MGMT_TX);
+ break;
+ default:
+ WARN_ONCE(1, "Got an invalid ROC type\n");
+ return -EINVAL;
+ }
time_cmd.apply_time = cpu_to_le32(0);
time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT);
time_cmd.is_present = cpu_to_le32(1);
-
time_cmd.interval = cpu_to_le32(1);
/*
- * IWL_MVM_ROC_TE_TYPE can have lower priority than other events
+ * The P2P Device TEs can have lower priority than other events
* that are being scheduled by the driver/fw, and thus it might not be
- * scheduled. To improve the chances of it being scheduled, allow it to
- * be fragmented.
- * In addition, for the same reasons, allow to delay the scheduling of
- * the time event.
+ * scheduled. To improve the chances of it being scheduled, allow them
+ * to be fragmented, and in addition allow them to be delayed.
*/
time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20);
time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h
index b36424eda361..f86c51065ed3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.h
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h
@@ -162,6 +162,7 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
* that the vif type is NL80211_IFTYPE_P2P_DEVICE
* @duration: the requested duration in millisecond for the fw to be on the
* channel that is bound to the vif.
+ * @type: the remain on channel request type
*
* This function can be used to issue a remain on channel session,
* which means that the fw will stay in the channel for the request %duration
@@ -172,7 +173,7 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
* another notification to the driver.
*/
int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- int duration);
+ int duration, enum ieee80211_roc_type type);
/**
* iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index 0556d5e16f4e..0acc0bff43c7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -417,7 +417,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
spin_unlock(&mvmsta->lock);
if (mvmsta->vif->type == NL80211_IFTYPE_AP &&
- txq_id < IWL_FIRST_AMPDU_QUEUE)
+ txq_id < IWL_MVM_FIRST_AGG_QUEUE)
atomic_inc(&mvmsta->pending_frames);
return 0;
@@ -606,7 +606,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
info);
/* Single frame failure in an AMPDU queue => send BAR */
- if (txq_id >= IWL_FIRST_AMPDU_QUEUE &&
+ if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE &&
!(info->flags & IEEE80211_TX_STAT_ACK))
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
@@ -619,7 +619,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
ieee80211_tx_status_ni(mvm->hw, skb);
}
- if (txq_id >= IWL_FIRST_AMPDU_QUEUE) {
+ if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE) {
/* If this is an aggregation queue, we use the ssn since:
* ssn = wifi seq_num % 256.
* The seq_ctl is the sequence control of the packet to which
@@ -681,7 +681,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
* If there are no pending frames for this STA, notify mac80211 that
* this station can go to sleep in its STA table.
*/
- if (txq_id < IWL_FIRST_AMPDU_QUEUE && mvmsta &&
+ if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta &&
!WARN_ON(skb_freed > 1) &&
mvmsta->vif->type == NL80211_IFTYPE_AP &&
atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) {
@@ -750,7 +750,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
struct ieee80211_sta *sta;
- if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_FIRST_AMPDU_QUEUE))
+ if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_MVM_FIRST_AGG_QUEUE))
return;
if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS))
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 282a5cafa913..68466ca80770 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1564,8 +1564,11 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
if (test_bit(STATUS_FW_ERROR, &trans_pcie->status))
return -EIO;
- if (test_bit(STATUS_RFKILL, &trans_pcie->status))
+ if (test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+ IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
+ cmd->id);
return -ERFKILL;
+ }
if (cmd->flags & CMD_ASYNC)
return iwl_pcie_send_hcmd_async(trans, cmd);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7490c4fc7177..0064d38276bf 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -964,6 +964,12 @@ static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
newtype, vif->addr);
hwsim_check_magic(vif);
+ /*
+ * interface may change from non-AP to AP in
+ * which case this needs to be set up again
+ */
+ vif->cab_queue = 0;
+
return 0;
}
@@ -1389,7 +1395,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
return 0;
}
-static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
+static void mac80211_hwsim_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
/* Not implemented, queues only on kernel side */
}
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c
index cf43b3c29250..966a78f8e21a 100644
--- a/drivers/net/wireless/mwifiex/11ac.c
+++ b/drivers/net/wireless/mwifiex/11ac.c
@@ -259,3 +259,44 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
return ret_len;
}
+
+int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
+ struct mwifiex_11ac_vht_cfg *cfg)
+{
+ struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_11AC_CFG);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) +
+ S_DS_GEN);
+ vhtcfg->action = cpu_to_le16(cmd_action);
+ vhtcfg->band_config = cfg->band_config;
+ vhtcfg->misc_config = cfg->misc_config;
+ vhtcfg->cap_info = cpu_to_le32(cfg->cap_info);
+ vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set);
+ vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set);
+
+ return 0;
+}
+
+/* This function initializes the BlockACK setup information for given
+ * mwifiex_private structure for 11ac enabled networks.
+ */
+void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv)
+{
+ priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE;
+ } else {
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
+ }
+
+ return;
+}
diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h
index 80fd1ba46200..7c2c69b5b3eb 100644
--- a/drivers/net/wireless/mwifiex/11ac.h
+++ b/drivers/net/wireless/mwifiex/11ac.h
@@ -20,7 +20,24 @@
#ifndef _MWIFIEX_11AC_H_
#define _MWIFIEX_11AC_H_
+#define VHT_CFG_2GHZ BIT(0)
+#define VHT_CFG_5GHZ BIT(1)
+
+enum vht_cfg_misc_config {
+ VHT_CAP_TX_OPERATION = 1,
+ VHT_CAP_ASSOCIATION,
+ VHT_CAP_UAP_ONLY
+};
+
+#define DEFAULT_VHT_MCS_SET 0xfffa
+#define DISABLE_VHT_MCS_SET 0xffff
+
+#define VHT_BW_80_160_80P80 BIT(2)
+
int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc,
u8 **buffer);
+int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
+ struct mwifiex_11ac_vht_cfg *cfg);
#endif /* _MWIFIEX_11AC_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 45f19716687e..41e9d25a2d8e 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -679,3 +679,25 @@ void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra)
return;
}
+
+/* This function initializes the BlockACK setup information for given
+ * mwifiex_private structure.
+ */
+void mwifiex_set_ba_params(struct mwifiex_private *priv)
+{
+ priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
+ } else {
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
+ }
+
+ return;
+}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 78c2bb8d3726..47012947a447 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1374,6 +1374,18 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
}
mwifiex_set_ht_params(priv, bss_cfg, params);
+
+ if (priv->adapter->is_hw_11ac_capable) {
+ mwifiex_set_vht_params(priv, bss_cfg, params);
+ mwifiex_set_vht_width(priv, params->chandef.width,
+ priv->ap_11ac_enabled);
+ }
+
+ if (priv->ap_11ac_enabled)
+ mwifiex_set_11ac_ba_params(priv);
+ else
+ mwifiex_set_ba_params(priv);
+
mwifiex_set_wmm_params(priv, bss_cfg, params);
if (params->inactivity_timeout > 0) {
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 9a1302bd4c03..da469c336aa1 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -153,7 +153,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
" or cmd size is 0, not sending\n");
if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_recycle_cmd_node(adapter, cmd_node);
return -1;
}
@@ -167,7 +167,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
"DNLD_CMD: FW in reset state, ignore cmd %#x\n",
cmd_code);
mwifiex_complete_cmd(adapter, cmd_node);
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_recycle_cmd_node(adapter, cmd_node);
return -1;
}
@@ -228,7 +228,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
adapter->cmd_sent = false;
if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
@@ -632,6 +632,20 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
}
+/* This function reuses a command node. */
+void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node)
+{
+ struct host_cmd_ds_command *host_cmd = (void *)cmd_node->cmd_skb->data;
+
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+
+ atomic_dec(&adapter->cmd_pending);
+ dev_dbg(adapter->dev, "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
+ le16_to_cpu(host_cmd->command),
+ atomic_read(&adapter->cmd_pending));
+}
+
/*
* This function queues a command to the command pending queue.
*
@@ -673,7 +687,9 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
list_add(&cmd_node->list, &adapter->cmd_pending_q);
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
- dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command);
+ atomic_inc(&adapter->cmd_pending);
+ dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
+ command, atomic_read(&adapter->cmd_pending));
}
/*
@@ -783,7 +799,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
le16_to_cpu(resp->command));
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -833,7 +849,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -865,8 +881,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = ret;
- /* Clean up and put current command back to cmd_free_q */
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
@@ -993,7 +1008,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
mwifiex_complete_cmd(adapter, cmd_node);
cmd_node->wait_q_enabled = false;
}
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_recycle_cmd_node(adapter, cmd_node);
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
}
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
@@ -1040,7 +1055,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
cmd_node = adapter->curr_cmd;
cmd_node->wait_q_enabled = false;
cmd_node->cmd_flag |= CMD_F_CANCELED;
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_recycle_cmd_node(adapter, cmd_node);
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index e8a569aaa2e8..94cc09d48444 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -41,8 +41,15 @@
#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2
#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16
-#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32
-#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16
+#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 16
+#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 32
+#define MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE 32
+#define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16
+#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 32
+#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 48
+#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 48
+#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 32
+
#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
#define MWIFIEX_RATE_BITMAP_MCS0 32
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 57c5defe1f9d..1f7578d553ec 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -295,6 +295,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
#define HostCmd_CMD_MGMT_FRAME_REG 0x010c
#define HostCmd_CMD_REMAIN_ON_CHAN 0x010d
+#define HostCmd_CMD_11AC_CFG 0x0112
#define PROTOCOL_NO_SECURITY 0x01
#define PROTOCOL_STATIC_WEP 0x02
@@ -1363,6 +1364,15 @@ struct host_cmd_ds_sys_config {
u8 tlv[0];
};
+struct host_cmd_11ac_vht_cfg {
+ __le16 action;
+ u8 band_config;
+ u8 misc_config;
+ __le32 cap_info;
+ __le32 mcs_tx_set;
+ __le32 mcs_rx_set;
+} __packed;
+
struct host_cmd_tlv_akmp {
struct host_cmd_tlv tlv;
__le16 key_mgmt;
@@ -1620,6 +1630,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_802_11_eeprom_access eeprom;
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
struct host_cmd_ds_sys_config uap_sys_config;
+ struct host_cmd_11ac_vht_cfg vht_cfg;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index daf8801cecd2..42d7f0adf9bd 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -533,10 +533,8 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
if (!adapter->priv[i])
continue;
priv = adapter->priv[i];
- for (j = 0; j < MAX_NUM_TID; ++j) {
+ for (j = 0; j < MAX_NUM_TID; ++j)
INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list);
- spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock);
- }
INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
INIT_LIST_HEAD(&priv->sta_list);
@@ -713,7 +711,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd) {
dev_warn(adapter->dev, "curr_cmd is still in processing\n");
del_timer(&adapter->cmd_timer);
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
adapter->curr_cmd = NULL;
}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 91d522c746ed..7f27e45680b5 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -272,6 +272,14 @@ struct mwifiex_ds_pm_cfg {
} param;
};
+struct mwifiex_11ac_vht_cfg {
+ u8 band_config;
+ u8 misc_config;
+ u32 cap_info;
+ u32 mcs_tx_set;
+ u32 mcs_rx_set;
+};
+
struct mwifiex_ds_11n_tx_cfg {
u16 tx_htcap;
u16 tx_htinfo;
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 2fe0ceba4400..6bcb66e6e97c 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -1295,6 +1295,14 @@ int mwifiex_associate(struct mwifiex_private *priv,
(bss_desc->bss_mode != NL80211_IFTYPE_STATION))
return -1;
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
+ !bss_desc->disable_11n && !bss_desc->disable_11ac &&
+ (priv->adapter->config_bands & BAND_GAC ||
+ priv->adapter->config_bands & BAND_AAC))
+ mwifiex_set_11ac_ba_params(priv);
+ else
+ mwifiex_set_ba_params(priv);
+
memcpy(&current_bssid,
&priv->curr_bss_params.bss_descriptor.mac_address,
sizeof(current_bssid));
@@ -1323,6 +1331,13 @@ mwifiex_adhoc_start(struct mwifiex_private *priv,
dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n",
priv->curr_bss_params.band);
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
+ (priv->adapter->config_bands & BAND_GAC ||
+ priv->adapter->config_bands & BAND_AAC))
+ mwifiex_set_11ac_ba_params(priv);
+ else
+ mwifiex_set_ba_params(priv);
+
return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START,
HostCmd_ACT_GEN_SET, 0, adhoc_ssid);
}
@@ -1356,6 +1371,14 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
return -1;
}
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
+ !bss_desc->disable_11n && !bss_desc->disable_11ac &&
+ (priv->adapter->config_bands & BAND_GAC ||
+ priv->adapter->config_bands & BAND_AAC))
+ mwifiex_set_11ac_ba_params(priv);
+ else
+ mwifiex_set_ba_params(priv);
+
dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
priv->curr_bss_params.bss_descriptor.channel);
dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 7255289a48ac..b7484efc9443 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -213,15 +213,12 @@ struct mwifiex_ra_list_tbl {
struct mwifiex_tid_tbl {
struct list_head ra_list;
- /* spin lock for tid table */
- spinlock_t tid_tbl_lock;
struct mwifiex_ra_list_tbl *ra_list_curr;
};
#define WMM_HIGHEST_PRIORITY 7
#define HIGH_PRIO_TID 7
#define LOW_PRIO_TID 0
-#define NO_PKT_PRIO_TID (-1)
struct mwifiex_wmm_desc {
struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
@@ -798,6 +795,8 @@ void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node);
+void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node);
void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node,
@@ -912,12 +911,20 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
void mwifiex_set_ht_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_vht_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params);
void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_vht_width(struct mwifiex_private *priv,
+ enum nl80211_chan_width width,
+ bool ap_11ac_disable);
void
mwifiex_set_wmm_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_ba_params(struct mwifiex_private *priv);
+void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv);
/*
* This function checks if the queuing is RA based or not.
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 8cd8cdc91a7e..856959b64bc7 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -287,18 +287,13 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
}
/*
- * This function wakes up the card.
- *
- * A host power up command is written to the card configuration
- * register to wake up the card.
+ * This function adds delay loop to ensure FW is awake before proceeding.
*/
-static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+static void mwifiex_pcie_dev_wakeup_delay(struct mwifiex_adapter *adapter)
{
int i = 0;
- struct pcie_service_card *card = adapter->card;
- const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- while (reg->sleep_cookie && mwifiex_pcie_ok_to_access_hw(adapter)) {
+ while (mwifiex_pcie_ok_to_access_hw(adapter)) {
i++;
usleep_range(10, 20);
/* 50ms max wait */
@@ -306,16 +301,32 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
break;
}
+ return;
+}
+
+/* This function wakes up the card by reading fw_status register. */
+static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+{
+ u32 fw_status;
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
dev_dbg(adapter->dev, "event: Wakeup device...\n");
- /* Enable interrupts or any chip access will wakeup device */
- if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, HOST_INTR_MASK)) {
- dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ if (reg->sleep_cookie)
+ mwifiex_pcie_dev_wakeup_delay(adapter);
+
+ /* Reading fw_status register will wakeup device */
+ if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status)) {
+ dev_warn(adapter->dev, "Reading fw_status register failed\n");
return -1;
}
- dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
- adapter->ps_state = PS_STATE_AWAKE;
+ if (reg->sleep_cookie) {
+ mwifiex_pcie_dev_wakeup_delay(adapter);
+ dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
+ adapter->ps_state = PS_STATE_AWAKE;
+ }
return 0;
}
@@ -1984,12 +1995,13 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
}
}
} else if (!adapter->pps_uapsd_mode &&
- adapter->ps_state == PS_STATE_SLEEP) {
+ adapter->ps_state == PS_STATE_SLEEP &&
+ mwifiex_pcie_ok_to_access_hw(adapter)) {
/* Potentially for PCIe we could get other
* interrupts like shared. Don't change power
* state until cookie is set */
- if (mwifiex_pcie_ok_to_access_hw(adapter))
- adapter->ps_state = PS_STATE_AWAKE;
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_fw_try = false;
}
}
}
@@ -2112,7 +2124,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
}
dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
adapter->cmd_sent, adapter->data_sent);
- mwifiex_pcie_enable_host_int(adapter);
+ if (adapter->ps_state != PS_STATE_SLEEP)
+ mwifiex_pcie_enable_host_int(adapter);
return 0;
}
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index d215b4d3c51b..e7f6deaf715e 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1393,8 +1393,10 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
queue_work(adapter->workqueue, &adapter->main_work);
/* Perform internal scan synchronously */
- if (!priv->scan_request)
+ if (!priv->scan_request) {
+ dev_dbg(adapter->dev, "wait internal scan\n");
mwifiex_wait_queue_complete(adapter, cmd_node);
+ }
} else {
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
@@ -1793,7 +1795,12 @@ check_next_scan:
/* Need to indicate IOCTL complete */
if (adapter->curr_cmd->wait_q_enabled) {
adapter->cmd_wait_q.status = 0;
- mwifiex_complete_cmd(adapter, adapter->curr_cmd);
+ if (!priv->scan_request) {
+ dev_dbg(adapter->dev,
+ "complete internal scan\n");
+ mwifiex_complete_cmd(adapter,
+ adapter->curr_cmd);
+ }
}
if (priv->report_scan_result)
priv->report_scan_result = false;
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index a2ae690a0a67..b193e25977d2 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -24,6 +24,7 @@
#include "main.h"
#include "wmm.h"
#include "11n.h"
+#include "11ac.h"
/*
* This function prepares command to set/get RSSI information.
@@ -1258,6 +1259,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) +
S_DS_GEN);
break;
+ case HostCmd_CMD_11AC_CFG:
+ ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf);
+ break;
case HostCmd_CMD_P2P_MODE_CFG:
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 80b9f2238001..9f990e14966e 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -95,7 +95,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
break;
}
/* Handling errors here */
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
@@ -907,6 +907,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_REMAIN_ON_CHAN:
ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf);
break;
+ case HostCmd_CMD_11AC_CFG:
+ break;
case HostCmd_CMD_P2P_MODE_CFG:
ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf);
break;
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 8c943b6ebf45..e6c9b2ae22ed 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -59,9 +59,6 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
{
int status;
- dev_dbg(adapter->dev, "cmd pending\n");
- atomic_inc(&adapter->cmd_pending);
-
/* Wait for completion */
status = wait_event_interruptible(adapter->cmd_wait_q.wait,
*(cmd_queued->condition));
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 6e76a15a8950..b04b1db29100 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -18,6 +18,7 @@
*/
#include "main.h"
+#include "11ac.h"
/* This function parses security related parameters from cfg80211_ap_settings
* and sets into FW understandable bss_config structure.
@@ -177,6 +178,60 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
return;
}
+/* This function updates 11ac related parameters from IE
+ * and sets them into bss_config structure.
+ */
+void mwifiex_set_vht_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params)
+{
+ const u8 *vht_ie;
+
+ vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail,
+ params->beacon.tail_len);
+ if (vht_ie) {
+ memcpy(&bss_cfg->vht_cap, vht_ie + 2,
+ sizeof(struct ieee80211_vht_cap));
+ priv->ap_11ac_enabled = 1;
+ } else {
+ priv->ap_11ac_enabled = 0;
+ }
+
+ return;
+}
+
+/* Enable VHT only when cfg80211_ap_settings has VHT IE.
+ * Otherwise disable VHT.
+ */
+void mwifiex_set_vht_width(struct mwifiex_private *priv,
+ enum nl80211_chan_width width,
+ bool ap_11ac_enable)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_11ac_vht_cfg vht_cfg;
+
+ vht_cfg.band_config = VHT_CFG_5GHZ;
+ vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap;
+
+ if (!ap_11ac_enable) {
+ vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET;
+ vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET;
+ } else {
+ vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET;
+ vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET;
+ }
+
+ vht_cfg.misc_config = VHT_CAP_UAP_ONLY;
+
+ if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
+ vht_cfg.misc_config |= VHT_BW_80_160_80P80;
+
+ mwifiex_send_cmd_sync(priv, HostCmd_CMD_11AC_CFG,
+ HostCmd_ACT_GEN_SET, 0, &vht_cfg);
+
+ return;
+}
+
/* This function finds supported rates IE from beacon parameter and sets
* these rates into bss_config structure.
*/
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 54667e65ca47..e57ac0dd3ab5 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -239,7 +239,6 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node)
{
- atomic_dec(&adapter->cmd_pending);
dev_dbg(adapter->dev, "cmd completed: status=%d\n",
adapter->cmd_wait_q.status);
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 32adc878041d..2cc81ba590e3 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -436,10 +436,7 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
= priv->aggr_prio_tbl[7].ampdu_user
= BA_STREAM_NOT_ALLOWED;
- priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
- priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
- priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
-
+ mwifiex_set_ba_params(priv);
mwifiex_reset_11n_rx_seq_num(priv);
atomic_set(&priv->wmm.tx_pkts_queued, 0);
@@ -688,13 +685,13 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
ra_list->total_pkts_size += skb->len;
ra_list->pkt_count++;
- atomic_inc(&priv->wmm.tx_pkts_queued);
-
if (atomic_read(&priv->wmm.highest_queued_prio) <
tos_to_tid_inv[tid_down])
atomic_set(&priv->wmm.highest_queued_prio,
tos_to_tid_inv[tid_down]);
+ atomic_inc(&priv->wmm.tx_pkts_queued);
+
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
}
@@ -890,19 +887,15 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head;
struct mwifiex_tid_tbl *tid_ptr;
atomic_t *hqp;
- int is_list_empty;
- unsigned long flags;
+ unsigned long flags_bss, flags_ra;
int i, j;
for (j = adapter->priv_num - 1; j >= 0; --j) {
spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock,
- flags);
- is_list_empty = list_empty(&adapter->bss_prio_tbl[j]
- .bss_prio_head);
- spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
- flags);
- if (is_list_empty)
- continue;
+ flags_bss);
+
+ if (list_empty(&adapter->bss_prio_tbl[j].bss_prio_head))
+ goto skip_prio_tbl;
if (adapter->bss_prio_tbl[j].bss_prio_cur ==
(struct mwifiex_bss_prio_node *)
@@ -919,26 +912,26 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
do {
priv_tmp = bssprio_node->priv;
- hqp = &priv_tmp->wmm.highest_queued_prio;
+ if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0)
+ goto skip_bss;
+
+ /* iterate over the WMM queues of the BSS */
+ hqp = &priv_tmp->wmm.highest_queued_prio;
for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
+ spin_lock_irqsave(&priv_tmp->wmm.
+ ra_list_spinlock, flags_ra);
+
tid_ptr = &(priv_tmp)->wmm.
tid_tbl_ptr[tos_to_tid[i]];
/* For non-STA ra_list_curr may be NULL */
if (!tid_ptr->ra_list_curr)
- continue;
-
- spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
- flags);
- is_list_empty =
- list_empty(&adapter->bss_prio_tbl[j]
- .bss_prio_head);
- spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock,
- flags);
- if (is_list_empty)
- continue;
+ goto skip_wmm_queue;
+
+ if (list_empty(&tid_ptr->ra_list))
+ goto skip_wmm_queue;
/*
* Always choose the next ra we transmitted
@@ -960,10 +953,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
}
do {
- is_list_empty =
- skb_queue_empty(&ptr->skb_head);
-
- if (!is_list_empty)
+ if (!skb_queue_empty(&ptr->skb_head))
+ /* holds both locks */
goto found;
/* Get next ra */
@@ -978,14 +969,14 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
struct mwifiex_ra_list_tbl,
list);
} while (ptr != head);
- }
- /* No packet at any TID for this priv. Mark as such
- * to skip checking TIDs for this priv (until pkt is
- * added).
- */
- atomic_set(hqp, NO_PKT_PRIO_TID);
+skip_wmm_queue:
+ spin_unlock_irqrestore(&priv_tmp->wmm.
+ ra_list_spinlock,
+ flags_ra);
+ }
+skip_bss:
/* Get next bss priority node */
bssprio_node = list_first_entry(&bssprio_node->list,
struct mwifiex_bss_prio_node,
@@ -1000,14 +991,21 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
struct mwifiex_bss_prio_node,
list);
} while (bssprio_node != bssprio_head);
+
+skip_prio_tbl:
+ spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
+ flags_bss);
}
+
return NULL;
found:
- spin_lock_irqsave(&priv_tmp->wmm.ra_list_spinlock, flags);
+ /* holds bss_prio_lock / ra_list_spinlock */
if (atomic_read(hqp) > i)
atomic_set(hqp, i);
- spin_unlock_irqrestore(&priv_tmp->wmm.ra_list_spinlock, flags);
+ spin_unlock_irqrestore(&priv_tmp->wmm.ra_list_spinlock, flags_ra);
+ spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
+ flags_bss);
*priv = priv_tmp;
*tid = tos_to_tid[i];
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 0640e7d7f0c2..956c1084ebf1 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -4807,16 +4807,14 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
struct mwl8k_priv *priv = hw->priv;
int rc;
- if (conf->flags & IEEE80211_CONF_IDLE) {
- mwl8k_cmd_radio_disable(hw);
- return 0;
- }
-
rc = mwl8k_fw_lock(hw);
if (rc)
return rc;
- rc = mwl8k_cmd_radio_enable(hw);
+ if (conf->flags & IEEE80211_CONF_IDLE)
+ rc = mwl8k_cmd_radio_disable(hw);
+ else
+ rc = mwl8k_cmd_radio_enable(hw);
if (rc)
goto out;
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index aadda99989c0..ee654a691f38 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -670,7 +670,7 @@ static unsigned int p54_flush_count(struct p54_common *priv)
return total;
}
-static void p54_flush(struct ieee80211_hw *dev, bool drop)
+static void p54_flush(struct ieee80211_hw *dev, u32 queues, bool drop)
{
struct p54_common *priv = dev->priv;
unsigned int total, i;
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index ffe61d53e3fe..9b915d3a44be 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -20,6 +20,7 @@ if RT2X00
config RT2400PCI
tristate "Ralink rt2400 (PCI/PCMCIA) support"
depends on PCI
+ select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI
select EEPROM_93CX6
---help---
@@ -31,6 +32,7 @@ config RT2400PCI
config RT2500PCI
tristate "Ralink rt2500 (PCI/PCMCIA) support"
depends on PCI
+ select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI
select EEPROM_93CX6
---help---
@@ -43,6 +45,7 @@ config RT61PCI
tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
depends on PCI
select RT2X00_LIB_PCI
+ select RT2X00_LIB_MMIO
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_ITU_T
@@ -57,6 +60,7 @@ config RT2800PCI
tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support"
depends on PCI || SOC_RT288X || SOC_RT305X
select RT2800_LIB
+ select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI if PCI
select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X
select RT2X00_LIB_FIRMWARE
@@ -192,6 +196,9 @@ endif
config RT2800_LIB
tristate
+config RT2X00_LIB_MMIO
+ tristate
+
config RT2X00_LIB_PCI
tristate
select RT2X00_LIB
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 349d5b8284a4..f069d8bc5b67 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -9,6 +9,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
+obj-$(CONFIG_RT2X00_LIB_MMIO) += rt2x00mmio.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 221beaaa83f1..dcfb54e0c516 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -34,6 +34,7 @@
#include <linux/slab.h>
#include "rt2x00.h"
+#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt2400pci.h"
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 39edc59e8d03..e1d2dc9ed28a 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -34,6 +34,7 @@
#include <linux/slab.h>
#include "rt2x00.h"
+#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt2500pci.h"
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index f08a0424fe4d..7deac4d2459f 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -5431,9 +5431,9 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
{
- u32 reg;
u16 value;
u16 eeprom;
+ u16 rf;
/*
* Read EEPROM word for configuration.
@@ -5445,42 +5445,14 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
* RT28xx/RT30xx: defined in "EEPROM_NIC_CONF0_RF_TYPE" field
* RT53xx: defined in "EEPROM_CHIP_ID" field
*/
- if (rt2x00_rt(rt2x00dev, RT3290))
- rt2800_register_read(rt2x00dev, MAC_CSR0_3290, &reg);
- else
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-
- if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT3290 ||
- rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 ||
- rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392)
- rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &value);
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
else
- value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
+ rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
- rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
- value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
-
- switch (rt2x00dev->chip.rt) {
- case RT2860:
- case RT2872:
- case RT2883:
- case RT3070:
- case RT3071:
- case RT3090:
- case RT3290:
- case RT3352:
- case RT3390:
- case RT3572:
- case RT5390:
- case RT5392:
- case RT5592:
- break;
- default:
- ERROR(rt2x00dev, "Invalid RT chipset 0x%04x detected.\n", rt2x00dev->chip.rt);
- return -ENODEV;
- }
-
- switch (rt2x00dev->chip.rf) {
+ switch (rf) {
case RF2820:
case RF2850:
case RF2720:
@@ -5501,11 +5473,12 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
case RF5592:
break;
default:
- ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
- rt2x00dev->chip.rf);
+ ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n", rf);
return -ENODEV;
}
+ rt2x00_set_rf(rt2x00dev, rf);
+
/*
* Identify default antenna configuration.
*/
@@ -6059,11 +6032,56 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
return 0;
}
+static int rt2800_probe_rt(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u32 rt;
+ u32 rev;
+
+ if (rt2x00_rt(rt2x00dev, RT3290))
+ rt2800_register_read(rt2x00dev, MAC_CSR0_3290, &reg);
+ else
+ rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+
+ rt = rt2x00_get_field32(reg, MAC_CSR0_CHIPSET);
+ rev = rt2x00_get_field32(reg, MAC_CSR0_REVISION);
+
+ switch (rt) {
+ case RT2860:
+ case RT2872:
+ case RT2883:
+ case RT3070:
+ case RT3071:
+ case RT3090:
+ case RT3290:
+ case RT3352:
+ case RT3390:
+ case RT3572:
+ case RT5390:
+ case RT5392:
+ case RT5592:
+ break;
+ default:
+ ERROR(rt2x00dev,
+ "Invalid RT chipset 0x%04x, rev %04x detected.\n",
+ rt, rev);
+ return -ENODEV;
+ }
+
+ rt2x00_set_rt(rt2x00dev, rt, rev);
+
+ return 0;
+}
+
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
u32 reg;
+ retval = rt2800_probe_rt(rt2x00dev);
+ if (retval)
+ return retval;
+
/*
* Allocate eeprom data.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index f732ded8f1ba..565a80d0e564 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -41,6 +41,7 @@
#include <linux/eeprom_93cx6.h>
#include "rt2x00.h"
+#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt2x00soc.h"
#include "rt2800lib.h"
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 51922cc179de..0d02d16ca166 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1106,6 +1106,23 @@ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
}
+static inline void rt2x00_set_rt(struct rt2x00_dev *rt2x00dev,
+ const u16 rt, const u16 rev)
+{
+ rt2x00dev->chip.rt = rt;
+ rt2x00dev->chip.rev = rev;
+
+ INFO(rt2x00dev, "RT chipset %04x, rev %04x detected\n",
+ rt2x00dev->chip.rt, rt2x00dev->chip.rev);
+}
+
+static inline void rt2x00_set_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
+{
+ rt2x00dev->chip.rf = rf;
+
+ INFO(rt2x00dev, "RF chipset %04x detected\n", rt2x00dev->chip.rf);
+}
+
static inline bool rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
{
return (rt2x00dev->chip.rt == rt);
@@ -1366,7 +1383,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
-void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);
+void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 20c6eccce5aa..9161c02d8ff9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -748,7 +748,7 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
-void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
+void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.c b/drivers/net/wireless/rt2x00/rt2x00mmio.c
new file mode 100644
index 000000000000..d84a680ba0c9
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00mmio.c
@@ -0,0 +1,216 @@
+/*
+ Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00mmio
+ Abstract: rt2x00 generic mmio device routines.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "rt2x00.h"
+#include "rt2x00mmio.h"
+
+/*
+ * Register access.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const struct rt2x00_field32 field,
+ u32 *reg)
+{
+ unsigned int i;
+
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, offset, reg);
+ if (!rt2x00_get_field32(*reg, field))
+ return 1;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ printk_once(KERN_ERR "%s() Indirect register access failed: "
+ "offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg);
+ *reg = ~0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
+
+bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue = rt2x00dev->rx;
+ struct queue_entry *entry;
+ struct queue_entry_priv_pci *entry_priv;
+ struct skb_frame_desc *skbdesc;
+ int max_rx = 16;
+
+ while (--max_rx) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ entry_priv = entry->priv_data;
+
+ if (rt2x00dev->ops->lib->get_entry_state(entry))
+ break;
+
+ /*
+ * Fill in desc fields of the skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(entry->skb);
+ skbdesc->desc = entry_priv->desc;
+ skbdesc->desc_len = entry->queue->desc_size;
+
+ /*
+ * DMA is already done, notify rt2x00lib that
+ * it finished successfully.
+ */
+ rt2x00lib_dmastart(entry);
+ rt2x00lib_dmadone(entry);
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry, GFP_ATOMIC);
+ }
+
+ return !max_rx;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
+
+void rt2x00pci_flush_queue(struct data_queue *queue, bool drop)
+{
+ unsigned int i;
+
+ for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
+ msleep(10);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue);
+
+/*
+ * Device initialization handlers.
+ */
+static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_queue *queue)
+{
+ struct queue_entry_priv_pci *entry_priv;
+ void *addr;
+ dma_addr_t dma;
+ unsigned int i;
+
+ /*
+ * Allocate DMA memory for descriptor and buffer.
+ */
+ addr = dma_alloc_coherent(rt2x00dev->dev,
+ queue->limit * queue->desc_size,
+ &dma, GFP_KERNEL);
+ if (!addr)
+ return -ENOMEM;
+
+ memset(addr, 0, queue->limit * queue->desc_size);
+
+ /*
+ * Initialize all queue entries to contain valid addresses.
+ */
+ for (i = 0; i < queue->limit; i++) {
+ entry_priv = queue->entries[i].priv_data;
+ entry_priv->desc = addr + i * queue->desc_size;
+ entry_priv->desc_dma = dma + i * queue->desc_size;
+ }
+
+ return 0;
+}
+
+static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_queue *queue)
+{
+ struct queue_entry_priv_pci *entry_priv =
+ queue->entries[0].priv_data;
+
+ if (entry_priv->desc)
+ dma_free_coherent(rt2x00dev->dev,
+ queue->limit * queue->desc_size,
+ entry_priv->desc, entry_priv->desc_dma);
+ entry_priv->desc = NULL;
+}
+
+int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ int status;
+
+ /*
+ * Allocate DMA
+ */
+ queue_for_each(rt2x00dev, queue) {
+ status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue);
+ if (status)
+ goto exit;
+ }
+
+ /*
+ * Register interrupt handler.
+ */
+ status = request_irq(rt2x00dev->irq,
+ rt2x00dev->ops->lib->irq_handler,
+ IRQF_SHARED, rt2x00dev->name, rt2x00dev);
+ if (status) {
+ ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
+ rt2x00dev->irq, status);
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ queue_for_each(rt2x00dev, queue)
+ rt2x00pci_free_queue_dma(rt2x00dev, queue);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
+
+void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ /*
+ * Free irq line.
+ */
+ free_irq(rt2x00dev->irq, rt2x00dev);
+
+ /*
+ * Free DMA
+ */
+ queue_for_each(rt2x00dev, queue)
+ rt2x00pci_free_queue_dma(rt2x00dev, queue);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
+
+/*
+ * rt2x00mmio module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 mmio library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.h b/drivers/net/wireless/rt2x00/rt2x00mmio.h
new file mode 100644
index 000000000000..4ecaf60175bf
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00mmio.h
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00mmio
+ Abstract: Data structures for the rt2x00mmio module.
+ */
+
+#ifndef RT2X00MMIO_H
+#define RT2X00MMIO_H
+
+#include <linux/io.h>
+
+/*
+ * Register access.
+ */
+static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 *value)
+{
+ *value = readl(rt2x00dev->csr.base + offset);
+}
+
+static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
+}
+
+static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 value)
+{
+ writel(value, rt2x00dev->csr.base + offset);
+}
+
+static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const void *value,
+ const u32 length)
+{
+ __iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
+}
+
+/**
+ * rt2x00pci_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const struct rt2x00_field32 field,
+ u32 *reg);
+
+/**
+ * struct queue_entry_priv_pci: Per entry PCI specific information
+ *
+ * @desc: Pointer to device descriptor
+ * @desc_dma: DMA pointer to &desc.
+ * @data: Pointer to device's entry memory.
+ * @data_dma: DMA pointer to &data.
+ */
+struct queue_entry_priv_pci {
+ __le32 *desc;
+ dma_addr_t desc_dma;
+};
+
+/**
+ * rt2x00pci_rxdone - Handle RX done events
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ *
+ * Returns true if there are still rx frames pending and false if all
+ * pending rx frames were processed.
+ */
+bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00pci_flush_queue - Flush data queue
+ * @queue: Data queue to stop
+ * @drop: True to drop all pending frames.
+ *
+ * This will wait for a maximum of 100ms, waiting for the queues
+ * to become empty.
+ */
+void rt2x00pci_flush_queue(struct data_queue *queue, bool drop);
+
+/*
+ * Device initialization handlers.
+ */
+int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+#endif /* RT2X00MMIO_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index c4009eaeb697..e87865e33113 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -33,180 +33,6 @@
#include "rt2x00pci.h"
/*
- * Register access.
- */
-int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- const struct rt2x00_field32 field,
- u32 *reg)
-{
- unsigned int i;
-
- if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
- return 0;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, offset, reg);
- if (!rt2x00_get_field32(*reg, field))
- return 1;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- printk_once(KERN_ERR "%s() Indirect register access failed: "
- "offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg);
- *reg = ~0;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
-
-bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue = rt2x00dev->rx;
- struct queue_entry *entry;
- struct queue_entry_priv_pci *entry_priv;
- struct skb_frame_desc *skbdesc;
- int max_rx = 16;
-
- while (--max_rx) {
- entry = rt2x00queue_get_entry(queue, Q_INDEX);
- entry_priv = entry->priv_data;
-
- if (rt2x00dev->ops->lib->get_entry_state(entry))
- break;
-
- /*
- * Fill in desc fields of the skb descriptor
- */
- skbdesc = get_skb_frame_desc(entry->skb);
- skbdesc->desc = entry_priv->desc;
- skbdesc->desc_len = entry->queue->desc_size;
-
- /*
- * DMA is already done, notify rt2x00lib that
- * it finished successfully.
- */
- rt2x00lib_dmastart(entry);
- rt2x00lib_dmadone(entry);
-
- /*
- * Send the frame to rt2x00lib for further processing.
- */
- rt2x00lib_rxdone(entry, GFP_ATOMIC);
- }
-
- return !max_rx;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
-
-void rt2x00pci_flush_queue(struct data_queue *queue, bool drop)
-{
- unsigned int i;
-
- for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
- msleep(10);
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue);
-
-/*
- * Device initialization handlers.
- */
-static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue)
-{
- struct queue_entry_priv_pci *entry_priv;
- void *addr;
- dma_addr_t dma;
- unsigned int i;
-
- /*
- * Allocate DMA memory for descriptor and buffer.
- */
- addr = dma_alloc_coherent(rt2x00dev->dev,
- queue->limit * queue->desc_size,
- &dma, GFP_KERNEL | __GFP_ZERO);
- if (!addr)
- return -ENOMEM;
-
- /*
- * Initialize all queue entries to contain valid addresses.
- */
- for (i = 0; i < queue->limit; i++) {
- entry_priv = queue->entries[i].priv_data;
- entry_priv->desc = addr + i * queue->desc_size;
- entry_priv->desc_dma = dma + i * queue->desc_size;
- }
-
- return 0;
-}
-
-static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue)
-{
- struct queue_entry_priv_pci *entry_priv =
- queue->entries[0].priv_data;
-
- if (entry_priv->desc)
- dma_free_coherent(rt2x00dev->dev,
- queue->limit * queue->desc_size,
- entry_priv->desc, entry_priv->desc_dma);
- entry_priv->desc = NULL;
-}
-
-int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
- int status;
-
- /*
- * Allocate DMA
- */
- queue_for_each(rt2x00dev, queue) {
- status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue);
- if (status)
- goto exit;
- }
-
- /*
- * Register interrupt handler.
- */
- status = request_irq(rt2x00dev->irq,
- rt2x00dev->ops->lib->irq_handler,
- IRQF_SHARED, rt2x00dev->name, rt2x00dev);
- if (status) {
- ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
- rt2x00dev->irq, status);
- goto exit;
- }
-
- return 0;
-
-exit:
- queue_for_each(rt2x00dev, queue)
- rt2x00pci_free_queue_dma(rt2x00dev, queue);
-
- return status;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
-
-void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
-
- /*
- * Free irq line.
- */
- free_irq(rt2x00dev->irq, rt2x00dev);
-
- /*
- * Free DMA
- */
- queue_for_each(rt2x00dev, queue)
- rt2x00pci_free_queue_dma(rt2x00dev, queue);
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
-
-/*
* PCI driver handlers.
*/
static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index e2c99f2b9a14..60d90b20f8b9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -36,94 +36,6 @@
#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops)
/*
- * Register access.
- */
-static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- u32 *value)
-{
- *value = readl(rt2x00dev->csr.base + offset);
-}
-
-static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- void *value, const u32 length)
-{
- memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
-}
-
-static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- u32 value)
-{
- writel(value, rt2x00dev->csr.base + offset);
-}
-
-static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- const void *value,
- const u32 length)
-{
- __iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
-}
-
-/**
- * rt2x00pci_regbusy_read - Read from register with busy check
- * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
- * @offset: Register offset
- * @field: Field to check if register is busy
- * @reg: Pointer to where register contents should be stored
- *
- * This function will read the given register, and checks if the
- * register is busy. If it is, it will sleep for a couple of
- * microseconds before reading the register again. If the register
- * is not read after a certain timeout, this function will return
- * FALSE.
- */
-int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- const struct rt2x00_field32 field,
- u32 *reg);
-
-/**
- * struct queue_entry_priv_pci: Per entry PCI specific information
- *
- * @desc: Pointer to device descriptor
- * @desc_dma: DMA pointer to &desc.
- * @data: Pointer to device's entry memory.
- * @data_dma: DMA pointer to &data.
- */
-struct queue_entry_priv_pci {
- __le32 *desc;
- dma_addr_t desc_dma;
-};
-
-/**
- * rt2x00pci_rxdone - Handle RX done events
- * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
- *
- * Returns true if there are still rx frames pending and false if all
- * pending rx frames were processed.
- */
-bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
-
-/**
- * rt2x00pci_flush_queue - Flush data queue
- * @queue: Data queue to stop
- * @drop: True to drop all pending frames.
- *
- * This will wait for a maximum of 100ms, waiting for the queues
- * to become empty.
- */
-void rt2x00pci_flush_queue(struct data_queue *queue, bool drop);
-
-/*
- * Device initialization handlers.
- */
-int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
-void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
-
-/*
* PCI driver handlers.
*/
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index f95792cfcf89..9e3c8ff53e3f 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -35,6 +35,7 @@
#include <linux/eeprom_93cx6.h>
#include "rt2x00.h"
+#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt61pci.h"
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index b6aa0c40658f..7253de3d8c66 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -55,6 +55,15 @@ config RTL8723AE
If you choose to build it as a module, it will be called rtl8723ae
+config RTL8188EE
+ tristate "Realtek RTL8188EE Wireless Network Adapter"
+ depends on RTLWIFI && PCI
+ ---help---
+ This is the driver for Realtek RTL8188EE 802.11n PCIe
+ wireless network adapters.
+
+ If you choose to build it as a module, it will be called rtl8188ee
+
config RTL8192CU
tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
depends on RTLWIFI && USB
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile
index 3b1cbac741e3..ff02b874f8d8 100644
--- a/drivers/net/wireless/rtlwifi/Makefile
+++ b/drivers/net/wireless/rtlwifi/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_RTL8192CU) += rtl8192cu/
obj-$(CONFIG_RTL8192SE) += rtl8192se/
obj-$(CONFIG_RTL8192DE) += rtl8192de/
obj-$(CONFIG_RTL8723AE) += rtl8723ae/
+obj-$(CONFIG_RTL8188EE) += rtl8188ee/
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 99c5cea3fe21..cac1fa912e8c 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -54,7 +54,8 @@
*5) frame process functions
*6) IOT functions
*7) sysfs functions
- *8) ...
+ *8) vif functions
+ *9) ...
*/
/*********************************************************
@@ -198,34 +199,46 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
- /*
- *hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+ /*hw->wiphy->bands[IEEE80211_BAND_2GHZ]
*base on ant_num
*rx_mask: RX mask
- *if rx_ant =1 rx_mask[0]=0xff;==>MCS0-MCS7
- *if rx_ant =2 rx_mask[1]=0xff;==>MCS8-MCS15
- *if rx_ant >=3 rx_mask[2]=0xff;
- *if BW_40 rx_mask[4]=0x01;
+ *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7
+ *if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15
+ *if rx_ant >= 3 rx_mask[2]= 0xff;
+ *if BW_40 rx_mask[4]= 0x01;
*highest supported RX rate
*/
- if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_2T2R) {
+ if (rtlpriv->dm.supp_phymode_switch) {
- RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T2R or 2T2R\n");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ "Support phy mode switch\n");
ht_cap->mcs.rx_mask[0] = 0xFF;
ht_cap->mcs.rx_mask[1] = 0xFF;
ht_cap->mcs.rx_mask[4] = 0x01;
ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
- } else if (get_rf_type(rtlphy) == RF_1T1R) {
-
- RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T1R\n");
-
- ht_cap->mcs.rx_mask[0] = 0xFF;
- ht_cap->mcs.rx_mask[1] = 0x00;
- ht_cap->mcs.rx_mask[4] = 0x01;
-
- ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
+ } else {
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_2T2R) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "1T2R or 2T2R\n");
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0xFF;
+ ht_cap->mcs.rx_mask[4] = 0x01;
+
+ ht_cap->mcs.rx_highest =
+ cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
+ } else if (get_rf_type(rtlphy) == RF_1T1R) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T1R\n");
+
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0x00;
+ ht_cap->mcs.rx_mask[4] = 0x01;
+
+ ht_cap->mcs.rx_highest =
+ cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
+ }
}
}
@@ -311,6 +324,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_CONNECTION_MONITOR |
/* IEEE80211_HW_SUPPORTS_CQM_RSSI | */
+ IEEE80211_HW_CONNECTION_MONITOR |
+ IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
/* swlps or hwlps has been set in diff chip in init_sw_vars */
@@ -323,8 +338,12 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO);
+ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->rts_threshold = 2347;
hw->queues = AC_MAX;
@@ -354,9 +373,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
/* <1> timer */
- init_timer(&rtlpriv->works.watchdog_timer);
setup_timer(&rtlpriv->works.watchdog_timer,
rtl_watch_dog_timer_callback, (unsigned long)hw);
+ setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer,
+ rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw);
/* <2> work queue */
rtlpriv->works.hw = hw;
@@ -369,6 +389,8 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
(void *)rtl_swlps_wq_callback);
INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq,
(void *)rtl_swlps_rfon_wq_callback);
+ INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq,
+ (void *)rtl_fwevt_wq_callback);
}
@@ -382,6 +404,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
cancel_delayed_work(&rtlpriv->works.ps_work);
cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
+ cancel_delayed_work(&rtlpriv->works.fwevt_wq);
}
void rtl_init_rfkill(struct ieee80211_hw *hw)
@@ -436,12 +459,6 @@ int rtl_init_core(struct ieee80211_hw *hw)
if (rtl_regd_init(hw, rtl_reg_notifier)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "REGD init failed\n");
return 1;
- } else {
- /* CRDA regd hint must after init CRDA */
- if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- "regulatory_hint fail\n");
- }
}
/* <4> locks */
@@ -449,15 +466,25 @@ int rtl_init_core(struct ieee80211_hw *hw)
mutex_init(&rtlpriv->locks.ps_mutex);
spin_lock_init(&rtlpriv->locks.ips_lock);
spin_lock_init(&rtlpriv->locks.irq_th_lock);
+ spin_lock_init(&rtlpriv->locks.irq_pci_lock);
+ spin_lock_init(&rtlpriv->locks.tx_lock);
spin_lock_init(&rtlpriv->locks.h2c_lock);
spin_lock_init(&rtlpriv->locks.rf_ps_lock);
spin_lock_init(&rtlpriv->locks.rf_lock);
spin_lock_init(&rtlpriv->locks.waitq_lock);
+ spin_lock_init(&rtlpriv->locks.entry_list_lock);
+ spin_lock_init(&rtlpriv->locks.fw_ps_lock);
spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
+ spin_lock_init(&rtlpriv->locks.check_sendpkt_lock);
+ spin_lock_init(&rtlpriv->locks.fw_ps_lock);
+ spin_lock_init(&rtlpriv->locks.lps_lock);
+
+ /* <5> init list */
+ INIT_LIST_HEAD(&rtlpriv->entry_list);
rtlmac->link_state = MAC80211_NOLINK;
- /* <5> init deferred work */
+ /* <6> init deferred work */
_rtl_init_deferred_work(hw);
return 0;
@@ -523,7 +550,8 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw,
if (mac->opmode == NL80211_IFTYPE_STATION)
bw_40 = mac->bw_40;
else if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC)
+ mac->opmode == NL80211_IFTYPE_ADHOC ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
if (bw_40 && sgi_40)
@@ -578,23 +606,26 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
if (mac->opmode == NL80211_IFTYPE_STATION) {
tcb_desc->ratr_index = 0;
- } else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ } else if (mac->opmode == NL80211_IFTYPE_ADHOC ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
if (tcb_desc->multicast || tcb_desc->broadcast) {
tcb_desc->hw_rate =
rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
tcb_desc->use_driver_rate = 1;
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
} else {
- /* TODO */
+ tcb_desc->ratr_index = ratr_index;
}
- tcb_desc->ratr_index = ratr_index;
} else if (mac->opmode == NL80211_IFTYPE_AP) {
tcb_desc->ratr_index = ratr_index;
}
}
if (rtlpriv->dm.useramask) {
- /* TODO we will differentiate adhoc and station futrue */
- if (mac->opmode == NL80211_IFTYPE_STATION) {
+ tcb_desc->ratr_index = ratr_index;
+ /* TODO we will differentiate adhoc and station future */
+ if (mac->opmode == NL80211_IFTYPE_STATION ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
tcb_desc->mac_id = 0;
if (mac->mode == WIRELESS_MODE_N_24G)
@@ -608,7 +639,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
else if (mac->mode & WIRELESS_MODE_A)
tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
} else if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC) {
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
if (NULL != sta) {
if (sta->aid > 0)
tcb_desc->mac_id = sta->aid + 1;
@@ -619,7 +650,6 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
}
}
}
-
}
static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
@@ -633,7 +663,8 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
if (!sta)
return;
if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC) {
+ mac->opmode == NL80211_IFTYPE_ADHOC ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
return;
} else if (mac->opmode == NL80211_IFTYPE_STATION) {
@@ -834,8 +865,8 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
if (rtlpriv->dm.supp_phymode_switch &&
mac->link_state < MAC80211_LINKED &&
(ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) {
- if (rtlpriv->cfg->ops->check_switch_to_dmdp)
- rtlpriv->cfg->ops->check_switch_to_dmdp(hw);
+ if (rtlpriv->cfg->ops->chk_switch_dmdp)
+ rtlpriv->cfg->ops->chk_switch_dmdp(hw);
}
if (ieee80211_is_auth(fc)) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
@@ -924,6 +955,56 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(rtl_get_tcb_desc);
+static bool addbareq_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_sta *sta = NULL;
+ struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+ struct rtl_sta_info *sta_entry = NULL;
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ u16 capab = 0, tid = 0;
+ struct rtl_tid_data *tid_data;
+ struct sk_buff *skb_delba = NULL;
+ struct ieee80211_rx_status rx_status = { 0 };
+
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, hdr->addr3);
+ if (sta == NULL) {
+ RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_EMERG,
+ "sta is NULL\n");
+ rcu_read_unlock();
+ return true;
+ }
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ if (!sta_entry) {
+ rcu_read_unlock();
+ return true;
+ }
+ capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+ tid_data = &sta_entry->tids[tid];
+ if (tid_data->agg.rx_agg_state == RTL_RX_AGG_START) {
+ skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid);
+ if (skb_delba) {
+ rx_status.freq = hw->conf.channel->center_freq;
+ rx_status.band = hw->conf.channel->band;
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+ rx_status.flag |= RX_FLAG_MACTIME_END;
+ rx_status.rate_idx = 0;
+ rx_status.signal = 50 + 10;
+ memcpy(IEEE80211_SKB_RXCB(skb_delba), &rx_status,
+ sizeof(rx_status));
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG,
+ "fake del\n", skb_delba->data,
+ skb_delba->len);
+ ieee80211_rx_irqsafe(hw, skb_delba);
+ }
+ }
+ rcu_read_unlock();
+ return false;
+}
+
bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
{
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -948,6 +1029,11 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
"%s ACT_ADDBAREQ From :%pM\n",
is_tx ? "Tx" : "Rx", hdr->addr2);
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n",
+ skb->data, skb->len);
+ if (!is_tx)
+ if (addbareq_rx(hw, skb))
+ return true;
break;
case ACT_ADDBARSP:
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
@@ -1003,8 +1089,9 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
is_tx ? "Tx" : "Rx");
if (is_tx) {
+ rtlpriv->enter_ps = false;
schedule_work(&rtlpriv->
- works.lps_leave_work);
+ works.lps_change_work);
ppsc->last_delaylps_stamp_jiffies =
jiffies;
}
@@ -1014,7 +1101,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
}
} else if (ETH_P_ARP == ether_type) {
if (is_tx) {
- schedule_work(&rtlpriv->works.lps_leave_work);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}
@@ -1024,7 +1112,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
"802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
if (is_tx) {
- schedule_work(&rtlpriv->works.lps_leave_work);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}
@@ -1101,6 +1190,58 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw,
return 0;
}
+int rtl_rx_agg_start(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_tid_data *tid_data;
+ struct rtl_sta_info *sta_entry = NULL;
+
+ if (sta == NULL)
+ return -EINVAL;
+
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ if (!sta_entry)
+ return -ENXIO;
+ tid_data = &sta_entry->tids[tid];
+
+ RT_TRACE(rtlpriv, COMP_RECV, DBG_DMESG,
+ "on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
+ tid_data->seq_number);
+
+ tid_data->agg.rx_agg_state = RTL_RX_AGG_START;
+ return 0;
+}
+
+int rtl_rx_agg_stop(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_sta_info *sta_entry = NULL;
+
+ if (sta == NULL)
+ return -EINVAL;
+
+ if (!sta->addr) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n");
+ return -EINVAL;
+ }
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+ "on ra = %pM tid = %d\n", sta->addr, tid);
+
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ sta_entry->tids[tid].agg.rx_agg_state = RTL_RX_AGG_STOP;
+
+ return 0;
+}
+
int rtl_tx_agg_oper(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid)
{
@@ -1132,6 +1273,34 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw,
* wq & timer callback functions
*
*********************************************************/
+/* this function is used for roaming */
+void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
+ return;
+
+ if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
+ return;
+
+ /* check if this really is a beacon */
+ if (!ieee80211_is_beacon(hdr->frame_control) &&
+ !ieee80211_is_probe_resp(hdr->frame_control))
+ return;
+
+ /* min. beacon length + FCS_LEN */
+ if (skb->len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
+ return;
+
+ rtlpriv->link_info.bcn_rx_inperiod++;
+}
+
void rtl_watchdog_wq_callback(void *data)
{
struct rtl_works *rtlworks = container_of_dwork_rtl(data,
@@ -1142,6 +1311,8 @@ void rtl_watchdog_wq_callback(void *data)
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
bool busytraffic = false;
+ bool tx_busy_traffic = false;
+ bool rx_busy_traffic = false;
bool higher_busytraffic = false;
bool higher_busyrxtraffic = false;
u8 idx, tid;
@@ -1151,7 +1322,6 @@ void rtl_watchdog_wq_callback(void *data)
u32 aver_tx_cnt_inperiod = 0;
u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
- bool enter_ps = false;
if (is_hal_stop(rtlhal))
return;
@@ -1191,8 +1361,13 @@ void rtl_watchdog_wq_callback(void *data)
aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4;
/* (2) check traffic busy */
- if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100)
+ if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100) {
busytraffic = true;
+ if (aver_rx_cnt_inperiod > aver_tx_cnt_inperiod)
+ rx_busy_traffic = true;
+ else
+ tx_busy_traffic = false;
+ }
/* Higher Tx/Rx data. */
if (aver_rx_cnt_inperiod > 4000 ||
@@ -1228,15 +1403,12 @@ void rtl_watchdog_wq_callback(void *data)
if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) ||
(rtlpriv->link_info.num_rx_inperiod > 2))
- enter_ps = false;
+ rtlpriv->enter_ps = true;
else
- enter_ps = true;
+ rtlpriv->enter_ps = false;
/* LeisurePS only work in infra mode. */
- if (enter_ps)
- rtl_lps_enter(hw);
- else
- rtl_lps_leave(hw);
+ schedule_work(&rtlpriv->works.lps_change_work);
}
rtlpriv->link_info.num_rx_inperiod = 0;
@@ -1246,10 +1418,37 @@ void rtl_watchdog_wq_callback(void *data)
rtlpriv->link_info.busytraffic = busytraffic;
rtlpriv->link_info.higher_busytraffic = higher_busytraffic;
+ rtlpriv->link_info.rx_busy_traffic = rx_busy_traffic;
+ rtlpriv->link_info.tx_busy_traffic = tx_busy_traffic;
rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;
/* <3> DM */
rtlpriv->cfg->ops->dm_watchdog(hw);
+
+ /* <4> roaming */
+ if (mac->link_state == MAC80211_LINKED &&
+ mac->opmode == NL80211_IFTYPE_STATION) {
+ if ((rtlpriv->link_info.bcn_rx_inperiod +
+ rtlpriv->link_info.num_rx_inperiod) == 0) {
+ rtlpriv->link_info.roam_times++;
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
+ "AP off for %d s\n",
+ (rtlpriv->link_info.roam_times * 2));
+
+ /* if we can't recv beacon for 6s, we should
+ * reconnect this AP
+ */
+ if (rtlpriv->link_info.roam_times >= 3) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "AP off, try to reconnect now\n");
+ rtlpriv->link_info.roam_times = 0;
+ ieee80211_connection_loss(rtlpriv->mac80211.vif);
+ }
+ } else {
+ rtlpriv->link_info.roam_times = 0;
+ }
+ }
+ rtlpriv->link_info.bcn_rx_inperiod = 0;
}
void rtl_watch_dog_timer_callback(unsigned long data)
@@ -1264,6 +1463,28 @@ void rtl_watch_dog_timer_callback(unsigned long data)
jiffies + MSECS(RTL_WATCH_DOG_TIME));
}
+void rtl_fwevt_wq_callback(void *data)
+{
+ struct rtl_works *rtlworks =
+ container_of_dwork_rtl(data, struct rtl_works, fwevt_wq);
+ struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->cfg->ops->c2h_command_handle(hw);
+}
+
+void rtl_easy_concurrent_retrytimer_callback(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_priv *buddy_priv = rtlpriv->buddy_priv;
+
+ if (buddy_priv == NULL)
+ return;
+
+ rtlpriv->cfg->ops->dualmac_easy_concurrent(hw);
+}
+
/*********************************************************
*
* frame process functions
@@ -1334,14 +1555,16 @@ static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
}
int rtl_send_smps_action(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta, u8 *da, u8 *bssid,
+ struct ieee80211_sta *sta,
enum ieee80211_smps_mode smps)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
- struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid);
+ struct sk_buff *skb = NULL;
struct rtl_tcb_desc tcb_desc;
+ u8 bssid[ETH_ALEN] = {0};
+
memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
if (rtlpriv->mac80211.act_scanning)
@@ -1356,21 +1579,67 @@ int rtl_send_smps_action(struct ieee80211_hw *hw,
if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
goto err_free;
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP)
+ memcpy(bssid, rtlpriv->efuse.dev_addr, ETH_ALEN);
+ else
+ memcpy(bssid, rtlpriv->mac80211.bssid, ETH_ALEN);
+
+ skb = rtl_make_smps_action(hw, smps, sta->addr, bssid);
/* this is a type = mgmt * stype = action frame */
if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl_sta_info *sta_entry =
(struct rtl_sta_info *) sta->drv_priv;
sta_entry->mimo_ps = smps;
- rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
info->control.rates[0].idx = 0;
info->band = hw->conf.channel->band;
rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc);
}
+ return 1;
+
err_free:
return 0;
}
+EXPORT_SYMBOL(rtl_send_smps_action);
+
+/* There seem to be issues in mac80211 regarding when del ba frames can be
+ * received. As a work around, we make a fake del_ba if we receive a ba_req;
+ * however, rx_agg was opened to let mac80211 release some ba related
+ * resources. This del_ba is for tx only.
+ */
+struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
+ u8 *sa, u8 *bssid, u16 tid)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *action_frame;
+ u16 params;
+
+ /* 27 = header + category + action + smps mode */
+ skb = dev_alloc_skb(34 + hw->extra_tx_headroom);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, hw->extra_tx_headroom);
+ action_frame = (void *)skb_put(skb, 34);
+ memset(action_frame, 0, 34);
+ memcpy(action_frame->sa, sa, ETH_ALEN);
+ memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN);
+ memcpy(action_frame->bssid, bssid, ETH_ALEN);
+ action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+ action_frame->u.action.category = WLAN_CATEGORY_BACK;
+ action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
+ params = (u16)(1 << 11); /* bit 11 initiator */
+ params |= (u16)(tid << 12); /* bit 15:12 TID number */
+
+ action_frame->u.action.u.delba.params = cpu_to_le16(params);
+ action_frame->u.action.u.delba.reason_code =
+ cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
+
+ return skb;
+}
/*********************************************************
*
@@ -1587,11 +1856,17 @@ MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
+struct rtl_global_var global_var = {};
+
static int __init rtl_core_module_init(void)
{
if (rtl_rate_control_register())
pr_err("Unable to register rtl_rc, use default RC !!\n");
+ /* init some global vars */
+ INIT_LIST_HEAD(&global_var.glb_priv_list);
+ spin_lock_init(&global_var.glb_list_lock);
+
return 0;
}
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index 5a8c80e259f7..8576bc34b032 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -113,6 +113,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw);
void rtl_init_rfkill(struct ieee80211_hw *hw);
void rtl_deinit_rfkill(struct ieee80211_hw *hw);
+void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
void rtl_watch_dog_timer_callback(unsigned long data);
void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
@@ -126,7 +127,12 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
u16 tid);
int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
u16 tid);
+int rtl_rx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ u16 tid);
+int rtl_rx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ u16 tid);
void rtl_watchdog_wq_callback(void *data);
+void rtl_fwevt_wq_callback(void *data);
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
@@ -134,14 +140,18 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
int rtl_send_smps_action(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta, u8 *da, u8 *bssid,
- enum ieee80211_smps_mode smps);
+ struct ieee80211_sta *sta,
+ enum ieee80211_smps_mode smps);
u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie);
void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
u8 rtl_tid_to_ac(u8 tid);
extern struct attribute_group rtl_attribute_group;
+void rtl_easy_concurrent_retrytimer_callback(unsigned long data);
+extern struct rtl_global_var global_var;
int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
bool isht, u8 desc_rate, bool first_ampdu);
bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
+struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
+ u8 *sa, u8 *bssid, u16 tid);
#endif
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index d3ce9fbef00e..2201b5cee08f 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -104,9 +104,12 @@ static void rtl_op_stop(struct ieee80211_hw *hw)
if (is_hal_stop(rtlhal))
return;
+ /* here is must, because adhoc do stop and start,
+ * but stop with RFOFF may cause something wrong,
+ * like adhoc TP
+ */
if (unlikely(ppsc->rfpwr_state == ERFOFF)) {
rtl_ips_nic_on(hw);
- mdelay(1);
}
mutex_lock(&rtlpriv->locks.conf_mutex);
@@ -167,7 +170,11 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
rtl_ips_nic_on(hw);
mutex_lock(&rtlpriv->locks.conf_mutex);
- switch (vif->type) {
+
+ switch (ieee80211_vif_type_p2p(vif)) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ mac->p2p = P2P_ROLE_CLIENT;
+ /*fall through*/
case NL80211_IFTYPE_STATION:
if (mac->beacon_enabled == 1) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
@@ -192,6 +199,9 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
(u8 *) (&mac->basic_rates));
break;
+ case NL80211_IFTYPE_P2P_GO:
+ mac->p2p = P2P_ROLE_GO;
+ /*fall through*/
case NL80211_IFTYPE_AP:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"NL80211_IFTYPE_AP\n");
@@ -205,6 +215,19 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
(u8 *) (&mac->basic_rates));
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ "NL80211_IFTYPE_MESH_POINT\n");
+
+ mac->link_state = MAC80211_LINKED;
+ rtlpriv->cfg->ops->set_bcn_reg(hw);
+ if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+ mac->basic_rates = 0xfff;
+ else
+ mac->basic_rates = 0xff0;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+ (u8 *)(&mac->basic_rates));
+ break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"operation mode %d is not supported!\n", vif->type);
@@ -212,6 +235,13 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ if (mac->p2p) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ "p2p role %x\n", vif->type);
+ mac->basic_rates = 0xff0;/*disable cck rate for p2p*/
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+ (u8 *)(&mac->basic_rates));
+ }
mac->vif = vif;
mac->opmode = vif->type;
rtlpriv->cfg->ops->set_network_type(hw, vif->type);
@@ -232,9 +262,9 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&rtlpriv->locks.conf_mutex);
/* Free beacon resources */
- if ((mac->opmode == NL80211_IFTYPE_AP) ||
- (mac->opmode == NL80211_IFTYPE_ADHOC) ||
- (mac->opmode == NL80211_IFTYPE_MESH_POINT)) {
+ if ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_ADHOC) ||
+ (vif->type == NL80211_IFTYPE_MESH_POINT)) {
if (mac->beacon_enabled == 1) {
mac->beacon_enabled = 0;
rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
@@ -247,6 +277,7 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
*Note: We assume NL80211_IFTYPE_UNSPECIFIED as
*NO LINK for our hardware.
*/
+ mac->p2p = 0;
mac->vif = NULL;
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
@@ -256,6 +287,22 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&rtlpriv->locks.conf_mutex);
}
+static int rtl_op_change_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype new_type, bool p2p)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int ret;
+ rtl_op_remove_interface(hw, vif);
+
+ vif->type = new_type;
+ vif->p2p = p2p;
+ ret = rtl_op_add_interface(hw, vif);
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ "p2p %x\n", p2p);
+ return ret;
+}
+
static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -264,6 +311,9 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct ieee80211_conf *conf = &hw->conf;
+ if (mac->skip_scan)
+ return 1;
+
mutex_lock(&rtlpriv->locks.conf_mutex);
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /*BIT(2)*/
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
@@ -323,6 +373,16 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
struct ieee80211_channel *channel = hw->conf.channel;
u8 wide_chan = (u8) channel->hw_value;
+ if (mac->act_scanning)
+ mac->n_channels++;
+
+ if (rtlpriv->dm.supp_phymode_switch &&
+ mac->link_state < MAC80211_LINKED &&
+ !mac->act_scanning) {
+ if (rtlpriv->cfg->ops->chk_switch_dmdp)
+ rtlpriv->cfg->ops->chk_switch_dmdp(hw);
+ }
+
/*
*because we should back channel to
*current_network.chan in in scanning,
@@ -373,13 +433,13 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
if (wide_chan <= 0)
wide_chan = 1;
- /* In scanning, before we go offchannel we may send a ps=1 null
- * to AP, and then we may send a ps = 0 null to AP quickly, but
- * first null may have caused AP to put lots of packet to hw tx
- * buffer. These packets must be tx'd before we go off channel
- * so we must delay more time to let AP flush these packets
- * before going offchannel, or dis-association or delete BA will
- * happen by AP
+ /* In scanning, before we go offchannel we may send a ps = 1
+ * null to AP, and then we may send a ps = 0 null to AP quickly,
+ * but first null may have caused AP to put lots of packet to
+ * hw tx buffer. These packets must be tx'd before we go off
+ * channel so we must delay more time to let AP flush these
+ * packets before going offchannel, or dis-association or
+ * delete BA will be caused by AP
*/
if (rtlpriv->mac80211.offchan_delay) {
rtlpriv->mac80211.offchan_delay = false;
@@ -441,7 +501,8 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
* and nolink check bssid is set in set network_type */
if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
(mac->link_state >= MAC80211_LINKED)) {
- if (mac->opmode != NL80211_IFTYPE_AP) {
+ if (mac->opmode != NL80211_IFTYPE_AP &&
+ mac->opmode != NL80211_IFTYPE_MESH_POINT) {
if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
rtlpriv->cfg->ops->set_chk_bssid(hw, false);
} else {
@@ -481,32 +542,43 @@ static int rtl_op_sta_add(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_sta_info *sta_entry;
if (sta) {
sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_add_tail(&sta_entry->list, &rtlpriv->entry_list);
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
if (rtlhal->current_bandtype == BAND_ON_2_4G) {
sta_entry->wireless_mode = WIRELESS_MODE_G;
if (sta->supp_rates[0] <= 0xf)
sta_entry->wireless_mode = WIRELESS_MODE_B;
- if (sta->ht_cap.ht_supported)
+ if (sta->ht_cap.ht_supported == true)
sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+
+ if (vif->type == NL80211_IFTYPE_ADHOC)
+ sta_entry->wireless_mode = WIRELESS_MODE_G;
} else if (rtlhal->current_bandtype == BAND_ON_5G) {
sta_entry->wireless_mode = WIRELESS_MODE_A;
- if (sta->ht_cap.ht_supported)
+ if (sta->ht_cap.ht_supported == true)
sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
- }
- /* I found some times mac80211 give wrong supp_rates for adhoc*/
- if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
- sta_entry->wireless_mode = WIRELESS_MODE_G;
+ if (vif->type == NL80211_IFTYPE_ADHOC)
+ sta_entry->wireless_mode = WIRELESS_MODE_A;
+ }
+ /*disable cck rate for p2p*/
+ if (mac->p2p)
+ sta->supp_rates[0] &= 0xfffffff0;
+ memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"Add sta addr is %pM\n", sta->addr);
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
}
return 0;
}
+
static int rtl_op_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -519,9 +591,14 @@ static int rtl_op_sta_remove(struct ieee80211_hw *hw,
sta_entry = (struct rtl_sta_info *) sta->drv_priv;
sta_entry->wireless_mode = 0;
sta_entry->ratr_index = 0;
+
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_del(&sta_entry->list);
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
}
return 0;
}
+
static int _rtl_get_hal_qnum(u16 queue)
{
int qnum;
@@ -547,8 +624,8 @@ static int _rtl_get_hal_qnum(u16 queue)
}
/*
- *for mac80211 VO=0, VI=1, BE=2, BK=3
- *for rtl819x BE=0, BK=1, VI=2, VO=3
+ *for mac80211 VO = 0, VI = 1, BE = 2, BK = 3
+ *for rtl819x BE = 0, BK = 1, VI = 2, VO = 3
*/
static int rtl_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
@@ -630,6 +707,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
/*TODO: reference to enum ieee80211_bss_change */
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
+ struct ieee80211_sta *sta = NULL;
/* we should reset all sec info & cam
* before set cam after linked, we should not
* reset in disassoc, that will cause tkip->wep
@@ -647,23 +725,39 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
if (rtlpriv->cfg->ops->linked_set_reg)
rtlpriv->cfg->ops->linked_set_reg(hw);
- if (mac->opmode == NL80211_IFTYPE_STATION && sta)
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
+
+ if (vif->type == NL80211_IFTYPE_STATION && sta)
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
+ RT_TRACE(rtlpriv, COMP_EASY_CONCURRENT, DBG_LOUD,
+ "send PS STATIC frame\n");
+ if (rtlpriv->dm.supp_phymode_switch) {
+ if (sta->ht_cap.ht_supported)
+ rtl_send_smps_action(hw, sta,
+ IEEE80211_SMPS_STATIC);
+ }
+ rcu_read_unlock();
+
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"BSS_CHANGED_ASSOC\n");
} else {
- if (mac->link_state == MAC80211_LINKED)
- rtl_lps_leave(hw);
+ if (mac->link_state == MAC80211_LINKED) {
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
+ }
+ if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
+ rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
-
- /* reset sec info */
- rtl_cam_reset_sec_info(hw);
-
- rtl_cam_reset_all_entry(hw);
mac->vendor = PEER_UNKNOWN;
+ if (rtlpriv->dm.supp_phymode_switch) {
+ if (rtlpriv->cfg->ops->chk_switch_dmdp)
+ rtlpriv->cfg->ops->chk_switch_dmdp(hw);
+ }
+
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"BSS_CHANGED_UN_ASSOC\n");
}
@@ -778,7 +872,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_BASIC_RATES) {
- /* for 5G must << RATE_6M_INDEX=4,
+ /* for 5G must << RATE_6M_INDEX = 4,
* because 5G have no cck rate*/
if (rtlhal->current_bandtype == BAND_ON_5G)
basic_rates = sta->supp_rates[1] << 4;
@@ -815,6 +909,9 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
ppsc->report_linked = false;
}
}
+ if (rtlpriv->cfg->ops->bt_wifi_media_status_notify)
+ rtlpriv->cfg->ops->bt_wifi_media_status_notify(hw,
+ ppsc->report_linked);
}
out:
@@ -885,7 +982,6 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
return rtl_tx_agg_stop(hw, sta, tid);
- break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid);
@@ -894,11 +990,11 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_START:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_RX_START:TID:%d\n", tid);
- break;
+ return rtl_rx_agg_start(hw, sta, tid);
case IEEE80211_AMPDU_RX_STOP:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid);
- break;
+ return rtl_rx_agg_stop(hw, sta, tid);
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"IEEE80211_AMPDU_ERR!!!!:\n");
@@ -912,12 +1008,20 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- mac->act_scanning = true;
-
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n");
+ mac->act_scanning = true;
+ if (rtlpriv->link_info.higher_busytraffic) {
+ mac->skip_scan = true;
+ return;
+ }
+ if (rtlpriv->dm.supp_phymode_switch) {
+ if (rtlpriv->cfg->ops->chk_switch_dmdp)
+ rtlpriv->cfg->ops->chk_switch_dmdp(hw);
+ }
if (mac->link_state == MAC80211_LINKED) {
- rtl_lps_leave(hw);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
mac->link_state = MAC80211_LINKED_SCANNING;
} else {
rtl_ips_nic_on(hw);
@@ -937,6 +1041,16 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n");
mac->act_scanning = false;
+ mac->skip_scan = false;
+ if (rtlpriv->link_info.higher_busytraffic)
+ return;
+
+ /*p2p will use 1/6/11 to scan */
+ if (mac->n_channels == 3)
+ mac->p2p_in_use = true;
+ else
+ mac->p2p_in_use = false;
+ mac->n_channels = 0;
/* Dual mac */
rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
@@ -970,6 +1084,11 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
"not open hw encryption\n");
return -ENOSPC; /*User disabled HW-crypto */
}
+ /* To support IBSS, use sw-crypto for GTK */
+ if (((vif->type == NL80211_IFTYPE_ADHOC) ||
+ (vif->type == NL80211_IFTYPE_MESH_POINT)) &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ return -ENOSPC;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"%s hardware based encryption for keyidx: %d, mac: %pM\n",
cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
@@ -996,6 +1115,14 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = AESCCMP_ENCRYPTION;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CCMP\n");
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ /*HW doesn't support CMAC encryption, use software CMAC */
+ key_type = AESCMAC_ENCRYPTION;
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CMAC\n");
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "HW don't support CMAC encryption, use software CMAC\n");
+ err = -EOPNOTSUPP;
+ goto out_unlock;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "alg_err:%x!!!!\n",
key->cipher);
@@ -1017,13 +1144,14 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* 1) wep only: is just for wep enc, in this condition
* rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
* will be true & enable_hw_sec will be set when wep
- * ke setting.
+ * key setting.
* 2) wep(group) + AES(pairwise): some AP like cisco
* may use it, in this condition enable_hw_sec will not
* be set when wep key setting */
/* we must reset sec_info after lingked before set key,
* or some flag will be wrong*/
- if (mac->opmode == NL80211_IFTYPE_AP) {
+ if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_MESH_POINT) {
if (!group_key || key_type == WEP40_ENCRYPTION ||
key_type == WEP104_ENCRYPTION) {
if (group_key)
@@ -1098,12 +1226,16 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key->hw_key_idx = key_idx;
if (key_type == TKIP_ENCRYPTION)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ /*use software CCMP encryption for management frames (MFP) */
+ if (key_type == AESCCMP_ENCRYPTION)
+ key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
break;
case DISABLE_KEY:
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"disable key delete one entry\n");
/*set local buf about wep key. */
- if (mac->opmode == NL80211_IFTYPE_AP) {
+ if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_MESH_POINT) {
if (sta)
rtl_cam_del_entry(hw, sta->addr);
}
@@ -1163,10 +1295,10 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
}
/* this function is called by mac80211 to flush tx buffer
- * before switch channle or power save, or tx buffer packet
+ * before switch channel or power save, or tx buffer packet
* maybe send after offchannel or rf sleep, this may cause
* dis-association by AP */
-static void rtl_op_flush(struct ieee80211_hw *hw, bool drop)
+static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1180,6 +1312,7 @@ const struct ieee80211_ops rtl_ops = {
.tx = rtl_op_tx,
.add_interface = rtl_op_add_interface,
.remove_interface = rtl_op_remove_interface,
+ .change_interface = rtl_op_change_interface,
.config = rtl_op_config,
.configure_filter = rtl_op_configure_filter,
.sta_add = rtl_op_sta_add,
diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c
index bdda9b2fffe1..7d52d3d7769f 100644
--- a/drivers/net/wireless/rtlwifi/debug.c
+++ b/drivers/net/wireless/rtlwifi/debug.c
@@ -41,7 +41,10 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
COMP_BEACON | COMP_RATE | COMP_RXDESC | COMP_DIG | COMP_TXAGC |
COMP_POWER | COMP_POWER_TRACKING | COMP_BB_POWERSAVING | COMP_SWAS |
COMP_RF | COMP_TURBO | COMP_RATR | COMP_CMD |
- COMP_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN;
+ COMP_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN |
+ COMP_EASY_CONCURRENT | COMP_EFUSE | COMP_QOS | COMP_MAC80211 |
+ COMP_REGD | COMP_CHAN | COMP_BT_COEXIST;
+
for (i = 0; i < DBGP_TYPE_MAX; i++)
rtlpriv->dbg.dbgp_type[i] = 0;
diff --git a/drivers/net/wireless/rtlwifi/debug.h b/drivers/net/wireless/rtlwifi/debug.h
index fd3269f47685..6d669364e3d9 100644
--- a/drivers/net/wireless/rtlwifi/debug.h
+++ b/drivers/net/wireless/rtlwifi/debug.h
@@ -115,11 +115,11 @@
/* Define EEPROM and EFUSE check module bit*/
#define EEPROM_W BIT(0)
#define EFUSE_PG BIT(1)
-#define EFUSE_READ_ALL BIT(2)
+#define EFUSE_READ_ALL BIT(2)
/* Define init check for module bit*/
#define INIT_EEPROM BIT(0)
-#define INIT_TxPower BIT(1)
+#define INIT_TXPOWER BIT(1)
#define INIT_IQK BIT(2)
#define INIT_RF BIT(3)
@@ -135,6 +135,15 @@
#define PHY_TXPWR BIT(8)
#define PHY_PWRDIFF BIT(9)
+/* Define Dynamic Mechanism check module bit --> FDM */
+#define WA_IOT BIT(0)
+#define DM_PWDB BIT(1)
+#define DM_MONITOR BIT(2)
+#define DM_DIG BIT(3)
+#define DM_EDCA_TURBO BIT(4)
+
+#define DM_PWDB BIT(1)
+
enum dbgp_flag_e {
FQOS = 0,
FTX = 1,
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 8e2f9afb125a..9e3894178e77 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -35,8 +35,6 @@ static const u8 MAX_PGPKT_SIZE = 9;
static const u8 PGPKT_DATA_SIZE = 8;
static const int EFUSE_MAX_SIZE = 512;
-static const u8 EFUSE_OOB_PROTECT_BYTES = 15;
-
static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = {
{0, 0, 0, 2},
{0, 1, 0, 2},
@@ -240,6 +238,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
u8 rtemp8[1];
u16 efuse_addr = 0;
u8 offset, wren;
+ u8 u1temp = 0;
u16 i;
u16 j;
const u16 efuse_max_section =
@@ -285,10 +284,31 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
}
while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) {
- offset = ((*rtemp8 >> 4) & 0x0f);
+ /* Check PG header for section num. */
+ if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */
+ u1temp = ((*rtemp8 & 0xE0) >> 5);
+ read_efuse_byte(hw, efuse_addr, rtemp8);
- if (offset < efuse_max_section) {
+ if ((*rtemp8 & 0x0F) == 0x0F) {
+ efuse_addr++;
+ read_efuse_byte(hw, efuse_addr, rtemp8);
+
+ if (*rtemp8 != 0xFF &&
+ (efuse_addr < efuse_len)) {
+ efuse_addr++;
+ }
+ continue;
+ } else {
+ offset = ((*rtemp8 & 0xF0) >> 1) | u1temp;
+ wren = (*rtemp8 & 0x0F);
+ efuse_addr++;
+ }
+ } else {
+ offset = ((*rtemp8 >> 4) & 0x0f);
wren = (*rtemp8 & 0x0f);
+ }
+
+ if (offset < efuse_max_section) {
RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
"offset-%d Worden=%x\n", offset, wren);
@@ -391,7 +411,8 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
efuse_used = rtlefuse->efuse_usedbytes;
if ((totalbytes + efuse_used) >=
- (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))
+ (EFUSE_MAX_SIZE -
+ rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))
result = false;
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
@@ -932,8 +953,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
u8 badworden = 0x0F;
static int repeat_times;
- if (efuse_get_current_size(hw) >=
- (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) {
+ if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE -
+ rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
"efuse_pg_packet_write error\n");
return false;
@@ -949,8 +970,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n");
- while (continual && (efuse_addr <
- (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) {
+ while (continual && (efuse_addr < (EFUSE_MAX_SIZE -
+ rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) {
if (write_state == PG_STATE_HEADER) {
badworden = 0x0F;
@@ -1003,7 +1024,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
}
}
- if (efuse_addr >= (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) {
+ if (efuse_addr >= (EFUSE_MAX_SIZE -
+ rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
"efuse_addr(%#x) Out of size!!\n", efuse_addr);
}
@@ -1102,8 +1124,11 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
u8 tempval;
u16 tmpV16;
- if (pwrstate && (rtlhal->hw_type !=
- HARDWARE_TYPE_RTL8192SE)) {
+ if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) {
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE)
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS],
+ 0x69);
+
tmpV16 = rtl_read_word(rtlpriv,
rtlpriv->cfg->maps[SYS_ISO_CTRL]);
if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
@@ -1153,6 +1178,10 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
}
} else {
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE)
+ rtl_write_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_ACCESS], 0);
+
if (write) {
tempval = rtl_read_byte(rtlpriv,
rtlpriv->cfg->maps[EFUSE_TEST] +
diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h
index 2bdea9a8699e..395a326acfb4 100644
--- a/drivers/net/wireless/rtlwifi/efuse.h
+++ b/drivers/net/wireless/rtlwifi/efuse.h
@@ -32,7 +32,6 @@
#define EFUSE_IC_ID_OFFSET 506
-#define EFUSE_REAL_CONTENT_LEN 512
#define EFUSE_MAP_LEN 128
#define EFUSE_MAX_WORD_UNIT 4
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 4261e8ecc4c3..999ffc12578b 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -59,7 +59,7 @@ static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
if (unlikely(ieee80211_is_beacon(fc)))
return BEACON_QUEUE;
- if (ieee80211_is_mgmt(fc))
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
return MGNT_QUEUE;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
if (ieee80211_is_nullfunc(fc))
@@ -271,9 +271,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- u8 pcibridge_busnum = pcipriv->ndis_adapter.pcibridge_busnum;
- u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
- u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
u16 aspmlevel;
@@ -302,8 +299,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
u_pcibridge_aspmsetting);
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
- "PlatformEnableASPM():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n",
- pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum,
+ "PlatformEnableASPM(): Write reg[%x] = %x\n",
(pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
u_pcibridge_aspmsetting);
@@ -349,6 +345,49 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
return status;
}
+static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw,
+ struct rtl_priv **buddy_priv)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ bool find_buddy_priv = false;
+ struct rtl_priv *tpriv = NULL;
+ struct rtl_pci_priv *tpcipriv = NULL;
+
+ if (!list_empty(&rtlpriv->glb_var->glb_priv_list)) {
+ list_for_each_entry(tpriv, &rtlpriv->glb_var->glb_priv_list,
+ list) {
+ if (tpriv) {
+ tpcipriv = (struct rtl_pci_priv *)tpriv->priv;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "pcipriv->ndis_adapter.funcnumber %x\n",
+ pcipriv->ndis_adapter.funcnumber);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "tpcipriv->ndis_adapter.funcnumber %x\n",
+ tpcipriv->ndis_adapter.funcnumber);
+
+ if ((pcipriv->ndis_adapter.busnumber ==
+ tpcipriv->ndis_adapter.busnumber) &&
+ (pcipriv->ndis_adapter.devnumber ==
+ tpcipriv->ndis_adapter.devnumber) &&
+ (pcipriv->ndis_adapter.funcnumber !=
+ tpcipriv->ndis_adapter.funcnumber)) {
+ find_buddy_priv = true;
+ break;
+ }
+ }
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "find_buddy_priv %d\n", find_buddy_priv);
+
+ if (find_buddy_priv)
+ *buddy_priv = tpriv;
+
+ return find_buddy_priv;
+}
+
static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
{
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
@@ -420,17 +459,14 @@ static void _rtl_pci_io_handler_init(struct device *dev,
}
-static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
-{
-}
-
static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- u8 additionlen = FCS_LEN;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct sk_buff *next_skb;
+ u8 additionlen = FCS_LEN;
/* here open is 4, wep/tkip is 8, aes is 12*/
if (info->control.hw_key)
@@ -455,7 +491,7 @@ static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
next_skb))
break;
- if (tcb_desc->empkt_num >= 5)
+ if (tcb_desc->empkt_num >= rtlhal->max_earlymode_num)
break;
}
spin_unlock_bh(&rtlpriv->locks.waitq_lock);
@@ -471,11 +507,17 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct sk_buff *skb = NULL;
struct ieee80211_tx_info *info = NULL;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
int tid;
if (!rtlpriv->rtlhal.earlymode_enable)
return;
+ if (rtlpriv->dm.supp_phymode_switch &&
+ (rtlpriv->easy_concurrent_ctl.switch_in_process ||
+ (rtlpriv->buddy_priv &&
+ rtlpriv->buddy_priv->easy_concurrent_ctl.switch_in_process)))
+ return;
/* we juse use em for BE/BK/VI/VO */
for (tid = 7; tid >= 0; tid--) {
u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(tid)];
@@ -487,7 +529,8 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
spin_lock_bh(&rtlpriv->locks.waitq_lock);
if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
- (ring->entries - skb_queue_len(&ring->queue) > 5)) {
+ (ring->entries - skb_queue_len(&ring->queue) >
+ rtlhal->max_earlymode_num)) {
skb = skb_dequeue(&mac->skb_waitq[tid]);
} else {
spin_unlock_bh(&rtlpriv->locks.waitq_lock);
@@ -525,9 +568,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
HW_DESC_OWN);
- /*
- *beacon packet will only use the first
- *descriptor defautly,and the own may not
+ /*beacon packet will only use the first
+ *descriptor by defaut, and the own may not
*be cleared by the hardware
*/
if (own)
@@ -558,8 +600,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
}
/* for sw LPS, just after NULL skb send out, we can
- * sure AP kown we are sleeped, our we should not let
- * rf to sleep*/
+ * sure AP knows we are sleeping, we should not let
+ * rf sleep
+ */
fc = rtl_get_fc(skb);
if (ieee80211_is_nullfunc(fc)) {
if (ieee80211_has_pm(fc)) {
@@ -569,6 +612,15 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
rtlpriv->psc.state_inap = false;
}
}
+ if (ieee80211_is_action(fc)) {
+ struct ieee80211_mgmt *action_frame =
+ (struct ieee80211_mgmt *)skb->data;
+ if (action_frame->u.action.u.ht_smps.action ==
+ WLAN_HT_ACTION_SMPS) {
+ dev_kfree_skb(skb);
+ goto tx_status_ok;
+ }
+ }
/* update tid tx pkt num */
tid = rtl_get_tid(skb);
@@ -602,7 +654,8 @@ tx_status_ok:
if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) ||
(rtlpriv->link_info.num_rx_inperiod > 2)) {
- schedule_work(&rtlpriv->works.lps_leave_work);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
}
}
@@ -637,6 +690,10 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
rtlpriv->link_info.num_rx_inperiod++;
}
+ /* static bcn for roaming */
+ rtl_beacon_statistic(hw, skb);
+ rtl_p2p_info(hw, (void *)skb->data, skb->len);
+
/* for sw lps */
rtl_swlps_beacon(hw, (void *)skb->data, skb->len);
rtl_recognize_peer(hw, (void *)skb->data, skb->len);
@@ -727,9 +784,10 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
_rtl_receive_one(hw, skb, rx_status);
if (((rtlpriv->link_info.num_rx_inperiod +
- rtlpriv->link_info.num_tx_inperiod) > 8) ||
- (rtlpriv->link_info.num_rx_inperiod > 2)) {
- schedule_work(&rtlpriv->works.lps_leave_work);
+ rtlpriv->link_info.num_tx_inperiod) > 8) ||
+ (rtlpriv->link_info.num_rx_inperiod > 2)) {
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
}
dev_kfree_skb_any(skb);
@@ -803,7 +861,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "beacon interrupt!\n");
}
- if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) {
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_BCNINT]) {
RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
"prepare beacon for interrupt!\n");
tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet);
@@ -884,6 +942,16 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
_rtl_pci_rx_interrupt(hw);
}
+ /*fw related*/
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) {
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ "firmware interrupt!\n");
+ queue_delayed_work(rtlpriv->works.rtl_wq,
+ &rtlpriv->works.fwevt_wq, 0);
+ }
+ }
+
if (rtlpriv->rtlhal.earlymode_enable)
tasklet_schedule(&rtlpriv->works.irq_tasklet);
@@ -939,13 +1007,17 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
return;
}
-static void rtl_lps_leave_work_callback(struct work_struct *work)
+static void rtl_lps_change_work_callback(struct work_struct *work)
{
struct rtl_works *rtlworks =
- container_of(work, struct rtl_works, lps_leave_work);
+ container_of(work, struct rtl_works, lps_change_work);
struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
- rtl_lps_leave(hw);
+ if (rtlpriv->enter_ps)
+ rtl_lps_enter(hw);
+ else
+ rtl_lps_leave(hw);
}
static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
@@ -1009,7 +1081,8 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet,
(void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet,
(unsigned long)hw);
- INIT_WORK(&rtlpriv->works.lps_leave_work, rtl_lps_leave_work_callback);
+ INIT_WORK(&rtlpriv->works.lps_change_work,
+ rtl_lps_change_work_callback);
}
static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
@@ -1458,10 +1531,14 @@ static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u16 i = 0;
int queue_id;
struct rtl8192_tx_ring *ring;
+ if (mac->skip_scan)
+ return;
+
for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
u32 queue_len;
ring = &pcipriv->dev.tx_ring[queue_id];
@@ -1491,7 +1568,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw)
synchronize_irq(rtlpci->pdev->irq);
tasklet_kill(&rtlpriv->works.irq_tasklet);
- cancel_work_sync(&rtlpriv->works.lps_leave_work);
+ cancel_work_sync(&rtlpriv->works.lps_change_work);
flush_workqueue(rtlpriv->works.rtl_wq);
destroy_workqueue(rtlpriv->works.rtl_wq);
@@ -1566,7 +1643,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
set_hal_stop(rtlhal);
rtlpriv->cfg->ops->disable_interrupt(hw);
- cancel_work_sync(&rtlpriv->works.lps_leave_work);
+ cancel_work_sync(&rtlpriv->works.lps_change_work);
spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
while (ppsc->rfchange_inprogress) {
@@ -1673,6 +1750,10 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"8192D PCI-E is found - vid/did=%x/%x\n",
venderid, deviceid);
+ } else if (deviceid == RTL_PCI_8188EE_DID) {
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8188EE;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Find adapter, Hardware type is 8188EE\n");
} else {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Err: Unknown device - vid/did=%x/%x\n",
@@ -1704,6 +1785,9 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn);
+ /* some ARM have no bridge_pdev and will crash here
+ * so we should check if bridge_pdev is NULL
+ */
if (bridge_pdev) {
/*find bridge info if available */
pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
@@ -1758,6 +1842,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pcipriv->ndis_adapter.amd_l1_patch);
rtl_pci_parse_configuration(pdev, hw);
+ list_add_tail(&rtlpriv->list, &rtlpriv->glb_var->glb_priv_list);
return true;
}
@@ -1804,6 +1889,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, hw);
rtlpriv = hw->priv;
+ rtlpriv->hw = hw;
pcipriv = (void *)rtlpriv->priv;
pcipriv->dev.pdev = pdev;
init_completion(&rtlpriv->firmware_loading_complete);
@@ -1812,6 +1898,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
rtlpriv->rtlhal.interface = INTF_PCI;
rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
rtlpriv->intf_ops = &rtl_pci_ops;
+ rtlpriv->glb_var = &global_var;
/*
*init dbgp flags before all
@@ -1916,7 +2003,6 @@ int rtl_pci_probe(struct pci_dev *pdev,
fail3:
rtl_deinit_core(hw);
- _rtl_pci_io_handler_release(hw);
if (rtlpriv->io.pci_mem_start != 0)
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
@@ -1965,14 +2051,15 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
rtl_pci_deinit(hw);
rtl_deinit_core(hw);
- _rtl_pci_io_handler_release(hw);
rtlpriv->cfg->ops->deinit_sw_vars(hw);
if (rtlpci->irq_alloc) {
+ synchronize_irq(rtlpci->pdev->irq);
free_irq(rtlpci->pdev->irq, hw);
rtlpci->irq_alloc = 0;
}
+ list_del(&rtlpriv->list);
if (rtlpriv->io.pci_mem_start != 0) {
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
pci_release_regions(pdev);
@@ -2034,6 +2121,7 @@ struct rtl_intf_ops rtl_pci_ops = {
.read_efuse_byte = read_efuse_byte,
.adapter_start = rtl_pci_start,
.adapter_stop = rtl_pci_stop,
+ .check_buddy_priv = rtl_pci_check_buddy_priv,
.adapter_tx = rtl_pci_tx,
.flush = rtl_pci_flush,
.reset_trx_ring = rtl_pci_reset_trx_ring,
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index 65b08f50022e..d3262ec45d23 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -94,6 +94,7 @@
#define RTL_PCI_8192CU_DID 0x8191 /*8192ce */
#define RTL_PCI_8192DE_DID 0x8193 /*8192de */
#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/
+#define RTL_PCI_8188EE_DID 0x8179 /*8188ee*/
/*8192 support 16 pages of IO registers*/
#define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000
@@ -175,6 +176,7 @@ struct rtl_pci {
/*irq */
u8 irq_alloc;
u32 irq_mask[2];
+ u32 sys_irq_mask;
/*Bcn control register setting */
u32 reg_bcn_ctrl_val;
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 13ad33e85577..884bceae38a9 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -180,6 +180,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
return;
}
+ if (mac->p2p_in_use)
+ return;
+
if (mac->link_state > MAC80211_NOLINK)
return;
@@ -189,6 +192,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
if (rtlpriv->sec.being_setkey)
return;
+ if (rtlpriv->cfg->ops->bt_coex_off_before_lps)
+ rtlpriv->cfg->ops->bt_coex_off_before_lps(hw);
+
if (ppsc->inactiveps) {
rtstate = ppsc->rfpwr_state;
@@ -231,6 +237,9 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw)
&rtlpriv->works.ips_nic_off_wq, MSECS(100));
}
+/* NOTICE: any opmode should exc nic_on, or disable without
+ * nic_on may something wrong, like adhoc TP
+ */
void rtl_ips_nic_on(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -299,7 +308,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
- u8 rpwm_val, fw_pwrmode;
+ bool enter_fwlps;
if (mac->opmode == NL80211_IFTYPE_ADHOC)
return;
@@ -324,43 +333,31 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
*/
if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
- bool fw_current_inps;
if (ppsc->dot11_psmode == EACTIVE) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
"FW LPS leave ps_mode:%x\n",
FW_PS_ACTIVE_MODE);
-
- rpwm_val = 0x0C; /* RF on */
- fw_pwrmode = FW_PS_ACTIVE_MODE;
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
- &rpwm_val);
+ enter_fwlps = false;
+ ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
+ ppsc->smart_ps = 0;
rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_H2C_FW_PWRMODE,
- &fw_pwrmode);
- fw_current_inps = false;
-
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_FW_PSMODE_STATUS,
- (u8 *) (&fw_current_inps));
+ HW_VAR_FW_LPS_ACTION,
+ (u8 *)(&enter_fwlps));
+ if (ppsc->p2p_ps_info.opp_ps)
+ rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
} else {
if (rtl_get_fwlps_doze(hw)) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
"FW LPS enter ps_mode:%x\n",
ppsc->fwctrl_psmode);
-
- rpwm_val = 0x02; /* RF off */
- fw_current_inps = true;
+ enter_fwlps = true;
+ ppsc->pwr_mode = ppsc->fwctrl_psmode;
+ ppsc->smart_ps = 2;
rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_FW_PSMODE_STATUS,
- (u8 *) (&fw_current_inps));
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_H2C_FW_PWRMODE,
- &ppsc->fwctrl_psmode);
+ HW_VAR_FW_LPS_ACTION,
+ (u8 *)(&enter_fwlps));
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_SET_RPWM,
- &rpwm_val);
} else {
/* Reset the power save related parameters. */
ppsc->dot11_psmode = EACTIVE;
@@ -642,3 +639,286 @@ void rtl_swlps_wq_callback(void *data)
rtlpriv->psc.state = ps;
}
}
+
+static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
+ unsigned int len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+ u8 *pos, *end, *ie;
+ u16 noa_len;
+ static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
+ u8 noa_num, index, i, noa_index = 0;
+ bool find_p2p_ie = false , find_p2p_ps_ie = false;
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = data + len;
+ ie = NULL;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ return;
+
+ if (pos[0] == 221 && pos[1] > 4) {
+ if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
+ ie = pos + 2+4;
+ break;
+ }
+ }
+ pos += 2 + pos[1];
+ }
+
+ if (ie == NULL)
+ return;
+ find_p2p_ie = true;
+ /*to find noa ie*/
+ while (ie + 1 < end) {
+ noa_len = READEF2BYTE(&ie[1]);
+ if (ie + 3 + ie[1] > end)
+ return;
+
+ if (ie[0] == 12) {
+ find_p2p_ps_ie = true;
+ if ((noa_len - 2) % 13 != 0) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "P2P notice of absence: invalid length.%d\n",
+ noa_len);
+ return;
+ } else {
+ noa_num = (noa_len - 2) / 13;
+ }
+ noa_index = ie[3];
+ if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
+ P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "update NOA ie.\n");
+ p2pinfo->noa_index = noa_index;
+ p2pinfo->opp_ps = (ie[4] >> 7);
+ p2pinfo->ctwindow = ie[4] & 0x7F;
+ p2pinfo->noa_num = noa_num;
+ index = 5;
+ for (i = 0; i < noa_num; i++) {
+ p2pinfo->noa_count_type[i] =
+ READEF1BYTE(ie+index);
+ index += 1;
+ p2pinfo->noa_duration[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ p2pinfo->noa_interval[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ p2pinfo->noa_start_time[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ }
+
+ if (p2pinfo->opp_ps == 1) {
+ p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+ /* Driver should wait LPS entering
+ * CTWindow
+ */
+ if (rtlpriv->psc.fw_current_inpsmode)
+ rtl_p2p_ps_cmd(hw,
+ P2P_PS_ENABLE);
+ } else if (p2pinfo->noa_num > 0) {
+ p2pinfo->p2p_ps_mode = P2P_PS_NOA;
+ rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
+ } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+ rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+ }
+ }
+ break;
+ }
+ ie += 3 + noa_len;
+ }
+
+ if (find_p2p_ie == true) {
+ if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
+ (find_p2p_ps_ie == false))
+ rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+ }
+}
+
+static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
+ unsigned int len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+ u8 noa_num, index, i, noa_index = 0;
+ u8 *pos, *end, *ie;
+ u16 noa_len;
+ static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
+
+ pos = (u8 *)&mgmt->u.action.category;
+ end = data + len;
+ ie = NULL;
+
+ if (pos[0] == 0x7f) {
+ if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
+ ie = pos + 3+4;
+ }
+
+ if (ie == NULL)
+ return;
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n");
+ /*to find noa ie*/
+ while (ie + 1 < end) {
+ noa_len = READEF2BYTE(&ie[1]);
+ if (ie + 3 + ie[1] > end)
+ return;
+
+ if (ie[0] == 12) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n");
+ RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
+ ie, noa_len);
+ if ((noa_len - 2) % 13 != 0) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "P2P notice of absence: invalid length.%d\n",
+ noa_len);
+ return;
+ } else {
+ noa_num = (noa_len - 2) / 13;
+ }
+ noa_index = ie[3];
+ if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
+ P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
+ p2pinfo->noa_index = noa_index;
+ p2pinfo->opp_ps = (ie[4] >> 7);
+ p2pinfo->ctwindow = ie[4] & 0x7F;
+ p2pinfo->noa_num = noa_num;
+ index = 5;
+ for (i = 0; i < noa_num; i++) {
+ p2pinfo->noa_count_type[i] =
+ READEF1BYTE(ie+index);
+ index += 1;
+ p2pinfo->noa_duration[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ p2pinfo->noa_interval[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ p2pinfo->noa_start_time[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ }
+
+ if (p2pinfo->opp_ps == 1) {
+ p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+ /* Driver should wait LPS entering
+ * CTWindow
+ */
+ if (rtlpriv->psc.fw_current_inpsmode)
+ rtl_p2p_ps_cmd(hw,
+ P2P_PS_ENABLE);
+ } else if (p2pinfo->noa_num > 0) {
+ p2pinfo->p2p_ps_mode = P2P_PS_NOA;
+ rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
+ } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+ rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+ }
+ }
+ break;
+ }
+ ie += 3 + noa_len;
+ }
+}
+
+void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n", p2p_ps_state);
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ p2pinfo->p2p_ps_state = p2p_ps_state;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+ (u8 *)(&p2p_ps_state));
+
+ p2pinfo->noa_index = 0;
+ p2pinfo->ctwindow = 0;
+ p2pinfo->opp_ps = 0;
+ p2pinfo->noa_num = 0;
+ p2pinfo->p2p_ps_mode = P2P_PS_NONE;
+ if (rtlps->fw_current_inpsmode == true) {
+ if (rtlps->smart_ps == 0) {
+ rtlps->smart_ps = 2;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&rtlps->pwr_mode));
+ }
+ }
+ break;
+ case P2P_PS_ENABLE:
+ if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+ p2pinfo->p2p_ps_state = p2p_ps_state;
+
+ if (p2pinfo->ctwindow > 0) {
+ if (rtlps->smart_ps != 0) {
+ rtlps->smart_ps = 0;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&rtlps->pwr_mode));
+ }
+ }
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+ (u8 *)(&p2p_ps_state));
+ }
+ break;
+ case P2P_PS_SCAN:
+ case P2P_PS_SCAN_DONE:
+ case P2P_PS_ALLSTASLEEP:
+ if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+ p2pinfo->p2p_ps_state = p2p_ps_state;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+ (u8 *)(&p2p_ps_state));
+ }
+ break;
+ default:
+ break;
+ }
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "ctwindow %x oppps %x\n", p2pinfo->ctwindow, p2pinfo->opp_ps);
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "count %x duration %x index %x interval %x start time %x noa num %x\n",
+ p2pinfo->noa_count_type[0], p2pinfo->noa_duration[0],
+ p2pinfo->noa_index, p2pinfo->noa_interval[0],
+ p2pinfo->noa_start_time[0], p2pinfo->noa_num);
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n");
+}
+
+void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct ieee80211_hdr *hdr = (void *)data;
+
+ if (!mac->p2p)
+ return;
+ if (mac->link_state != MAC80211_LINKED)
+ return;
+ /* min. beacon length + FCS_LEN */
+ if (len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
+ return;
+
+ /* check if this really is a beacon */
+ if (!(ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_probe_resp(hdr->frame_control) ||
+ ieee80211_is_action(hdr->frame_control)))
+ return;
+
+ if (ieee80211_is_action(hdr->frame_control))
+ rtl_p2p_action_ie(hw, data, len - FCS_LEN);
+ else
+ rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
+}
diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h
index 1357856998c2..4d682b753f50 100644
--- a/drivers/net/wireless/rtlwifi/ps.h
+++ b/drivers/net/wireless/rtlwifi/ps.h
@@ -47,5 +47,7 @@ void rtl_swlps_wq_callback(void *data);
void rtl_swlps_rfon_wq_callback(void *data);
void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
+void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
+void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile
new file mode 100644
index 000000000000..5b194e97f4b3
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile
@@ -0,0 +1,16 @@
+rtl8188ee-objs := \
+ dm.o \
+ fw.o \
+ hw.o \
+ led.o \
+ phy.o \
+ pwrseq.o \
+ pwrseqcmd.o \
+ rf.o \
+ sw.o \
+ table.o \
+ trx.o
+
+obj-$(CONFIG_RTL8188EE) += rtl8188ee.o
+
+ccflags-y += -Idrivers/net/wireless/rtlwifi -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/def.h b/drivers/net/wireless/rtlwifi/rtl8188ee/def.h
new file mode 100644
index 000000000000..c764fff9ebe6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/def.h
@@ -0,0 +1,324 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_DEF_H__
+#define __RTL92C_DEF_H__
+
+#define HAL_RETRY_LIMIT_INFRA 48
+#define HAL_RETRY_LIMIT_AP_ADHOC 7
+
+#define RESET_DELAY_8185 20
+
+#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER)
+#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK)
+
+#define NUM_OF_FIRMWARE_QUEUE 10
+#define NUM_OF_PAGES_IN_FW 0x100
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1
+
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00
+
+#define MAX_LINES_HWCONFIG_TXT 1000
+#define MAX_BYTES_LINE_HWCONFIG_TXT 256
+
+#define SW_THREE_WIRE 0
+#define HW_THREE_WIRE 2
+
+#define BT_DEMO_BOARD 0
+#define BT_QA_BOARD 1
+#define BT_FPGA 2
+
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0
+#define HAL_PRIME_CHNL_OFFSET_LOWER 1
+#define HAL_PRIME_CHNL_OFFSET_UPPER 2
+
+#define MAX_H2C_QUEUE_NUM 10
+
+#define RX_MPDU_QUEUE 0
+#define RX_CMD_QUEUE 1
+#define RX_MAX_QUEUE 2
+#define AC2QUEUEID(_AC) (_AC)
+
+#define C2H_RX_CMD_HDR_LEN 8
+#define GET_C2H_CMD_CMD_LEN(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 0, 16)
+#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 16, 8)
+#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 24, 7)
+#define GET_C2H_CMD_CONTINUE(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 31, 1)
+#define GET_C2H_CMD_CONTENT(__prxhdr) \
+ ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN)
+
+#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8)
+#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8)
+#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16)
+#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5)
+#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1)
+#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5)
+#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1)
+#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
+#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
+
+#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3)
+
+
+/* [15:12] IC version(CUT): A-cut=0, B-cut=1, C-cut=2, D-cut=3
+ * [7] Manufacturer: TSMC=0, UMC=1
+ * [6:4] RF type: 1T1R=0, 1T2R=1, 2T2R=2
+ * [3] Chip type: TEST=0, NORMAL=1
+ * [2:0] IC type: 81xxC=0, 8723=1, 92D=2
+ */
+#define CHIP_8723 BIT(0)
+#define CHIP_92D BIT(1)
+#define NORMAL_CHIP BIT(3)
+#define RF_TYPE_1T1R (~(BIT(4)|BIT(5)|BIT(6)))
+#define RF_TYPE_1T2R BIT(4)
+#define RF_TYPE_2T2R BIT(5)
+#define CHIP_VENDOR_UMC BIT(7)
+#define B_CUT_VERSION BIT(12)
+#define C_CUT_VERSION BIT(13)
+#define D_CUT_VERSION ((BIT(12)|BIT(13)))
+#define E_CUT_VERSION BIT(14)
+
+
+/* MASK */
+#define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2))
+#define CHIP_TYPE_MASK BIT(3)
+#define RF_TYPE_MASK (BIT(4)|BIT(5)|BIT(6))
+#define MANUFACTUER_MASK BIT(7)
+#define ROM_VERSION_MASK (BIT(11)|BIT(10)|BIT(9)|BIT(8))
+#define CUT_VERSION_MASK (BIT(15)|BIT(14)|BIT(13)|BIT(12))
+
+/* Get element */
+#define GET_CVID_IC_TYPE(version) ((version) & IC_TYPE_MASK)
+#define GET_CVID_CHIP_TYPE(version) ((version) & CHIP_TYPE_MASK)
+#define GET_CVID_RF_TYPE(version) ((version) & RF_TYPE_MASK)
+#define GET_CVID_MANUFACTUER(version) ((version) & MANUFACTUER_MASK)
+#define GET_CVID_ROM_VERSION(version) ((version) & ROM_VERSION_MASK)
+#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK)
+
+
+#define IS_81XXC(version) \
+ ((GET_CVID_IC_TYPE(version) == 0) ? true : false)
+#define IS_8723_SERIES(version) \
+ ((GET_CVID_IC_TYPE(version) == CHIP_8723) ? true : false)
+#define IS_92D(version) \
+ ((GET_CVID_IC_TYPE(version) == CHIP_92D) ? true : false)
+
+#define IS_NORMAL_CHIP(version) \
+ ((GET_CVID_CHIP_TYPE(version)) ? true : false)
+#define IS_NORMAL_CHIP92D(version) \
+ ((GET_CVID_CHIP_TYPE(version)) ? true : false)
+
+#define IS_1T1R(version) \
+ ((GET_CVID_RF_TYPE(version)) ? false : true)
+#define IS_1T2R(version) \
+ ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false)
+#define IS_2T2R(version) \
+ ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version) \
+ ((GET_CVID_MANUFACTUER(version)) ? true : false)
+
+#define IS_92C_SERIAL(version) \
+ ((IS_81XXC(version) && IS_2T2R(version)) ? true : false)
+#define IS_81xxC_VENDOR_UMC_A_CUT(version) \
+ (IS_81XXC(version) ? ((IS_CHIP_VENDOR_UMC(version)) ? \
+ ((GET_CVID_CUT_VERSION(version)) ? false : true) : false) : false)
+#define IS_81xxC_VENDOR_UMC_B_CUT(version) \
+ (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \
+ ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true \
+ : false) : false) : false)
+
+enum version_8188e {
+ VERSION_TEST_CHIP_88E = 0x00,
+ VERSION_NORMAL_CHIP_88E = 0x01,
+ VERSION_UNKNOWN = 0xFF,
+};
+
+enum rx_packet_type {
+ NORMAL_RX,
+ TX_REPORT1,
+ TX_REPORT2,
+ HIS_REPORT,
+};
+
+enum rtl819x_loopback_e {
+ RTL819X_NO_LOOPBACK = 0,
+ RTL819X_MAC_LOOPBACK = 1,
+ RTL819X_DMA_LOOPBACK = 2,
+ RTL819X_CCK_LOOPBACK = 3,
+};
+
+enum rf_optype {
+ RF_OP_BY_SW_3WIRE = 0,
+ RF_OP_BY_FW,
+ RF_OP_MAX
+};
+
+enum rf_power_state {
+ RF_ON,
+ RF_OFF,
+ RF_SLEEP,
+ RF_SHUT_DOWN,
+};
+
+enum power_save_mode {
+ POWER_SAVE_MODE_ACTIVE,
+ POWER_SAVE_MODE_SAVE,
+};
+
+enum power_polocy_config {
+ POWERCFG_MAX_POWER_SAVINGS,
+ POWERCFG_GLOBAL_POWER_SAVINGS,
+ POWERCFG_LOCAL_POWER_SAVINGS,
+ POWERCFG_LENOVO,
+};
+
+enum interface_select_pci {
+ INTF_SEL1_MINICARD,
+ INTF_SEL0_PCIE,
+ INTF_SEL2_RSV,
+ INTF_SEL3_RSV,
+};
+
+enum hal_fw_c2h_cmd_id {
+ HAL_FW_C2H_CMD_Read_MACREG,
+ HAL_FW_C2H_CMD_Read_BBREG,
+ HAL_FW_C2H_CMD_Read_RFREG,
+ HAL_FW_C2H_CMD_Read_EEPROM,
+ HAL_FW_C2H_CMD_Read_EFUSE,
+ HAL_FW_C2H_CMD_Read_CAM,
+ HAL_FW_C2H_CMD_Get_BasicRate,
+ HAL_FW_C2H_CMD_Get_DataRate,
+ HAL_FW_C2H_CMD_Survey,
+ HAL_FW_C2H_CMD_SurveyDone,
+ HAL_FW_C2H_CMD_JoinBss,
+ HAL_FW_C2H_CMD_AddSTA,
+ HAL_FW_C2H_CMD_DelSTA,
+ HAL_FW_C2H_CMD_AtimDone,
+ HAL_FW_C2H_CMD_TX_Report,
+ HAL_FW_C2H_CMD_CCX_Report,
+ HAL_FW_C2H_CMD_DTM_Report,
+ HAL_FW_C2H_CMD_TX_Rate_Statistics,
+ HAL_FW_C2H_CMD_C2HLBK,
+ HAL_FW_C2H_CMD_C2HDBG,
+ HAL_FW_C2H_CMD_C2HFEEDBACK,
+ HAL_FW_C2H_CMD_MAX
+};
+
+enum wake_on_wlan_mode {
+ ewowlandisable,
+ ewakeonmagicpacketonly,
+ ewakeonpatternmatchonly,
+ ewakeonbothtypepacket
+};
+
+enum rtl_desc_qsel {
+ QSLT_BK = 0x2,
+ QSLT_BE = 0x0,
+ QSLT_VI = 0x5,
+ QSLT_VO = 0x7,
+ QSLT_BEACON = 0x10,
+ QSLT_HIGH = 0x11,
+ QSLT_MGNT = 0x12,
+ QSLT_CMD = 0x13,
+};
+
+enum rtl_desc92c_rate {
+ DESC92C_RATE1M = 0x00,
+ DESC92C_RATE2M = 0x01,
+ DESC92C_RATE5_5M = 0x02,
+ DESC92C_RATE11M = 0x03,
+
+ DESC92C_RATE6M = 0x04,
+ DESC92C_RATE9M = 0x05,
+ DESC92C_RATE12M = 0x06,
+ DESC92C_RATE18M = 0x07,
+ DESC92C_RATE24M = 0x08,
+ DESC92C_RATE36M = 0x09,
+ DESC92C_RATE48M = 0x0a,
+ DESC92C_RATE54M = 0x0b,
+
+ DESC92C_RATEMCS0 = 0x0c,
+ DESC92C_RATEMCS1 = 0x0d,
+ DESC92C_RATEMCS2 = 0x0e,
+ DESC92C_RATEMCS3 = 0x0f,
+ DESC92C_RATEMCS4 = 0x10,
+ DESC92C_RATEMCS5 = 0x11,
+ DESC92C_RATEMCS6 = 0x12,
+ DESC92C_RATEMCS7 = 0x13,
+ DESC92C_RATEMCS8 = 0x14,
+ DESC92C_RATEMCS9 = 0x15,
+ DESC92C_RATEMCS10 = 0x16,
+ DESC92C_RATEMCS11 = 0x17,
+ DESC92C_RATEMCS12 = 0x18,
+ DESC92C_RATEMCS13 = 0x19,
+ DESC92C_RATEMCS14 = 0x1a,
+ DESC92C_RATEMCS15 = 0x1b,
+ DESC92C_RATEMCS15_SG = 0x1c,
+ DESC92C_RATEMCS32 = 0x20,
+};
+
+struct phy_sts_cck_8192s_t {
+ u8 adc_pwdb_X[4];
+ u8 sq_rpt;
+ u8 cck_agc_rpt;
+};
+
+struct h2c_cmd_8192c {
+ u8 element_id;
+ u32 cmd_len;
+ u8 *p_cmdbuffer;
+};
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
new file mode 100644
index 000000000000..21a5cf060677
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
@@ -0,0 +1,1794 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "trx.h"
+
+static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
+ 0x7f8001fe, /* 0, +6.0dB */
+ 0x788001e2, /* 1, +5.5dB */
+ 0x71c001c7, /* 2, +5.0dB */
+ 0x6b8001ae, /* 3, +4.5dB */
+ 0x65400195, /* 4, +4.0dB */
+ 0x5fc0017f, /* 5, +3.5dB */
+ 0x5a400169, /* 6, +3.0dB */
+ 0x55400155, /* 7, +2.5dB */
+ 0x50800142, /* 8, +2.0dB */
+ 0x4c000130, /* 9, +1.5dB */
+ 0x47c0011f, /* 10, +1.0dB */
+ 0x43c0010f, /* 11, +0.5dB */
+ 0x40000100, /* 12, +0dB */
+ 0x3c8000f2, /* 13, -0.5dB */
+ 0x390000e4, /* 14, -1.0dB */
+ 0x35c000d7, /* 15, -1.5dB */
+ 0x32c000cb, /* 16, -2.0dB */
+ 0x300000c0, /* 17, -2.5dB */
+ 0x2d4000b5, /* 18, -3.0dB */
+ 0x2ac000ab, /* 19, -3.5dB */
+ 0x288000a2, /* 20, -4.0dB */
+ 0x26000098, /* 21, -4.5dB */
+ 0x24000090, /* 22, -5.0dB */
+ 0x22000088, /* 23, -5.5dB */
+ 0x20000080, /* 24, -6.0dB */
+ 0x1e400079, /* 25, -6.5dB */
+ 0x1c800072, /* 26, -7.0dB */
+ 0x1b00006c, /* 27. -7.5dB */
+ 0x19800066, /* 28, -8.0dB */
+ 0x18000060, /* 29, -8.5dB */
+ 0x16c0005b, /* 30, -9.0dB */
+ 0x15800056, /* 31, -9.5dB */
+ 0x14400051, /* 32, -10.0dB */
+ 0x1300004c, /* 33, -10.5dB */
+ 0x12000048, /* 34, -11.0dB */
+ 0x11000044, /* 35, -11.5dB */
+ 0x10000040, /* 36, -12.0dB */
+ 0x0f00003c, /* 37, -12.5dB */
+ 0x0e400039, /* 38, -13.0dB */
+ 0x0d800036, /* 39, -13.5dB */
+ 0x0cc00033, /* 40, -14.0dB */
+ 0x0c000030, /* 41, -14.5dB */
+ 0x0b40002d, /* 42, -15.0dB */
+};
+
+static const u8 cck_tbl_ch1_13[CCK_TABLE_SIZE][8] = {
+ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */
+ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */
+ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */
+ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */
+ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */
+ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */
+ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */
+ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */
+ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */
+ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */
+ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */
+ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */
+ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */
+ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */
+ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */
+ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */
+ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */
+ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */
+ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */
+ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */
+ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB*/
+ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB*/
+ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB*/
+ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB*/
+ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB*/
+ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB*/
+ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB*/
+ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB*/
+ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB*/
+ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB*/
+ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB*/
+ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB*/
+ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB*/
+};
+
+static const u8 cck_tbl_ch14[CCK_TABLE_SIZE][8] = {
+ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */
+ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */
+ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */
+ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */
+ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */
+ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */
+ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */
+ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */
+ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */
+ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */
+ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */
+ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */
+ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */
+ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */
+ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */
+ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */
+ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */
+ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */
+ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */
+ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */
+ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB*/
+ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB*/
+ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB*/
+ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB*/
+ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB*/
+ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB*/
+ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB*/
+ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB*/
+ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB*/
+ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB*/
+ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB*/
+ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB*/
+ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB*/
+};
+
+#define CAL_SWING_OFF(_off, _dir, _size, _del) \
+ do { \
+ for (_off = 0; _off < _size; _off++) { \
+ if (_del < thermal_threshold[_dir][_off]) { \
+ if (_off != 0) \
+ _off--; \
+ break; \
+ } \
+ } \
+ if (_off >= _size) \
+ _off = _size - 1; \
+ } while (0)
+
+static void rtl88e_set_iqk_matrix(struct ieee80211_hw *hw,
+ u8 ofdm_index, u8 rfpath,
+ long iqk_result_x, long iqk_result_y)
+{
+ long ele_a = 0, ele_d, ele_c = 0, value32;
+
+ ele_d = (ofdmswing_table[ofdm_index] & 0xFFC00000)>>22;
+
+ if (iqk_result_x != 0) {
+ if ((iqk_result_x & 0x00000200) != 0)
+ iqk_result_x = iqk_result_x | 0xFFFFFC00;
+ ele_a = ((iqk_result_x * ele_d)>>8)&0x000003FF;
+
+ if ((iqk_result_y & 0x00000200) != 0)
+ iqk_result_y = iqk_result_y | 0xFFFFFC00;
+ ele_c = ((iqk_result_y * ele_d)>>8)&0x000003FF;
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ value32 = (ele_d << 22)|((ele_c & 0x3F)<<16) | ele_a;
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD,
+ value32);
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, value32);
+ value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(24), value32);
+ break;
+ case RF90_PATH_B:
+ value32 = (ele_d << 22)|((ele_c & 0x3F)<<16) | ele_a;
+ rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBAL,
+ MASKDWORD, value32);
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE, MASKH4BITS, value32);
+ value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(28), value32);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD,
+ ofdmswing_table[ofdm_index]);
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(24), 0x00);
+ break;
+ case RF90_PATH_B:
+ rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBAL, MASKDWORD,
+ ofdmswing_table[ofdm_index]);
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE, MASKH4BITS, 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(28), 0x00);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void rtl88e_dm_txpower_track_adjust(struct ieee80211_hw *hw,
+ u8 type, u8 *pdirection, u32 *poutwrite_val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ u8 pwr_val = 0;
+ u8 cck_base = rtldm->swing_idx_cck_base;
+ u8 cck_val = rtldm->swing_idx_cck;
+ u8 ofdm_base = rtldm->swing_idx_ofdm_base;
+ u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A];
+
+ if (type == 0) {
+ if (ofdm_val <= ofdm_base) {
+ *pdirection = 1;
+ pwr_val = ofdm_base - ofdm_val;
+ } else {
+ *pdirection = 2;
+ pwr_val = ofdm_val - ofdm_base;
+ }
+ } else if (type == 1) {
+ if (cck_val <= cck_base) {
+ *pdirection = 1;
+ pwr_val = cck_base - cck_val;
+ } else {
+ *pdirection = 2;
+ pwr_val = cck_val - cck_base;
+ }
+ }
+
+ if (pwr_val >= TXPWRTRACK_MAX_IDX && (*pdirection == 1))
+ pwr_val = TXPWRTRACK_MAX_IDX;
+
+ *poutwrite_val = pwr_val | (pwr_val << 8) | (pwr_val << 16) |
+ (pwr_val << 24);
+}
+
+
+static void rtl88e_chk_tx_track(struct ieee80211_hw *hw,
+ enum pwr_track_control_method method,
+ u8 rfpath, u8 index)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ int jj = rtldm->swing_idx_cck;
+ int i;
+
+ if (method == TXAGC) {
+ if (rtldm->swing_flag_ofdm == true ||
+ rtldm->swing_flag_cck == true) {
+ u8 chan = rtlphy->current_channel;
+ rtl88e_phy_set_txpower_level(hw, chan);
+ rtldm->swing_flag_ofdm = false;
+ rtldm->swing_flag_cck = false;
+ }
+ } else if (method == BBSWING) {
+ if (!rtldm->cck_inch14) {
+ for (i = 0; i < 8; i++)
+ rtl_write_byte(rtlpriv, 0xa22 + i,
+ cck_tbl_ch1_13[jj][i]);
+ } else {
+ for (i = 0; i < 8; i++)
+ rtl_write_byte(rtlpriv, 0xa22 + i,
+ cck_tbl_ch14[jj][i]);
+ }
+
+ if (rfpath == RF90_PATH_A) {
+ long x = rtlphy->iqk_matrix[index].value[0][0];
+ long y = rtlphy->iqk_matrix[index].value[0][1];
+ u8 indx = rtldm->swing_idx_ofdm[rfpath];
+ rtl88e_set_iqk_matrix(hw, indx, rfpath, x, y);
+ } else if (rfpath == RF90_PATH_B) {
+ u8 indx = rtldm->swing_idx_ofdm[rfpath];
+ long x = rtlphy->iqk_matrix[indx].value[0][4];
+ long y = rtlphy->iqk_matrix[indx].value[0][5];
+ rtl88e_set_iqk_matrix(hw, indx, rfpath, x, y);
+ }
+ } else {
+ return;
+ }
+}
+
+static void rtl88e_dm_diginit(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+
+ dm_dig->dig_enable_flag = true;
+ dm_dig->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
+ dm_dig->pre_igvalue = 0;
+ dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+ dm_dig->presta_cstate = DIG_STA_DISCONNECT;
+ dm_dig->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
+ dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW;
+ dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH;
+ dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+ dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+ dm_dig->rx_gain_max = DM_DIG_MAX;
+ dm_dig->rx_gain_min = DM_DIG_MIN;
+ dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT;
+ dm_dig->back_range_max = DM_DIG_BACKOFF_MAX;
+ dm_dig->back_range_min = DM_DIG_BACKOFF_MIN;
+ dm_dig->pre_cck_cca_thres = 0xff;
+ dm_dig->cur_cck_cca_thres = 0x83;
+ dm_dig->forbidden_igi = DM_DIG_MIN;
+ dm_dig->large_fa_hit = 0;
+ dm_dig->recover_cnt = 0;
+ dm_dig->dig_min_0 = 0x25;
+ dm_dig->dig_min_1 = 0x25;
+ dm_dig->media_connect_0 = false;
+ dm_dig->media_connect_1 = false;
+ rtlpriv->dm.dm_initialgain_enable = true;
+}
+
+static u8 rtl88e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+ long rssi_val_min = 0;
+
+ if ((dm_dig->curmultista_cstate == DIG_MULTISTA_CONNECT) &&
+ (dm_dig->cursta_cstate == DIG_STA_CONNECT)) {
+ if (rtlpriv->dm.entry_min_undec_sm_pwdb != 0)
+ rssi_val_min =
+ (rtlpriv->dm.entry_min_undec_sm_pwdb >
+ rtlpriv->dm.undec_sm_pwdb) ?
+ rtlpriv->dm.undec_sm_pwdb :
+ rtlpriv->dm.entry_min_undec_sm_pwdb;
+ else
+ rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+ } else if (dm_dig->cursta_cstate == DIG_STA_CONNECT ||
+ dm_dig->cursta_cstate == DIG_STA_BEFORE_CONNECT) {
+ rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+ } else if (dm_dig->curmultista_cstate ==
+ DIG_MULTISTA_CONNECT) {
+ rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
+ }
+ return (u8)rssi_val_min;
+}
+
+static void rtl88e_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+ u32 ret_value;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *alm_cnt = &(rtlpriv->falsealm_cnt);
+
+ rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD);
+ alm_cnt->cnt_fast_fsync_fail = (ret_value&0xffff);
+ alm_cnt->cnt_sb_search_fail = ((ret_value&0xffff0000)>>16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
+ alm_cnt->cnt_ofdm_cca = (ret_value&0xffff);
+ alm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
+ alm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
+ alm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
+ alm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+ alm_cnt->cnt_ofdm_fail = alm_cnt->cnt_parity_fail +
+ alm_cnt->cnt_rate_illegal +
+ alm_cnt->cnt_crc8_fail +
+ alm_cnt->cnt_mcs_fail +
+ alm_cnt->cnt_fast_fsync_fail +
+ alm_cnt->cnt_sb_search_fail;
+
+ ret_value = rtl_get_bbreg(hw, REG_SC_CNT, MASKDWORD);
+ alm_cnt->cnt_bw_lsc = (ret_value & 0xffff);
+ alm_cnt->cnt_bw_usc = ((ret_value & 0xffff0000) >> 16);
+
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(12), 1);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1);
+
+ ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
+ alm_cnt->cnt_cck_fail = ret_value;
+
+ ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3);
+ alm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
+
+ ret_value = rtl_get_bbreg(hw, RCCK0_CCA_CNT, MASKDWORD);
+ alm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) |
+ ((ret_value&0xFF00)>>8);
+
+ alm_cnt->cnt_all = alm_cnt->cnt_fast_fsync_fail +
+ alm_cnt->cnt_sb_search_fail +
+ alm_cnt->cnt_parity_fail +
+ alm_cnt->cnt_rate_illegal +
+ alm_cnt->cnt_crc8_fail +
+ alm_cnt->cnt_mcs_fail +
+ alm_cnt->cnt_cck_fail;
+ alm_cnt->cnt_cca_all = alm_cnt->cnt_ofdm_cca + alm_cnt->cnt_cck_cca;
+
+ rtl_set_bbreg(hw, ROFDM0_TRSWISOLATION, BIT(31), 1);
+ rtl_set_bbreg(hw, ROFDM0_TRSWISOLATION, BIT(31), 0);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(27), 1);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(27), 0);
+ rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 0);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 0);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(13)|BIT(12), 0);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(13)|BIT(12), 2);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(15)|BIT(14), 0);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(15)|BIT(14), 2);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "cnt_parity_fail = %d, cnt_rate_illegal = %d, "
+ "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+ alm_cnt->cnt_parity_fail,
+ alm_cnt->cnt_rate_illegal,
+ alm_cnt->cnt_crc8_fail, alm_cnt->cnt_mcs_fail);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n",
+ alm_cnt->cnt_ofdm_fail,
+ alm_cnt->cnt_cck_fail, alm_cnt->cnt_all);
+}
+
+static void rtl88e_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+ u8 cur_cck_cca_thresh;
+
+ if (dm_dig->cursta_cstate == DIG_STA_CONNECT) {
+ dm_dig->rssi_val_min = rtl88e_dm_initial_gain_min_pwdb(hw);
+ if (dm_dig->rssi_val_min > 25) {
+ cur_cck_cca_thresh = 0xcd;
+ } else if ((dm_dig->rssi_val_min <= 25) &&
+ (dm_dig->rssi_val_min > 10)) {
+ cur_cck_cca_thresh = 0x83;
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+ cur_cck_cca_thresh = 0x83;
+ else
+ cur_cck_cca_thresh = 0x40;
+ }
+
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+ cur_cck_cca_thresh = 0x83;
+ else
+ cur_cck_cca_thresh = 0x40;
+ }
+
+ if (dm_dig->cur_cck_cca_thres != cur_cck_cca_thresh)
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, cur_cck_cca_thresh);
+
+ dm_dig->cur_cck_cca_thres = cur_cck_cca_thresh;
+ dm_dig->pre_cck_cca_thres = dm_dig->cur_cck_cca_thres;
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "CCK cca thresh hold =%x\n", dm_dig->cur_cck_cca_thres);
+}
+
+static void rtl88e_dm_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 dig_min, dig_maxofmin;
+ bool bfirstconnect;
+ u8 dm_dig_max, dm_dig_min;
+ u8 current_igi = dm_dig->cur_igvalue;
+
+ if (rtlpriv->dm.dm_initialgain_enable == false)
+ return;
+ if (dm_dig->dig_enable_flag == false)
+ return;
+ if (mac->act_scanning == true)
+ return;
+
+ if (mac->link_state >= MAC80211_LINKED)
+ dm_dig->cursta_cstate = DIG_STA_CONNECT;
+ else
+ dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
+ rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
+ dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+
+ dm_dig_max = DM_DIG_MAX;
+ dm_dig_min = DM_DIG_MIN;
+ dig_maxofmin = DM_DIG_MAX_AP;
+ dig_min = dm_dig->dig_min_0;
+ bfirstconnect = ((mac->link_state >= MAC80211_LINKED) ? true : false) &&
+ (dm_dig->media_connect_0 == false);
+
+ dm_dig->rssi_val_min =
+ rtl88e_dm_initial_gain_min_pwdb(hw);
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if ((dm_dig->rssi_val_min + 20) > dm_dig_max)
+ dm_dig->rx_gain_max = dm_dig_max;
+ else if ((dm_dig->rssi_val_min + 20) < dm_dig_min)
+ dm_dig->rx_gain_max = dm_dig_min;
+ else
+ dm_dig->rx_gain_max = dm_dig->rssi_val_min + 20;
+
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
+ dig_min = dm_dig->antdiv_rssi_max;
+ } else {
+ if (dm_dig->rssi_val_min < dm_dig_min)
+ dig_min = dm_dig_min;
+ else if (dm_dig->rssi_val_min < dig_maxofmin)
+ dig_min = dig_maxofmin;
+ else
+ dig_min = dm_dig->rssi_val_min;
+ }
+ } else {
+ dm_dig->rx_gain_max = dm_dig_max;
+ dig_min = dm_dig_min;
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
+ }
+
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
+ dm_dig->large_fa_hit++;
+ if (dm_dig->forbidden_igi < current_igi) {
+ dm_dig->forbidden_igi = current_igi;
+ dm_dig->large_fa_hit = 1;
+ }
+
+ if (dm_dig->large_fa_hit >= 3) {
+ if ((dm_dig->forbidden_igi + 1) > dm_dig->rx_gain_max)
+ dm_dig->rx_gain_min = dm_dig->rx_gain_max;
+ else
+ dm_dig->rx_gain_min = dm_dig->forbidden_igi + 1;
+ dm_dig->recover_cnt = 3600;
+ }
+ } else {
+ if (dm_dig->recover_cnt != 0) {
+ dm_dig->recover_cnt--;
+ } else {
+ if (dm_dig->large_fa_hit == 0) {
+ if ((dm_dig->forbidden_igi - 1) < dig_min) {
+ dm_dig->forbidden_igi = dig_min;
+ dm_dig->rx_gain_min = dig_min;
+ } else {
+ dm_dig->forbidden_igi--;
+ dm_dig->rx_gain_min =
+ dm_dig->forbidden_igi + 1;
+ }
+ } else if (dm_dig->large_fa_hit == 3) {
+ dm_dig->large_fa_hit = 0;
+ }
+ }
+ }
+
+ if (dm_dig->cursta_cstate == DIG_STA_CONNECT) {
+ if (bfirstconnect) {
+ current_igi = dm_dig->rssi_val_min;
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2)
+ current_igi += 2;
+ else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1)
+ current_igi++;
+ else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
+ current_igi--;
+ }
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+ current_igi += 2;
+ else if (rtlpriv->falsealm_cnt.cnt_all > 8000)
+ current_igi++;
+ else if (rtlpriv->falsealm_cnt.cnt_all < 500)
+ current_igi--;
+ }
+
+ if (current_igi > DM_DIG_FA_UPPER)
+ current_igi = DM_DIG_FA_UPPER;
+ else if (current_igi < DM_DIG_FA_LOWER)
+ current_igi = DM_DIG_FA_LOWER;
+
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+ current_igi = DM_DIG_FA_UPPER;
+
+ dm_dig->cur_igvalue = current_igi;
+ rtl88e_dm_write_dig(hw);
+ dm_dig->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ?
+ true : false);
+ dm_dig->dig_min_0 = dig_min;
+
+ rtl88e_dm_cck_packet_detection_thresh(hw);
+}
+
+static void rtl88e_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dynamic_txpower_enable = false;
+
+ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+}
+
+static void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undec_sm_pwdb;
+
+ if (!rtlpriv->dm.dynamic_txpower_enable)
+ return;
+
+ if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+ return;
+ }
+
+ if ((mac->link_state < MAC80211_LINKED) &&
+ (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ "Not connected\n");
+
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+
+ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+ return;
+ }
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ undec_sm_pwdb =
+ rtlpriv->dm.entry_min_undec_sm_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "AP Client PWDB = 0x%lx\n",
+ undec_sm_pwdb);
+ } else {
+ undec_sm_pwdb =
+ rtlpriv->dm.undec_sm_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "STA Default Port PWDB = 0x%lx\n",
+ undec_sm_pwdb);
+ }
+ } else {
+ undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "AP Ext Port PWDB = 0x%lx\n", undec_sm_pwdb);
+ }
+
+ if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "TXHIGHPWRLEVEL_LEVEL1 (TxPwr = 0x0)\n");
+ } else if ((undec_sm_pwdb <
+ (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+ (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "TXHIGHPWRLEVEL_LEVEL1 (TxPwr = 0x10)\n");
+ } else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "TXHIGHPWRLEVEL_NORMAL\n");
+ }
+
+ if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "PHY_SetTxPowerLevel8192S() Channel = %d\n",
+ rtlphy->current_channel);
+ rtl88e_phy_set_txpower_level(hw, rtlphy->current_channel);
+ }
+
+ rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
+void rtl88e_dm_write_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+ "cur_igvalue = 0x%x, "
+ "pre_igvalue = 0x%x, back_val = %d\n",
+ dm_dig->cur_igvalue, dm_dig->pre_igvalue,
+ dm_dig->back_val);
+
+ if (dm_dig->cur_igvalue > 0x3f)
+ dm_dig->cur_igvalue = 0x3f;
+ if (dm_dig->pre_igvalue != dm_dig->cur_igvalue) {
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f,
+ dm_dig->cur_igvalue);
+
+ dm_dig->pre_igvalue = dm_dig->cur_igvalue;
+ }
+}
+
+static void rtl88e_dm_pwdb_monitor(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *drv_priv;
+ static u64 last_txok;
+ static u64 last_rx;
+ long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
+
+ if (rtlhal->oem_id == RT_CID_819x_HP) {
+ u64 cur_txok_cnt = 0;
+ u64 cur_rxok_cnt = 0;
+ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok;
+ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rx;
+ last_txok = cur_txok_cnt;
+ last_rx = cur_rxok_cnt;
+
+ if (cur_rxok_cnt > (cur_txok_cnt * 6))
+ rtl_write_dword(rtlpriv, REG_ARFR0, 0x8f015);
+ else
+ rtl_write_dword(rtlpriv, REG_ARFR0, 0xff015);
+ }
+
+ /* AP & ADHOC & MESH */
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+ if (drv_priv->rssi_stat.undec_sm_pwdb < tmp_entry_min_pwdb)
+ tmp_entry_min_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
+ if (drv_priv->rssi_stat.undec_sm_pwdb > tmp_entry_max_pwdb)
+ tmp_entry_max_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
+ }
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+ /* If associated entry is found */
+ if (tmp_entry_max_pwdb != 0) {
+ rtlpriv->dm.entry_max_undec_sm_pwdb = tmp_entry_max_pwdb;
+ RTPRINT(rtlpriv, FDM, DM_PWDB, "EntryMaxPWDB = 0x%lx(%ld)\n",
+ tmp_entry_max_pwdb, tmp_entry_max_pwdb);
+ } else {
+ rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
+ }
+ /* If associated entry is found */
+ if (tmp_entry_min_pwdb != 0xff) {
+ rtlpriv->dm.entry_min_undec_sm_pwdb = tmp_entry_min_pwdb;
+ RTPRINT(rtlpriv, FDM, DM_PWDB, "EntryMinPWDB = 0x%lx(%ld)\n",
+ tmp_entry_min_pwdb, tmp_entry_min_pwdb);
+ } else {
+ rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
+ }
+ /* Indicate Rx signal strength to FW. */
+ if (!rtlpriv->dm.useramask)
+ rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb);
+}
+
+void rtl88e_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.current_turbo_edca = false;
+ rtlpriv->dm.is_any_nonbepkts = false;
+ rtlpriv->dm.is_cur_rdlstate = false;
+}
+
+static void rtl88e_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ static u64 last_txok_cnt;
+ static u64 last_rxok_cnt;
+ static u32 last_bt_edca_ul;
+ static u32 last_bt_edca_dl;
+ u64 cur_txok_cnt = 0;
+ u64 cur_rxok_cnt = 0;
+ u32 edca_be_ul = 0x5ea42b;
+ u32 edca_be_dl = 0x5ea42b;
+ bool change_edca = false;
+
+ if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) ||
+ (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) {
+ rtlpriv->dm.current_turbo_edca = false;
+ last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+ last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl;
+ }
+
+ if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) {
+ edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+ change_edca = true;
+ }
+
+ if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) {
+ edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl;
+ change_edca = true;
+ }
+
+ if (mac->link_state != MAC80211_LINKED) {
+ rtlpriv->dm.current_turbo_edca = false;
+ return;
+ }
+
+ if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) {
+ if (!(edca_be_ul & 0xffff0000))
+ edca_be_ul |= 0x005e0000;
+
+ if (!(edca_be_dl & 0xffff0000))
+ edca_be_dl |= 0x005e0000;
+ }
+
+ if ((change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) &&
+ (!rtlpriv->dm.disable_framebursting))) {
+ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
+ if (cur_rxok_cnt > 4 * cur_txok_cnt) {
+ if (!rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ rtl_write_dword(rtlpriv,
+ REG_EDCA_BE_PARAM,
+ edca_be_dl);
+ rtlpriv->dm.is_cur_rdlstate = true;
+ }
+ } else {
+ if (rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ rtl_write_dword(rtlpriv,
+ REG_EDCA_BE_PARAM,
+ edca_be_ul);
+ rtlpriv->dm.is_cur_rdlstate = false;
+ }
+ }
+ rtlpriv->dm.current_turbo_edca = true;
+ } else {
+ if (rtlpriv->dm.current_turbo_edca) {
+ u8 tmp = AC0_BE;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_AC_PARAM,
+ (u8 *)(&tmp));
+ rtlpriv->dm.current_turbo_edca = false;
+ }
+ }
+
+ rtlpriv->dm.is_any_nonbepkts = false;
+ last_txok_cnt = rtlpriv->stats.txbytesunicast;
+ last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
+ *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 thermalvalue = 0, delta, delta_lck, delta_iqk, off;
+ u8 th_avg_cnt = 0;
+ u32 thermalvalue_avg = 0;
+ long ele_d, temp_cck;
+ char ofdm_index[2], cck_index = 0, ofdm_old[2] = {0, 0}, cck_old = 0;
+ int i = 0;
+ bool is2t = false;
+
+ u8 ofdm_min_index = 6, rf = (is2t) ? 2 : 1;
+ u8 index_for_channel;
+ enum _dec_inc {dec, power_inc};
+
+ /* 0.1 the following TWO tables decide the final index of
+ * OFDM/CCK swing table
+ */
+ char del_tbl_idx[2][15] = {
+ {0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11},
+ {0, 0, -1, -2, -3, -4, -4, -4, -4, -5, -7, -8, -9, -9, -10}
+ };
+ u8 thermal_threshold[2][15] = {
+ {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 27},
+ {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 25, 25, 25}
+ };
+
+ /*Initilization (7 steps in total) */
+ rtlpriv->dm.txpower_trackinginit = true;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "rtl88e_dm_txpower_tracking_callback_thermalmeter\n");
+
+ thermalvalue = (u8) rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xfc00);
+ if (!thermalvalue)
+ return;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x\n",
+ thermalvalue, rtlpriv->dm.thermalvalue,
+ rtlefuse->eeprom_thermalmeter);
+
+ /*1. Query OFDM Default Setting: Path A*/
+ ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD) & MASKOFDM_D;
+ for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
+ if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
+ ofdm_old[0] = (u8) i;
+ rtldm->swing_idx_ofdm_base = (u8)i;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n",
+ ROFDM0_XATXIQIMBAL,
+ ele_d, ofdm_old[0]);
+ break;
+ }
+ }
+
+ if (is2t) {
+ ele_d = rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBAL,
+ MASKDWORD) & MASKOFDM_D;
+ for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
+ if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
+ ofdm_old[1] = (u8)i;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+ DBG_LOUD,
+ "Initial pathB ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n",
+ ROFDM0_XBTXIQIMBAL, ele_d,
+ ofdm_old[1]);
+ break;
+ }
+ }
+ }
+ /*2.Query CCK default setting From 0xa24*/
+ temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2, MASKDWORD) & MASKCCK;
+ for (i = 0; i < CCK_TABLE_LENGTH; i++) {
+ if (rtlpriv->dm.cck_inch14) {
+ if (memcmp(&temp_cck, &cck_tbl_ch14[i][2], 4) == 0) {
+ cck_old = (u8)i;
+ rtldm->swing_idx_cck_base = (u8)i;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch 14 %d\n",
+ RCCK0_TXFILTER2, temp_cck, cck_old,
+ rtlpriv->dm.cck_inch14);
+ break;
+ }
+ } else {
+ if (memcmp(&temp_cck, &cck_tbl_ch1_13[i][2], 4) == 0) {
+ cck_old = (u8)i;
+ rtldm->swing_idx_cck_base = (u8)i;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch14 %d\n",
+ RCCK0_TXFILTER2, temp_cck, cck_old,
+ rtlpriv->dm.cck_inch14);
+ break;
+ }
+ }
+ }
+
+ /*3 Initialize ThermalValues of RFCalibrateInfo*/
+ if (!rtldm->thermalvalue) {
+ rtlpriv->dm.thermalvalue = rtlefuse->eeprom_thermalmeter;
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ for (i = 0; i < rf; i++)
+ rtlpriv->dm.ofdm_index[i] = ofdm_old[i];
+ rtlpriv->dm.cck_index = cck_old;
+ }
+
+ /*4 Calculate average thermal meter*/
+ rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermalvalue;
+ rtldm->thermalvalue_avg_index++;
+ if (rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_88E)
+ rtldm->thermalvalue_avg_index = 0;
+
+ for (i = 0; i < AVG_THERMAL_NUM_88E; i++) {
+ if (rtldm->thermalvalue_avg[i]) {
+ thermalvalue_avg += rtldm->thermalvalue_avg[i];
+ th_avg_cnt++;
+ }
+ }
+
+ if (th_avg_cnt)
+ thermalvalue = (u8)(thermalvalue_avg / th_avg_cnt);
+
+ /* 5 Calculate delta, delta_LCK, delta_IQK.*/
+ if (rtlhal->reloadtxpowerindex) {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+ rtlhal->reloadtxpowerindex = false;
+ rtlpriv->dm.done_txpower = false;
+ } else if (rtlpriv->dm.done_txpower) {
+ delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue) :
+ (rtlpriv->dm.thermalvalue - thermalvalue);
+ } else {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+ }
+ delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
+ (rtlpriv->dm.thermalvalue_lck - thermalvalue);
+ delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
+ (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+ "eeprom_thermalmeter 0x%x delta 0x%x "
+ "delta_lck 0x%x delta_iqk 0x%x\n",
+ thermalvalue, rtlpriv->dm.thermalvalue,
+ rtlefuse->eeprom_thermalmeter, delta, delta_lck,
+ delta_iqk);
+ /* 6 If necessary, do LCK.*/
+ if (delta_lck >= 8) {
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtl88e_phy_lc_calibrate(hw);
+ }
+
+ /* 7 If necessary, move the index of swing table to adjust Tx power. */
+ if (delta > 0 && rtlpriv->dm.txpower_track_control) {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+
+ /* 7.1 Get the final CCK_index and OFDM_index for each
+ * swing table.
+ */
+ if (thermalvalue > rtlefuse->eeprom_thermalmeter) {
+ CAL_SWING_OFF(off, power_inc, IDX_MAP, delta);
+ for (i = 0; i < rf; i++)
+ ofdm_index[i] = rtldm->ofdm_index[i] +
+ del_tbl_idx[power_inc][off];
+ cck_index = rtldm->cck_index +
+ del_tbl_idx[power_inc][off];
+ } else {
+ CAL_SWING_OFF(off, dec, IDX_MAP, delta);
+ for (i = 0; i < rf; i++)
+ ofdm_index[i] = rtldm->ofdm_index[i] +
+ del_tbl_idx[dec][off];
+ cck_index = rtldm->cck_index + del_tbl_idx[dec][off];
+ }
+
+ /* 7.2 Handle boundary conditions of index.*/
+ for (i = 0; i < rf; i++) {
+ if (ofdm_index[i] > OFDM_TABLE_SIZE-1)
+ ofdm_index[i] = OFDM_TABLE_SIZE-1;
+ else if (rtldm->ofdm_index[i] < ofdm_min_index)
+ ofdm_index[i] = ofdm_min_index;
+ }
+
+ if (cck_index > CCK_TABLE_SIZE - 1)
+ cck_index = CCK_TABLE_SIZE - 1;
+ else if (cck_index < 0)
+ cck_index = 0;
+
+ /*7.3Configure the Swing Table to adjust Tx Power.*/
+ if (rtlpriv->dm.txpower_track_control) {
+ rtldm->done_txpower = true;
+ rtldm->swing_idx_ofdm[RF90_PATH_A] =
+ (u8)ofdm_index[RF90_PATH_A];
+ if (is2t)
+ rtldm->swing_idx_ofdm[RF90_PATH_B] =
+ (u8)ofdm_index[RF90_PATH_B];
+ rtldm->swing_idx_cck = cck_index;
+ if (rtldm->swing_idx_ofdm_cur !=
+ rtldm->swing_idx_ofdm[0]) {
+ rtldm->swing_idx_ofdm_cur =
+ rtldm->swing_idx_ofdm[0];
+ rtldm->swing_flag_ofdm = true;
+ }
+
+ if (rtldm->swing_idx_cck != rtldm->swing_idx_cck) {
+ rtldm->swing_idx_cck_cur = rtldm->swing_idx_cck;
+ rtldm->swing_flag_cck = true;
+ }
+
+ rtl88e_chk_tx_track(hw, TXAGC, 0, 0);
+
+ if (is2t)
+ rtl88e_chk_tx_track(hw, BBSWING,
+ RF90_PATH_B,
+ index_for_channel);
+ }
+ }
+
+ if (delta_iqk >= 8) {
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ rtl88e_phy_iq_calibrate(hw, false);
+ }
+
+ if (rtldm->txpower_track_control)
+ rtldm->thermalvalue = thermalvalue;
+ rtldm->txpowercount = 0;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "end\n");
+}
+
+static void rtl88e_dm_init_txpower_tracking(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.txpower_tracking = true;
+ rtlpriv->dm.txpower_trackinginit = false;
+ rtlpriv->dm.txpowercount = 0;
+ rtlpriv->dm.txpower_track_control = true;
+
+ rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A] = 12;
+ rtlpriv->dm.swing_idx_ofdm_cur = 12;
+ rtlpriv->dm.swing_flag_ofdm = false;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ " rtlpriv->dm.txpower_tracking = %d\n",
+ rtlpriv->dm.txpower_tracking);
+}
+
+void rtl88e_dm_check_txpower_tracking(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ static u8 tm_trigger;
+
+ if (!rtlpriv->dm.txpower_tracking)
+ return;
+
+ if (!tm_trigger) {
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17)|BIT(16),
+ 0x03);
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Trigger 88E Thermal Meter!!\n");
+ tm_trigger = 1;
+ return;
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Schedule TxPowerTracking !!\n");
+ rtl88e_dm_txpower_tracking_callback_thermalmeter(hw);
+ tm_trigger = 0;
+ }
+}
+
+void rtl88e_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rate_adaptive *p_ra = &(rtlpriv->ra);
+
+ p_ra->ratr_state = DM_RATR_STA_INIT;
+ p_ra->pre_ratr_state = DM_RATR_STA_INIT;
+
+ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+ rtlpriv->dm.useramask = true;
+ else
+ rtlpriv->dm.useramask = false;
+}
+
+static void rtl88e_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rate_adaptive *p_ra = &(rtlpriv->ra);
+ struct ieee80211_sta *sta = NULL;
+ u32 low_rssi, hi_rssi;
+
+ if (is_hal_stop(rtlhal)) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "driver is going to unload\n");
+ return;
+ }
+
+ if (!rtlpriv->dm.useramask) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "driver does not control rate adaptive mask\n");
+ return;
+ }
+
+ if (mac->link_state == MAC80211_LINKED &&
+ mac->opmode == NL80211_IFTYPE_STATION) {
+ switch (p_ra->pre_ratr_state) {
+ case DM_RATR_STA_HIGH:
+ hi_rssi = 50;
+ low_rssi = 20;
+ break;
+ case DM_RATR_STA_MIDDLE:
+ hi_rssi = 55;
+ low_rssi = 20;
+ break;
+ case DM_RATR_STA_LOW:
+ hi_rssi = 50;
+ low_rssi = 25;
+ break;
+ default:
+ hi_rssi = 50;
+ low_rssi = 20;
+ break;
+ }
+
+ if (rtlpriv->dm.undec_sm_pwdb > (long)hi_rssi)
+ p_ra->ratr_state = DM_RATR_STA_HIGH;
+ else if (rtlpriv->dm.undec_sm_pwdb > (long)low_rssi)
+ p_ra->ratr_state = DM_RATR_STA_MIDDLE;
+ else
+ p_ra->ratr_state = DM_RATR_STA_LOW;
+
+ if (p_ra->pre_ratr_state != p_ra->ratr_state) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI = %ld\n",
+ rtlpriv->dm.undec_sm_pwdb);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI_LEVEL = %d\n", p_ra->ratr_state);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "PreState = %d, CurState = %d\n",
+ p_ra->pre_ratr_state, p_ra->ratr_state);
+
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, mac->bssid);
+ if (sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ p_ra->ratr_state);
+ rcu_read_unlock();
+
+ p_ra->pre_ratr_state = p_ra->ratr_state;
+ }
+ }
+}
+
+static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ps_t *dm_pstable = &rtlpriv->dm_pstable;
+
+ dm_pstable->pre_ccastate = CCA_MAX;
+ dm_pstable->cur_ccasate = CCA_MAX;
+ dm_pstable->pre_rfstate = RF_MAX;
+ dm_pstable->cur_rfstate = RF_MAX;
+ dm_pstable->rssi_val_min = 0;
+}
+
+static void rtl88e_dm_update_rx_idle_ant(struct ieee80211_hw *hw, u8 ant)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 def_ant, opt_ant;
+
+ if (fat_tbl->rx_idle_ant != ant) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "need to update rx idle ant\n");
+ if (ant == MAIN_ANT) {
+ def_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+ MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+ opt_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+ AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+ } else {
+ def_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+ AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+ opt_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+ MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+ }
+
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) |
+ BIT(4) | BIT(3), def_ant);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
+ BIT(7) | BIT(6), opt_ant);
+ rtl_set_bbreg(hw, DM_REG_ANTSEL_CTRL_11N, BIT(14) |
+ BIT(13) | BIT(12), def_ant);
+ rtl_set_bbreg(hw, DM_REG_RESP_TX_11N, BIT(6) | BIT(7),
+ def_ant);
+ } else if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) {
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) |
+ BIT(4) | BIT(3), def_ant);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
+ BIT(7) | BIT(6), opt_ant);
+ }
+ }
+ fat_tbl->rx_idle_ant = ant;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "RxIdleAnt %s\n",
+ ((ant == MAIN_ANT) ? ("MAIN_ANT") : ("AUX_ANT")));
+}
+
+static void rtl88e_dm_update_tx_ant(struct ieee80211_hw *hw,
+ u8 ant, u32 mac_id)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u8 target_ant;
+
+ if (ant == MAIN_ANT)
+ target_ant = MAIN_ANT_CG_TRX;
+ else
+ target_ant = AUX_ANT_CG_TRX;
+
+ fat_tbl->antsel_a[mac_id] = target_ant & BIT(0);
+ fat_tbl->antsel_b[mac_id] = (target_ant & BIT(1)) >> 1;
+ fat_tbl->antsel_c[mac_id] = (target_ant & BIT(2)) >> 2;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "txfrominfo target ant %s\n",
+ ((ant == MAIN_ANT) ? ("MAIN_ANT") : ("AUX_ANT")));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "antsel_tr_mux = 3'b%d%d%d\n",
+ fat_tbl->antsel_c[mac_id],
+ fat_tbl->antsel_b[mac_id], fat_tbl->antsel_a[mac_id]);
+}
+
+static void rtl88e_dm_rx_hw_antena_div_init(struct ieee80211_hw *hw)
+{
+ u32 value32;
+ /*MAC Setting*/
+ value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
+ rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 |
+ (BIT(23) | BIT(25)));
+ /*Pin Setting*/
+ rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(22), 1);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(31), 1);
+ /*OFDM Setting*/
+ rtl_set_bbreg(hw, DM_REG_ANTDIV_PARA1_11N, MASKDWORD, 0x000000a0);
+ /*CCK Setting*/
+ rtl_set_bbreg(hw, DM_REG_BB_PWR_SAV4_11N, BIT(7), 1);
+ rtl_set_bbreg(hw, DM_REG_CCK_ANTDIV_PARA2_11N, BIT(4), 1);
+ rtl88e_dm_update_rx_idle_ant(hw, MAIN_ANT);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKLWORD, 0x0201);
+}
+
+static void rtl88e_dm_trx_hw_antenna_div_init(struct ieee80211_hw *hw)
+{
+ u32 value32;
+
+ /*MAC Setting*/
+ value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
+ rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 |
+ (BIT(23) | BIT(25)));
+ /*Pin Setting*/
+ rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(22), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(31), 1);
+ /*OFDM Setting*/
+ rtl_set_bbreg(hw, DM_REG_ANTDIV_PARA1_11N, MASKDWORD, 0x000000a0);
+ /*CCK Setting*/
+ rtl_set_bbreg(hw, DM_REG_BB_PWR_SAV4_11N, BIT(7), 1);
+ rtl_set_bbreg(hw, DM_REG_CCK_ANTDIV_PARA2_11N, BIT(4), 1);
+ /*TX Setting*/
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N, BIT(21), 0);
+ rtl88e_dm_update_rx_idle_ant(hw, MAIN_ANT);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKLWORD, 0x0201);
+}
+
+static void rtl88e_dm_fast_training_init(struct ieee80211_hw *hw)
+{
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 ant_combo = 2;
+ u32 value32, i;
+
+ for (i = 0; i < 6; i++) {
+ fat_tbl->bssid[i] = 0;
+ fat_tbl->ant_sum[i] = 0;
+ fat_tbl->ant_cnt[i] = 0;
+ fat_tbl->ant_ave[i] = 0;
+ }
+ fat_tbl->train_idx = 0;
+ fat_tbl->fat_state = FAT_NORMAL_STATE;
+
+ /*MAC Setting*/
+ value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
+ rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 | (BIT(23) |
+ BIT(25)));
+ value32 = rtl_get_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKDWORD);
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKDWORD, value32 | (BIT(16) |
+ BIT(17)));
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKLWORD, 0);
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1, MASKDWORD, 0);
+
+ /*Pin Setting*/
+ rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(22), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(31), 1);
+
+ /*OFDM Setting*/
+ rtl_set_bbreg(hw, DM_REG_ANTDIV_PARA1_11N, MASKDWORD, 0x000000a0);
+ /*antenna mapping table*/
+ if (ant_combo == 2) {
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE0, 1);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE1, 2);
+ } else if (ant_combo == 7) {
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE0, 1);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE1, 2);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE2, 2);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE3, 3);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE0, 4);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE1, 5);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE2, 6);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE3, 7);
+ }
+
+ /*TX Setting*/
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N, BIT(21), 1);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) | BIT(4) | BIT(3), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) | BIT(7) | BIT(6), 1);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(2) | BIT(1) | BIT(0),
+ (ant_combo - 1));
+
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
+}
+
+static void rtl88e_dm_antenna_div_init(struct ieee80211_hw *hw)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtl88e_dm_rx_hw_antena_div_init(hw);
+ else if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl88e_dm_trx_hw_antenna_div_init(hw);
+ else if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV)
+ rtl88e_dm_fast_training_init(hw);
+}
+
+void rtl88e_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
+ u8 *pdesc, u32 mac_id)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+
+ if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) ||
+ (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)) {
+ SET_TX_DESC_ANTSEL_A(pdesc, fat_tbl->antsel_a[mac_id]);
+ SET_TX_DESC_ANTSEL_B(pdesc, fat_tbl->antsel_b[mac_id]);
+ SET_TX_DESC_ANTSEL_C(pdesc, fat_tbl->antsel_c[mac_id]);
+ }
+}
+
+void rtl88e_dm_ant_sel_statistics(struct ieee80211_hw *hw,
+ u8 antsel_tr_mux, u32 mac_id, u32 rx_pwdb_all)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
+ if (antsel_tr_mux == MAIN_ANT_CG_TRX) {
+ fat_tbl->main_ant_sum[mac_id] += rx_pwdb_all;
+ fat_tbl->main_ant_cnt[mac_id]++;
+ } else {
+ fat_tbl->aux_ant_sum[mac_id] += rx_pwdb_all;
+ fat_tbl->aux_ant_cnt[mac_id]++;
+ }
+ } else if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) {
+ if (antsel_tr_mux == MAIN_ANT_CGCS_RX) {
+ fat_tbl->main_ant_sum[mac_id] += rx_pwdb_all;
+ fat_tbl->main_ant_cnt[mac_id]++;
+ } else {
+ fat_tbl->aux_ant_sum[mac_id] += rx_pwdb_all;
+ fat_tbl->aux_ant_cnt[mac_id]++;
+ }
+ }
+}
+
+static void rtl88e_dm_hw_ant_div(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct rtl_sta_info *drv_priv;
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 i, min_rssi = 0xff, ant_div_max_rssi = 0, max_rssi = 0;
+ u32 local_min_rssi, local_max_rssi;
+ u32 main_rssi, aux_rssi;
+ u8 rx_idle_ant = 0, target_ant = 7;
+
+ i = 0;
+ main_rssi = (fat_tbl->main_ant_cnt[i] != 0) ?
+ (fat_tbl->main_ant_sum[i] /
+ fat_tbl->main_ant_cnt[i]) : 0;
+ aux_rssi = (fat_tbl->aux_ant_cnt[i] != 0) ?
+ (fat_tbl->aux_ant_sum[i] / fat_tbl->aux_ant_cnt[i]) : 0;
+ target_ant = (main_rssi == aux_rssi) ?
+ fat_tbl->rx_idle_ant : ((main_rssi >= aux_rssi) ?
+ MAIN_ANT : AUX_ANT);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "main_ant_sum %d main_ant_cnt %d\n",
+ fat_tbl->main_ant_sum[i], fat_tbl->main_ant_cnt[i]);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "aux_ant_sum %d aux_ant_cnt %d\n",
+ fat_tbl->aux_ant_sum[i],
+ fat_tbl->aux_ant_cnt[i]);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "main_rssi %d aux_rssi%d\n", main_rssi, aux_rssi);
+ local_max_rssi = (main_rssi > aux_rssi) ? main_rssi : aux_rssi;
+ if ((local_max_rssi > ant_div_max_rssi) && (local_max_rssi < 40))
+ ant_div_max_rssi = local_max_rssi;
+ if (local_max_rssi > max_rssi)
+ max_rssi = local_max_rssi;
+
+ if ((fat_tbl->rx_idle_ant == MAIN_ANT) && (main_rssi == 0))
+ main_rssi = aux_rssi;
+ else if ((fat_tbl->rx_idle_ant == AUX_ANT) && (aux_rssi == 0))
+ aux_rssi = main_rssi;
+
+ local_min_rssi = (main_rssi > aux_rssi) ? aux_rssi : main_rssi;
+ if (local_min_rssi < min_rssi) {
+ min_rssi = local_min_rssi;
+ rx_idle_ant = target_ant;
+ }
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl88e_dm_update_tx_ant(hw, target_ant, i);
+
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
+ rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) {
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+ i++;
+ main_rssi = (fat_tbl->main_ant_cnt[i] != 0) ?
+ (fat_tbl->main_ant_sum[i] /
+ fat_tbl->main_ant_cnt[i]) : 0;
+ aux_rssi = (fat_tbl->aux_ant_cnt[i] != 0) ?
+ (fat_tbl->aux_ant_sum[i] /
+ fat_tbl->aux_ant_cnt[i]) : 0;
+ target_ant = (main_rssi == aux_rssi) ?
+ fat_tbl->rx_idle_ant : ((main_rssi >=
+ aux_rssi) ? MAIN_ANT : AUX_ANT);
+
+
+ local_max_rssi = max_t(u32, main_rssi, aux_rssi);
+ if ((local_max_rssi > ant_div_max_rssi) &&
+ (local_max_rssi < 40))
+ ant_div_max_rssi = local_max_rssi;
+ if (local_max_rssi > max_rssi)
+ max_rssi = local_max_rssi;
+
+ if ((fat_tbl->rx_idle_ant == MAIN_ANT) && !main_rssi)
+ main_rssi = aux_rssi;
+ else if ((fat_tbl->rx_idle_ant == AUX_ANT) &&
+ (aux_rssi == 0))
+ aux_rssi = main_rssi;
+
+ local_min_rssi = (main_rssi > aux_rssi) ?
+ aux_rssi : main_rssi;
+ if (local_min_rssi < min_rssi) {
+ min_rssi = local_min_rssi;
+ rx_idle_ant = target_ant;
+ }
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl88e_dm_update_tx_ant(hw, target_ant, i);
+ }
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+ }
+
+ for (i = 0; i < ASSOCIATE_ENTRY_NUM; i++) {
+ fat_tbl->main_ant_sum[i] = 0;
+ fat_tbl->aux_ant_sum[i] = 0;
+ fat_tbl->main_ant_cnt[i] = 0;
+ fat_tbl->aux_ant_cnt[i] = 0;
+ }
+
+ rtl88e_dm_update_rx_idle_ant(hw, rx_idle_ant);
+
+ dm_dig->antdiv_rssi_max = ant_div_max_rssi;
+ dm_dig->rssi_max = max_rssi;
+}
+
+static void rtl88e_set_next_mac_address_target(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct rtl_sta_info *drv_priv;
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 value32, i, j = 0;
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ for (i = 0; i < ASSOCIATE_ENTRY_NUM; i++) {
+ if ((fat_tbl->train_idx + 1) == ASSOCIATE_ENTRY_NUM)
+ fat_tbl->train_idx = 0;
+ else
+ fat_tbl->train_idx++;
+
+ if (fat_tbl->train_idx == 0) {
+ value32 = (mac->mac_addr[5] << 8) |
+ mac->mac_addr[4];
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2,
+ MASKLWORD, value32);
+
+ value32 = (mac->mac_addr[3] << 24) |
+ (mac->mac_addr[2] << 16) |
+ (mac->mac_addr[1] << 8) |
+ mac->mac_addr[0];
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1,
+ MASKDWORD, value32);
+ break;
+ }
+
+ if (rtlpriv->mac80211.opmode !=
+ NL80211_IFTYPE_STATION) {
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_for_each_entry(drv_priv,
+ &rtlpriv->entry_list,
+ list) {
+ j++;
+ if (j != fat_tbl->train_idx)
+ continue;
+
+ value32 = (drv_priv->mac_addr[5] << 8) |
+ drv_priv->mac_addr[4];
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2,
+ MASKLWORD, value32);
+
+ value32 = (drv_priv->mac_addr[3]<<24) |
+ (drv_priv->mac_addr[2]<<16) |
+ (drv_priv->mac_addr[1]<<8) |
+ drv_priv->mac_addr[0];
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1,
+ MASKDWORD, value32);
+ break;
+ }
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+ /*find entry, break*/
+ if (j == fat_tbl->train_idx)
+ break;
+ }
+ }
+ }
+}
+
+static void rtl88e_dm_fast_ant_training(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 i, max_rssi = 0;
+ u8 target_ant = 2;
+ bool bpkt_filter_match = false;
+
+ if (fat_tbl->fat_state == FAT_TRAINING_STATE) {
+ for (i = 0; i < 7; i++) {
+ if (fat_tbl->ant_cnt[i] == 0) {
+ fat_tbl->ant_ave[i] = 0;
+ } else {
+ fat_tbl->ant_ave[i] = fat_tbl->ant_sum[i] /
+ fat_tbl->ant_cnt[i];
+ bpkt_filter_match = true;
+ }
+
+ if (fat_tbl->ant_ave[i] > max_rssi) {
+ max_rssi = fat_tbl->ant_ave[i];
+ target_ant = (u8) i;
+ }
+ }
+
+ if (bpkt_filter_match == false) {
+ rtl_set_bbreg(hw, DM_REG_TXAGC_A_1_MCS32_11N,
+ BIT(16), 0);
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 0);
+ } else {
+ rtl_set_bbreg(hw, DM_REG_TXAGC_A_1_MCS32_11N,
+ BIT(16), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
+ BIT(7) | BIT(6), target_ant);
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N, BIT(21), 1);
+
+ fat_tbl->antsel_a[fat_tbl->train_idx] =
+ target_ant & BIT(0);
+ fat_tbl->antsel_b[fat_tbl->train_idx] =
+ (target_ant & BIT(1)) >> 1;
+ fat_tbl->antsel_c[fat_tbl->train_idx] =
+ (target_ant & BIT(2)) >> 2;
+
+ if (target_ant == 0)
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 0);
+ }
+
+ for (i = 0; i < 7; i++) {
+ fat_tbl->ant_sum[i] = 0;
+ fat_tbl->ant_cnt[i] = 0;
+ }
+
+ fat_tbl->fat_state = FAT_NORMAL_STATE;
+ return;
+ }
+
+ if (fat_tbl->fat_state == FAT_NORMAL_STATE) {
+ rtl88e_set_next_mac_address_target(hw);
+
+ fat_tbl->fat_state = FAT_TRAINING_STATE;
+ rtl_set_bbreg(hw, DM_REG_TXAGC_A_1_MCS32_11N, BIT(16), 1);
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
+
+ mod_timer(&rtlpriv->works.fast_antenna_training_timer,
+ jiffies + MSECS(RTL_WATCH_DOG_TIME));
+ }
+}
+
+void rtl88e_dm_fast_antenna_training_callback(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+
+ rtl88e_dm_fast_ant_training(hw);
+}
+
+static void rtl88e_dm_antenna_diversity(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+
+ if (mac->link_state < MAC80211_LINKED) {
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "No Link\n");
+ if (fat_tbl->becomelinked == true) {
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+ "need to turn off HW AntDiv\n");
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 0);
+ rtl_set_bbreg(hw, DM_REG_CCK_ANTDIV_PARA1_11N,
+ BIT(15), 0);
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N,
+ BIT(21), 0);
+ fat_tbl->becomelinked =
+ (mac->link_state == MAC80211_LINKED) ? true : false;
+ }
+ return;
+ } else {
+ if (fat_tbl->becomelinked == false) {
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+ "Need to turn on HW AntDiv\n");
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
+ rtl_set_bbreg(hw, DM_REG_CCK_ANTDIV_PARA1_11N,
+ BIT(15), 1);
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N,
+ BIT(21), 1);
+ fat_tbl->becomelinked =
+ (mac->link_state >= MAC80211_LINKED) ? true : false;
+ }
+ }
+
+ if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) ||
+ (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV))
+ rtl88e_dm_hw_ant_div(hw);
+ else if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV)
+ rtl88e_dm_fast_ant_training(hw);
+}
+
+void rtl88e_dm_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+ rtl88e_dm_diginit(hw);
+ rtl88e_dm_init_dynamic_txpower(hw);
+ rtl88e_dm_init_edca_turbo(hw);
+ rtl88e_dm_init_rate_adaptive_mask(hw);
+ rtl88e_dm_init_txpower_tracking(hw);
+ rtl92c_dm_init_dynamic_bb_powersaving(hw);
+ rtl88e_dm_antenna_div_init(hw);
+}
+
+void rtl88e_dm_watchdog(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool fw_current_inpsmode = false;
+ bool fw_ps_awake = true;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inpsmode));
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+ (u8 *)(&fw_ps_awake));
+ if (ppsc->p2p_ps_info.p2p_ps_mode)
+ fw_ps_awake = false;
+
+ if ((ppsc->rfpwr_state == ERFON) &&
+ ((!fw_current_inpsmode) && fw_ps_awake) &&
+ (!ppsc->rfchange_inprogress)) {
+ rtl88e_dm_pwdb_monitor(hw);
+ rtl88e_dm_dig(hw);
+ rtl88e_dm_false_alarm_counter_statistics(hw);
+ rtl92c_dm_dynamic_txpower(hw);
+ rtl88e_dm_check_txpower_tracking(hw);
+ rtl88e_dm_refresh_rate_adaptive_mask(hw);
+ rtl88e_dm_check_edca_turbo(hw);
+ rtl88e_dm_antenna_diversity(hw);
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
new file mode 100644
index 000000000000..0e07f72ea158
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
@@ -0,0 +1,326 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL88E_DM_H__
+#define __RTL88E_DM_H__
+
+#define MAIN_ANT 0
+#define AUX_ANT 1
+#define MAIN_ANT_CG_TRX 1
+#define AUX_ANT_CG_TRX 0
+#define MAIN_ANT_CGCS_RX 0
+#define AUX_ANT_CGCS_RX 1
+
+/*RF REG LIST*/
+#define DM_REG_RF_MODE_11N 0x00
+#define DM_REG_RF_0B_11N 0x0B
+#define DM_REG_CHNBW_11N 0x18
+#define DM_REG_T_METER_11N 0x24
+#define DM_REG_RF_25_11N 0x25
+#define DM_REG_RF_26_11N 0x26
+#define DM_REG_RF_27_11N 0x27
+#define DM_REG_RF_2B_11N 0x2B
+#define DM_REG_RF_2C_11N 0x2C
+#define DM_REG_RXRF_A3_11N 0x3C
+#define DM_REG_T_METER_92D_11N 0x42
+#define DM_REG_T_METER_88E_11N 0x42
+
+/*BB REG LIST*/
+/*PAGE 8 */
+#define DM_REG_BB_CTRL_11N 0x800
+#define DM_REG_RF_PIN_11N 0x804
+#define DM_REG_PSD_CTRL_11N 0x808
+#define DM_REG_TX_ANT_CTRL_11N 0x80C
+#define DM_REG_BB_PWR_SAV5_11N 0x818
+#define DM_REG_CCK_RPT_FORMAT_11N 0x824
+#define DM_REG_RX_DEFAULT_A_11N 0x858
+#define DM_REG_RX_DEFAULT_B_11N 0x85A
+#define DM_REG_BB_PWR_SAV3_11N 0x85C
+#define DM_REG_ANTSEL_CTRL_11N 0x860
+#define DM_REG_RX_ANT_CTRL_11N 0x864
+#define DM_REG_PIN_CTRL_11N 0x870
+#define DM_REG_BB_PWR_SAV1_11N 0x874
+#define DM_REG_ANTSEL_PATH_11N 0x878
+#define DM_REG_BB_3WIRE_11N 0x88C
+#define DM_REG_SC_CNT_11N 0x8C4
+#define DM_REG_PSD_DATA_11N 0x8B4
+/*PAGE 9*/
+#define DM_REG_ANT_MAPPING1_11N 0x914
+#define DM_REG_ANT_MAPPING2_11N 0x918
+/*PAGE A*/
+#define DM_REG_CCK_ANTDIV_PARA1_11N 0xA00
+#define DM_REG_CCK_CCA_11N 0xA0A
+#define DM_REG_CCK_ANTDIV_PARA2_11N 0xA0C
+#define DM_REG_CCK_ANTDIV_PARA3_11N 0xA10
+#define DM_REG_CCK_ANTDIV_PARA4_11N 0xA14
+#define DM_REG_CCK_FILTER_PARA1_11N 0xA22
+#define DM_REG_CCK_FILTER_PARA2_11N 0xA23
+#define DM_REG_CCK_FILTER_PARA3_11N 0xA24
+#define DM_REG_CCK_FILTER_PARA4_11N 0xA25
+#define DM_REG_CCK_FILTER_PARA5_11N 0xA26
+#define DM_REG_CCK_FILTER_PARA6_11N 0xA27
+#define DM_REG_CCK_FILTER_PARA7_11N 0xA28
+#define DM_REG_CCK_FILTER_PARA8_11N 0xA29
+#define DM_REG_CCK_FA_RST_11N 0xA2C
+#define DM_REG_CCK_FA_MSB_11N 0xA58
+#define DM_REG_CCK_FA_LSB_11N 0xA5C
+#define DM_REG_CCK_CCA_CNT_11N 0xA60
+#define DM_REG_BB_PWR_SAV4_11N 0xA74
+/*PAGE B */
+#define DM_REG_LNA_SWITCH_11N 0xB2C
+#define DM_REG_PATH_SWITCH_11N 0xB30
+#define DM_REG_RSSI_CTRL_11N 0xB38
+#define DM_REG_CONFIG_ANTA_11N 0xB68
+#define DM_REG_RSSI_BT_11N 0xB9C
+/*PAGE C */
+#define DM_REG_OFDM_FA_HOLDC_11N 0xC00
+#define DM_REG_RX_PATH_11N 0xC04
+#define DM_REG_TRMUX_11N 0xC08
+#define DM_REG_OFDM_FA_RSTC_11N 0xC0C
+#define DM_REG_RXIQI_MATRIX_11N 0xC14
+#define DM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C
+#define DM_REG_IGI_A_11N 0xC50
+#define DM_REG_ANTDIV_PARA2_11N 0xC54
+#define DM_REG_IGI_B_11N 0xC58
+#define DM_REG_ANTDIV_PARA3_11N 0xC5C
+#define DM_REG_BB_PWR_SAV2_11N 0xC70
+#define DM_REG_RX_OFF_11N 0xC7C
+#define DM_REG_TXIQK_MATRIXA_11N 0xC80
+#define DM_REG_TXIQK_MATRIXB_11N 0xC88
+#define DM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94
+#define DM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C
+#define DM_REG_RXIQK_MATRIX_LSB_11N 0xCA0
+#define DM_REG_ANTDIV_PARA1_11N 0xCA4
+#define DM_REG_OFDM_FA_TYPE1_11N 0xCF0
+/*PAGE D */
+#define DM_REG_OFDM_FA_RSTD_11N 0xD00
+#define DM_REG_OFDM_FA_TYPE2_11N 0xDA0
+#define DM_REG_OFDM_FA_TYPE3_11N 0xDA4
+#define DM_REG_OFDM_FA_TYPE4_11N 0xDA8
+/*PAGE E */
+#define DM_REG_TXAGC_A_6_18_11N 0xE00
+#define DM_REG_TXAGC_A_24_54_11N 0xE04
+#define DM_REG_TXAGC_A_1_MCS32_11N 0xE08
+#define DM_REG_TXAGC_A_MCS0_3_11N 0xE10
+#define DM_REG_TXAGC_A_MCS4_7_11N 0xE14
+#define DM_REG_TXAGC_A_MCS8_11_11N 0xE18
+#define DM_REG_TXAGC_A_MCS12_15_11N 0xE1C
+#define DM_REG_FPGA0_IQK_11N 0xE28
+#define DM_REG_TXIQK_TONE_A_11N 0xE30
+#define DM_REG_RXIQK_TONE_A_11N 0xE34
+#define DM_REG_TXIQK_PI_A_11N 0xE38
+#define DM_REG_RXIQK_PI_A_11N 0xE3C
+#define DM_REG_TXIQK_11N 0xE40
+#define DM_REG_RXIQK_11N 0xE44
+#define DM_REG_IQK_AGC_PTS_11N 0xE48
+#define DM_REG_IQK_AGC_RSP_11N 0xE4C
+#define DM_REG_BLUETOOTH_11N 0xE6C
+#define DM_REG_RX_WAIT_CCA_11N 0xE70
+#define DM_REG_TX_CCK_RFON_11N 0xE74
+#define DM_REG_TX_CCK_BBON_11N 0xE78
+#define DM_REG_OFDM_RFON_11N 0xE7C
+#define DM_REG_OFDM_BBON_11N 0xE80
+#define DM_REG_TX2RX_11N 0xE84
+#define DM_REG_TX2TX_11N 0xE88
+#define DM_REG_RX_CCK_11N 0xE8C
+#define DM_REG_RX_OFDM_11N 0xED0
+#define DM_REG_RX_WAIT_RIFS_11N 0xED4
+#define DM_REG_RX2RX_11N 0xED8
+#define DM_REG_STANDBY_11N 0xEDC
+#define DM_REG_SLEEP_11N 0xEE0
+#define DM_REG_PMPD_ANAEN_11N 0xEEC
+
+
+/*MAC REG LIST*/
+#define DM_REG_BB_RST_11N 0x02
+#define DM_REG_ANTSEL_PIN_11N 0x4C
+#define DM_REG_EARLY_MODE_11N 0x4D0
+#define DM_REG_RSSI_MONITOR_11N 0x4FE
+#define DM_REG_EDCA_VO_11N 0x500
+#define DM_REG_EDCA_VI_11N 0x504
+#define DM_REG_EDCA_BE_11N 0x508
+#define DM_REG_EDCA_BK_11N 0x50C
+#define DM_REG_TXPAUSE_11N 0x522
+#define DM_REG_RESP_TX_11N 0x6D8
+#define DM_REG_ANT_TRAIN_1 0x7b0
+#define DM_REG_ANT_TRAIN_2 0x7b4
+
+/*DIG Related*/
+#define DM_BIT_IGI_11N 0x0000007F
+
+#define HAL_DM_DIG_DISABLE BIT(0)
+#define HAL_DM_HIPWR_DISABLE BIT(1)
+
+#define OFDM_TABLE_LENGTH 43
+#define CCK_TABLE_LENGTH 33
+
+#define OFDM_TABLE_SIZE 43
+#define CCK_TABLE_SIZE 33
+
+#define BW_AUTO_SWITCH_HIGH_LOW 25
+#define BW_AUTO_SWITCH_LOW_HIGH 30
+
+#define DM_DIG_THRESH_HIGH 40
+#define DM_DIG_THRESH_LOW 35
+
+#define DM_FALSEALARM_THRESH_LOW 400
+#define DM_FALSEALARM_THRESH_HIGH 1000
+
+#define DM_DIG_MAX 0x3e
+#define DM_DIG_MIN 0x1e
+
+#define DM_DIG_MAX_AP 0x32
+#define DM_DIG_MIN_AP 0x20
+
+#define DM_DIG_FA_UPPER 0x3e
+#define DM_DIG_FA_LOWER 0x1e
+#define DM_DIG_FA_TH0 0x200
+#define DM_DIG_FA_TH1 0x300
+#define DM_DIG_FA_TH2 0x400
+
+#define DM_DIG_BACKOFF_MAX 12
+#define DM_DIG_BACKOFF_MIN -4
+#define DM_DIG_BACKOFF_DEFAULT 10
+
+#define RXPATHSELECTION_SS_TH_LOW 30
+#define RXPATHSELECTION_DIFF_TH 18
+
+#define DM_RATR_STA_INIT 0
+#define DM_RATR_STA_HIGH 1
+#define DM_RATR_STA_MIDDLE 2
+#define DM_RATR_STA_LOW 3
+
+#define CTS2SELF_THVAL 30
+#define REGC38_TH 20
+
+#define WAIOTTHVAL 25
+
+#define TXHIGHPWRLEVEL_NORMAL 0
+#define TXHIGHPWRLEVEL_LEVEL1 1
+#define TXHIGHPWRLEVEL_LEVEL2 2
+#define TXHIGHPWRLEVEL_BT1 3
+#define TXHIGHPWRLEVEL_BT2 4
+
+#define DM_TYPE_BYFW 0
+#define DM_TYPE_BYDRIVER 1
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
+#define TXPWRTRACK_MAX_IDX 6
+
+struct swat_t {
+ u8 failure_cnt;
+ u8 try_flag;
+ u8 stop_trying;
+ long pre_rssi;
+ long trying_threshold;
+ u8 cur_antenna;
+ u8 pre_antenna;
+};
+
+enum FAT_STATE {
+ FAT_NORMAL_STATE = 0,
+ FAT_TRAINING_STATE = 1,
+};
+
+enum tag_dynamic_init_gain_operation_type_definition {
+ DIG_TYPE_THRESH_HIGH = 0,
+ DIG_TYPE_THRESH_LOW = 1,
+ DIG_TYPE_BACKOFF = 2,
+ DIG_TYPE_RX_GAIN_MIN = 3,
+ DIG_TYPE_RX_GAIN_MAX = 4,
+ DIG_TYPE_ENABLE = 5,
+ DIG_TYPE_DISABLE = 6,
+ DIG_OP_TYPE_MAX
+};
+
+enum tag_cck_packet_detection_threshold_type_definition {
+ CCK_PD_STAGE_LOWRSSI = 0,
+ CCK_PD_STAGE_HIGHRSSI = 1,
+ CCK_FA_STAGE_LOW = 2,
+ CCK_FA_STAGE_HIGH = 3,
+ CCK_PD_STAGE_MAX = 4,
+};
+
+enum dm_1r_cca_e {
+ CCA_1R = 0,
+ CCA_2R = 1,
+ CCA_MAX = 2,
+};
+
+enum dm_rf_e {
+ RF_SAVE = 0,
+ RF_NORMAL = 1,
+ RF_MAX = 2,
+};
+
+enum dm_sw_ant_switch_e {
+ ANS_ANTENNA_B = 1,
+ ANS_ANTENNA_A = 2,
+ ANS_ANTENNA_MAX = 3,
+};
+
+enum dm_dig_ext_port_alg_e {
+ DIG_EXT_PORT_STAGE_0 = 0,
+ DIG_EXT_PORT_STAGE_1 = 1,
+ DIG_EXT_PORT_STAGE_2 = 2,
+ DIG_EXT_PORT_STAGE_3 = 3,
+ DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_dig_connect_e {
+ DIG_STA_DISCONNECT = 0,
+ DIG_STA_CONNECT = 1,
+ DIG_STA_BEFORE_CONNECT = 2,
+ DIG_MULTISTA_DISCONNECT = 3,
+ DIG_MULTISTA_CONNECT = 4,
+ DIG_CONNECT_MAX
+};
+
+enum pwr_track_control_method {
+ BBSWING,
+ TXAGC
+};
+
+void rtl88e_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
+ u8 *pdesc, u32 mac_id);
+void rtl88e_dm_ant_sel_statistics(struct ieee80211_hw *hw, u8 antsel_tr_mux,
+ u32 mac_id, u32 rx_pwdb_all);
+void rtl88e_dm_fast_antenna_training_callback(unsigned long data);
+void rtl88e_dm_init(struct ieee80211_hw *hw);
+void rtl88e_dm_watchdog(struct ieee80211_hw *hw);
+void rtl88e_dm_write_dig(struct ieee80211_hw *hw);
+void rtl88e_dm_init_edca_turbo(struct ieee80211_hw *hw);
+void rtl88e_dm_check_txpower_tracking(struct ieee80211_hw *hw);
+void rtl88e_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl88e_dm_txpower_track_adjust(struct ieee80211_hw *hw,
+ u8 type, u8 *pdirection,
+ u32 *poutwrite_val);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
new file mode 100644
index 000000000000..57e4cc5833a9
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
@@ -0,0 +1,830 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+
+#include <linux/kmemleak.h>
+
+static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp;
+
+ if (enable) {
+ tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
+ } else {
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
+
+ rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
+ }
+}
+
+static void _rtl88e_fw_block_write(struct ieee80211_hw *hw,
+ const u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 blk_sz = sizeof(u32);
+ u8 *buf_ptr = (u8 *)buffer;
+ u32 *pu4BytePtr = (u32 *)buffer;
+ u32 i, offset, blk_cnt, remain;
+
+ blk_cnt = size / blk_sz;
+ remain = size % blk_sz;
+
+ for (i = 0; i < blk_cnt; i++) {
+ offset = i * blk_sz;
+ rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
+ *(pu4BytePtr + i));
+ }
+
+ if (remain) {
+ offset = blk_cnt * blk_sz;
+ buf_ptr += offset;
+ for (i = 0; i < remain; i++) {
+ rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
+ offset + i), *(buf_ptr + i));
+ }
+ }
+}
+
+static void _rtl88e_fw_page_write(struct ieee80211_hw *hw,
+ u32 page, const u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 value8;
+ u8 u8page = (u8) (page & 0x07);
+
+ value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
+
+ rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
+ _rtl88e_fw_block_write(hw, buffer, size);
+}
+
+static void _rtl88e_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
+{
+ u32 fwlen = *pfwlen;
+ u8 remain = (u8) (fwlen % 4);
+
+ remain = (remain == 0) ? 0 : (4 - remain);
+
+ while (remain > 0) {
+ pfwbuf[fwlen] = 0;
+ fwlen++;
+ remain--;
+ }
+
+ *pfwlen = fwlen;
+}
+
+static void _rtl88e_write_fw(struct ieee80211_hw *hw,
+ enum version_8188e version, u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 *buf_ptr = (u8 *)buffer;
+ u32 page_no, remain;
+ u32 page, offset;
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
+
+ _rtl88e_fill_dummy(buf_ptr, &size);
+
+ page_no = size / FW_8192C_PAGE_SIZE;
+ remain = size % FW_8192C_PAGE_SIZE;
+
+ if (page_no > 8) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Page numbers should not greater then 8\n");
+ }
+
+ for (page = 0; page < page_no; page++) {
+ offset = page * FW_8192C_PAGE_SIZE;
+ _rtl88e_fw_page_write(hw, page, (buf_ptr + offset),
+ FW_8192C_PAGE_SIZE);
+ }
+
+ if (remain) {
+ offset = page_no * FW_8192C_PAGE_SIZE;
+ page = page_no;
+ _rtl88e_fw_page_write(hw, page, (buf_ptr + offset), remain);
+ }
+}
+
+static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int err = -EIO;
+ u32 counter = 0;
+ u32 value32;
+
+ do {
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
+ (!(value32 & FWDL_CHKSUM_RPT)));
+
+ if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
+ value32);
+ goto exit;
+ }
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
+
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ value32 |= MCUFWDL_RDY;
+ value32 &= ~WINTINI_RDY;
+ rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+
+ rtl88e_firmware_selfreset(hw);
+ counter = 0;
+
+ do {
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ if (value32 & WINTINI_RDY) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ "Polling FW ready success!! REG_MCUFWDL:0x%08x.\n",
+ value32);
+ err = 0;
+ goto exit;
+ }
+
+ udelay(FW_8192C_POLLING_DELAY);
+
+ } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
+
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
+
+exit:
+ return err;
+}
+
+int rtl88e_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl92c_firmware_header *pfwheader;
+ u8 *pfwdata;
+ u32 fwsize;
+ int err;
+ enum version_8188e version = rtlhal->version;
+
+ if (!rtlhal->pfirmware)
+ return 1;
+
+ pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
+ pfwdata = (u8 *)rtlhal->pfirmware;
+ fwsize = rtlhal->fwsize;
+ RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+ "normal Firmware SIZE %d\n", fwsize);
+
+ if (IS_FW_HEADER_EXIST(pfwheader)) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+ "Firmware Version(%d), Signature(%#x), Size(%d)\n",
+ pfwheader->version, pfwheader->signature,
+ (int)sizeof(struct rtl92c_firmware_header));
+
+ pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
+ fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
+ }
+
+ if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
+ rtl88e_firmware_selfreset(hw);
+ }
+ _rtl88e_enable_fw_download(hw, true);
+ _rtl88e_write_fw(hw, version, pfwdata, fwsize);
+ _rtl88e_enable_fw_download(hw, false);
+
+ err = _rtl88e_fw_free_to_go(hw);
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+ "Firmware is%s ready to run!\n", err ? " not" : "");
+ return 0;
+}
+
+static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 val_hmetfr;
+
+ val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
+ if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
+ return true;
+ return false;
+}
+
+static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
+ u8 element_id, u32 cmd_len,
+ u8 *cmd_b)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 boxnum;
+ u16 box_reg = 0, box_extreg = 0;
+ u8 u1b_tmp;
+ bool isfw_read = false;
+ u8 buf_index = 0;
+ bool write_sucess = false;
+ u8 wait_h2c_limit = 100;
+ u8 wait_writeh2c_limit = 100;
+ u8 boxc[4], boxext[2];
+ u32 h2c_waitcounter = 0;
+ unsigned long flag;
+ u8 idx;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
+
+ while (true) {
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+ if (rtlhal->h2c_setinprogress) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "H2C set in progress! Wait to set..element_id(%d).\n",
+ element_id);
+
+ while (rtlhal->h2c_setinprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
+ flag);
+ h2c_waitcounter++;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wait 100 us (%d times)...\n",
+ h2c_waitcounter);
+ udelay(100);
+
+ if (h2c_waitcounter > 1000)
+ return;
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
+ flag);
+ }
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+ } else {
+ rtlhal->h2c_setinprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+ break;
+ }
+ }
+
+ while (!write_sucess) {
+ wait_writeh2c_limit--;
+ if (wait_writeh2c_limit == 0) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Write H2C fail because no trigger for FW INT!\n");
+ break;
+ }
+
+ boxnum = rtlhal->last_hmeboxnum;
+ switch (boxnum) {
+ case 0:
+ box_reg = REG_HMEBOX_0;
+ box_extreg = REG_HMEBOX_EXT_0;
+ break;
+ case 1:
+ box_reg = REG_HMEBOX_1;
+ box_extreg = REG_HMEBOX_EXT_1;
+ break;
+ case 2:
+ box_reg = REG_HMEBOX_2;
+ box_extreg = REG_HMEBOX_EXT_2;
+ break;
+ case 3:
+ box_reg = REG_HMEBOX_3;
+ box_extreg = REG_HMEBOX_EXT_3;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+
+ isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
+ while (!isfw_read) {
+ wait_h2c_limit--;
+ if (wait_h2c_limit == 0) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wating too long for FW read "
+ "clear HMEBox(%d)!\n", boxnum);
+ break;
+ }
+
+ udelay(10);
+
+ isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
+ u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wating for FW read clear HMEBox(%d)!!! "
+ "0x130 = %2x\n", boxnum, u1b_tmp);
+ }
+
+ if (!isfw_read) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Write H2C register BOX[%d] fail!!!!! "
+ "Fw do not read.\n", boxnum);
+ break;
+ }
+
+ memset(boxc, 0, sizeof(boxc));
+ memset(boxext, 0, sizeof(boxext));
+ boxc[0] = element_id;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Write element_id box_reg(%4x) = %2x\n",
+ box_reg, element_id);
+
+ switch (cmd_len) {
+ case 1:
+ case 2:
+ case 3:
+ /*boxc[0] &= ~(BIT(7));*/
+ memcpy((u8 *)(boxc) + 1, cmd_b + buf_index, cmd_len);
+
+ for (idx = 0; idx < 4; idx++)
+ rtl_write_byte(rtlpriv, box_reg+idx, boxc[idx]);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ /*boxc[0] |= (BIT(7));*/
+ memcpy((u8 *)(boxext), cmd_b + buf_index+3, cmd_len-3);
+ memcpy((u8 *)(boxc) + 1, cmd_b + buf_index, 3);
+
+ for (idx = 0; idx < 2; idx++) {
+ rtl_write_byte(rtlpriv, box_extreg + idx,
+ boxext[idx]);
+ }
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxc[idx]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+
+ write_sucess = true;
+
+ rtlhal->last_hmeboxnum = boxnum + 1;
+ if (rtlhal->last_hmeboxnum == 4)
+ rtlhal->last_hmeboxnum = 0;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "pHalData->last_hmeboxnum = %d\n",
+ rtlhal->last_hmeboxnum);
+ }
+
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+ rtlhal->h2c_setinprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
+}
+
+void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
+ u8 element_id, u32 cmd_len, u8 *cmd_b)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 tmp_cmdbuf[2];
+
+ if (rtlhal->fw_ready == false) {
+ RT_ASSERT(false, "fail H2C cmd - Fw download fail!!!\n");
+ return;
+ }
+
+ memset(tmp_cmdbuf, 0, 8);
+ memcpy(tmp_cmdbuf, cmd_b, cmd_len);
+ _rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
+
+ return;
+}
+
+void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
+{
+ u8 u1b_tmp;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "8051Reset88E(): 8051 reset success.\n");
+}
+
+void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 power_state = 0;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+ SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
+ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, 0);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+ (rtlpriv->mac80211.p2p) ?
+ ppsc->smart_ps : 1);
+ SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
+ ppsc->reg_max_lps_awakeintvl);
+ SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
+ if (mode == FW_PS_ACTIVE_MODE)
+ power_state |= FW_PWR_STATE_ACTIVE;
+ else
+ power_state |= FW_PWR_STATE_RF_OFF;
+ SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
+ u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE, H2C_88E_PWEMODE_LENGTH,
+ u1_h2c_set_pwrmode);
+}
+
+void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
+{
+ u8 u1_joinbssrpt_parm[1] = { 0 };
+
+ SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
+
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
+}
+
+void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+ u8 ap_offload_enable)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
+
+ SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
+ SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
+ SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
+
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD, H2C_88E_AP_OFFLOAD_LENGTH,
+ u1_apoffload_parm);
+}
+
+static bool _rtl88e_cmd_send_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ struct sk_buff *pskb = NULL;
+ unsigned long flags;
+
+ ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ pskb = __skb_dequeue(&ring->queue);
+ if (pskb)
+ kfree_skb(pskb);
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ pdesc = &ring->desc[0];
+
+ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+
+ __skb_queue_tail(&ring->queue, skb);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+ return true;
+}
+
+#define BEACON_PG 0 /* ->1 */
+#define PSPOLL_PG 2
+#define NULL_PG 3
+#define PROBERSP_PG 4 /* ->5 */
+
+#define TOTAL_RESERVED_PKT_LEN 768
+
+static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
+ /* page 0 beacon */
+ 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+ 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+ 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+ 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+ 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+ 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+ 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 1 beacon */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 2 ps-poll */
+ 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 3 null */
+ 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 4 probe_resp */
+ 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+ 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
+ 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+ 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+ 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+ 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+ 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+ 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+ 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 5 probe_resp */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct sk_buff *skb = NULL;
+
+ u32 totalpacketlen;
+ u8 u1RsvdPageLoc[5] = { 0 };
+
+ u8 *beacon;
+ u8 *pspoll;
+ u8 *nullfunc;
+ u8 *probersp;
+ /*---------------------------------------------------------
+ * (1) beacon
+ *---------------------------------------------------------
+ */
+ beacon = &reserved_page_packet[BEACON_PG * 128];
+ SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+ /*-------------------------------------------------------
+ * (2) ps-poll
+ *--------------------------------------------------------
+ */
+ pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+ SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
+ SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
+ SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
+
+ SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+
+ /*--------------------------------------------------------
+ * (3) null data
+ *---------------------------------------------------------
+ */
+ nullfunc = &reserved_page_packet[NULL_PG * 128];
+ SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+ SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+ SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+
+ /*---------------------------------------------------------
+ * (4) probe response
+ *----------------------------------------------------------
+ */
+ probersp = &reserved_page_packet[PROBERSP_PG * 128];
+ SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
+ SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
+
+ SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
+
+ totalpacketlen = TOTAL_RESERVED_PKT_LEN;
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+ "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+ &reserved_page_packet[0], totalpacketlen);
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+ u1RsvdPageLoc, 3);
+
+ skb = dev_alloc_skb(totalpacketlen);
+ if (!skb)
+ return;
+ kmemleak_not_leak(skb);
+ memcpy(skb_put(skb, totalpacketlen),
+ &reserved_page_packet, totalpacketlen);
+
+ if (_rtl88e_cmd_send_packet(hw, skb)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "Set RSVD page location to Fw.\n");
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3);
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
+ sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+ } else
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Set RSVD page location to Fw FAIL!!!!!!.\n");
+}
+
+/*Shoud check FW support p2p or not.*/
+static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
+{
+ u8 u1_ctwindow_period[1] = {ctwindow};
+
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+}
+
+void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
+ struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+ u8 i;
+ u16 ctwindow;
+ u32 start_time, tsf_low;
+
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+ memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+ break;
+ case P2P_PS_ENABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+ /* update CTWindow value. */
+ if (p2pinfo->ctwindow > 0) {
+ p2p_ps_offload->ctwindow_en = 1;
+ ctwindow = p2pinfo->ctwindow;
+ rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
+ }
+ /* hw only support 2 set of NoA */
+ for (i = 0; i < p2pinfo->noa_num; i++) {
+ /* To control the register setting for which NOA*/
+ rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+ if (i == 0)
+ p2p_ps_offload->noa0_en = 1;
+ else
+ p2p_ps_offload->noa1_en = 1;
+
+ /* config P2P NoA Descriptor Register */
+ rtl_write_dword(rtlpriv, 0x5E0,
+ p2pinfo->noa_duration[i]);
+ rtl_write_dword(rtlpriv, 0x5E4,
+ p2pinfo->noa_interval[i]);
+
+ /*Get Current TSF value */
+ tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ start_time = p2pinfo->noa_start_time[i];
+ if (p2pinfo->noa_count_type[i] != 1) {
+ while (start_time <= (tsf_low + (50 * 1024))) {
+ start_time += p2pinfo->noa_interval[i];
+ if (p2pinfo->noa_count_type[i] != 255)
+ p2pinfo->noa_count_type[i]--;
+ }
+ }
+ rtl_write_dword(rtlpriv, 0x5E8, start_time);
+ rtl_write_dword(rtlpriv, 0x5EC,
+ p2pinfo->noa_count_type[i]);
+ }
+
+ if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+ /* rst p2p circuit */
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+ p2p_ps_offload->offload_en = 1;
+
+ if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+ p2p_ps_offload->role = 1;
+ p2p_ps_offload->allstasleep = 0;
+ } else {
+ p2p_ps_offload->role = 0;
+ }
+
+ p2p_ps_offload->discovery = 0;
+ }
+ break;
+ case P2P_PS_SCAN:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+ p2p_ps_offload->discovery = 1;
+ break;
+ case P2P_PS_SCAN_DONE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+ p2p_ps_offload->discovery = 0;
+ p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+ break;
+ default:
+ break;
+ }
+
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
+ (u8 *)p2p_ps_offload);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h
new file mode 100644
index 000000000000..854a9875cd5f
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h
@@ -0,0 +1,301 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C__FW__H__
+#define __RTL92C__FW__H__
+
+#define FW_8192C_SIZE 0x8000
+#define FW_8192C_START_ADDRESS 0x1000
+#define FW_8192C_END_ADDRESS 0x5FFF
+#define FW_8192C_PAGE_SIZE 4096
+#define FW_8192C_POLLING_DELAY 5
+#define FW_8192C_POLLING_TIMEOUT_COUNT 3000
+
+#define IS_FW_HEADER_EXIST(_pfwhdr) \
+ ((_pfwhdr->signature&0xFFFF) == 0x88E1)
+#define USE_OLD_WOWLAN_DEBUG_FW 0
+
+#define H2C_88E_RSVDPAGE_LOC_LEN 5
+#define H2C_88E_PWEMODE_LENGTH 5
+#define H2C_88E_JOINBSSRPT_LENGTH 1
+#define H2C_88E_AP_OFFLOAD_LENGTH 3
+#define H2C_88E_WOWLAN_LENGTH 3
+#define H2C_88E_KEEP_ALIVE_CTRL_LENGTH 3
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define H2C_88E_REMOTE_WAKE_CTRL_LEN 1
+#else
+#define H2C_88E_REMOTE_WAKE_CTRL_LEN 3
+#endif
+#define H2C_88E_AOAC_GLOBAL_INFO_LEN 2
+#define H2C_88E_AOAC_RSVDPAGE_LOC_LEN 7
+
+/* Fw PS state for RPWM.
+ * BIT[2:0] = HW state
+ * BIT[3] = Protocol PS state, 1: register active state, 0: register sleep state
+ * BIT[4] = sub-state
+ */
+#define FW_PS_GO_ON BIT(0)
+#define FW_PS_TX_NULL BIT(1)
+#define FW_PS_RF_ON BIT(2)
+#define FW_PS_REGISTER_ACTIVE BIT(3)
+
+#define FW_PS_DPS BIT(0)
+#define FW_PS_LCLK (FW_PS_DPS)
+#define FW_PS_RF_OFF BIT(1)
+#define FW_PS_ALL_ON BIT(2)
+#define FW_PS_ST_ACTIVE BIT(3)
+#define FW_PS_ISR_ENABLE BIT(4)
+#define FW_PS_IMR_ENABLE BIT(5)
+
+
+#define FW_PS_ACK BIT(6)
+#define FW_PS_TOGGLE BIT(7)
+
+ /* 88E RPWM value*/
+ /* BIT[0] = 1: 32k, 0: 40M*/
+#define FW_PS_CLOCK_OFF BIT(0) /* 32k*/
+#define FW_PS_CLOCK_ON 0 /*40M*/
+
+#define FW_PS_STATE_MASK (0x0F)
+#define FW_PS_STATE_HW_MASK (0x07)
+/*ISR_ENABLE, IMR_ENABLE, and PS mode should be inherited.*/
+#define FW_PS_STATE_INT_MASK (0x3F)
+
+#define FW_PS_STATE(x) (FW_PS_STATE_MASK & (x))
+#define FW_PS_STATE_HW(x) (FW_PS_STATE_HW_MASK & (x))
+#define FW_PS_STATE_INT(x) (FW_PS_STATE_INT_MASK & (x))
+#define FW_PS_ISR_VAL(x) ((x) & 0x70)
+#define FW_PS_IMR_MASK(x) ((x) & 0xDF)
+#define FW_PS_KEEP_IMR(x) ((x) & 0x20)
+
+#define FW_PS_STATE_S0 (FW_PS_DPS)
+#define FW_PS_STATE_S1 (FW_PS_LCLK)
+#define FW_PS_STATE_S2 (FW_PS_RF_OFF)
+#define FW_PS_STATE_S3 (FW_PS_ALL_ON)
+#define FW_PS_STATE_S4 ((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON))
+
+#define FW_PS_STATE_ALL_ON_88E (FW_PS_CLOCK_ON)
+#define FW_PS_STATE_RF_ON_88E (FW_PS_CLOCK_ON)
+#define FW_PS_STATE_RF_OFF_88E (FW_PS_CLOCK_ON)
+#define FW_PS_STATE_RF_OFF_LOW_PWR_88E (FW_PS_CLOCK_OFF)
+
+#define FW_PS_STATE_ALL_ON_92C (FW_PS_STATE_S4)
+#define FW_PS_STATE_RF_ON_92C (FW_PS_STATE_S3)
+#define FW_PS_STATE_RF_OFF_92C (FW_PS_STATE_S2)
+#define FW_PS_STATE_RF_OFF_LOW_PWR_92C (FW_PS_STATE_S1)
+
+/* For 88E H2C PwrMode Cmd ID 5.*/
+#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define FW_PWR_STATE_RF_OFF 0
+
+#define FW_PS_IS_ACK(x) ((x) & FW_PS_ACK)
+#define FW_PS_IS_CLK_ON(x) ((x) & (FW_PS_RF_OFF | FW_PS_ALL_ON))
+#define FW_PS_IS_RF_ON(x) ((x) & (FW_PS_ALL_ON))
+#define FW_PS_IS_ACTIVE(x) ((x) & (FW_PS_ST_ACTIVE))
+#define FW_PS_IS_CPWM_INT(x) ((x) & 0x40)
+
+#define FW_CLR_PS_STATE(x) ((x) = ((x) & (0xF0)))
+
+#define IS_IN_LOW_POWER_STATE_88E(fwpsstate) \
+ (FW_PS_STATE(fwpsstate) == FW_PS_CLOCK_OFF)
+
+#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define FW_PWR_STATE_RF_OFF 0
+
+struct rtl92c_firmware_header {
+ u16 signature;
+ u8 category;
+ u8 function;
+ u16 version;
+ u8 subversion;
+ u8 rsvd1;
+ u8 month;
+ u8 date;
+ u8 hour;
+ u8 minute;
+ u16 ramcodesize;
+ u16 rsvd2;
+ u32 svnindex;
+ u32 rsvd3;
+ u32 rsvd4;
+ u32 rsvd5;
+};
+
+enum rtl8192c_h2c_cmd {
+ H2C_88E_RSVDPAGE = 0,
+ H2C_88E_JOINBSSRPT = 1,
+ H2C_88E_SCAN = 2,
+ H2C_88E_KEEP_ALIVE_CTRL = 3,
+ H2C_88E_DISCONNECT_DECISION = 4,
+#if (USE_OLD_WOWLAN_DEBUG_FW == 1)
+ H2C_88E_WO_WLAN = 5,
+#endif
+ H2C_88E_INIT_OFFLOAD = 6,
+#if (USE_OLD_WOWLAN_DEBUG_FW == 1)
+ H2C_88E_REMOTE_WAKE_CTRL = 7,
+#endif
+ H2C_88E_AP_OFFLOAD = 8,
+ H2C_88E_BCN_RSVDPAGE = 9,
+ H2C_88E_PROBERSP_RSVDPAGE = 10,
+
+ H2C_88E_SETPWRMODE = 0x20,
+ H2C_88E_PS_TUNING_PARA = 0x21,
+ H2C_88E_PS_TUNING_PARA2 = 0x22,
+ H2C_88E_PS_LPS_PARA = 0x23,
+ H2C_88E_P2P_PS_OFFLOAD = 024,
+
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+ H2C_88E_WO_WLAN = 0x80,
+ H2C_88E_REMOTE_WAKE_CTRL = 0x81,
+ H2C_88E_AOAC_GLOBAL_INFO = 0x82,
+ H2C_88E_AOAC_RSVDPAGE = 0x83,
+#endif
+ /* Not defined in new 88E H2C CMD Format */
+ H2C_88E_RA_MASK,
+ H2C_88E_SELECTIVE_SUSPEND_ROF_CMD,
+ H2C_88E_P2P_PS_MODE,
+ H2C_88E_PSD_RESULT,
+ /*Not defined CTW CMD for P2P yet*/
+ H2C_88E_P2P_PS_CTW_CMD,
+ MAX_88E_H2CCMD
+};
+
+#define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
+
+#define SET_88E_H2CCMD_WOWLAN_FUNC_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 2, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 3, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_ALL_PKT_DROP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 4, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_GPIO_ACTIVE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 5, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_REKEY_WAKE_UP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 6, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 7, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_GPIONUM(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_88E_H2CCMD_WOWLAN_GPIO_DURATION(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+
+
+#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_RLBM(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 4, __value)
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 4, 4, __value)
+#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __value)
+#define GET_88E_H2CCMD_PWRMODE_PARM_MODE(__cmd) \
+ LE_BITS_TO_1BYTE(__cmd, 0, 8)
+
+#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+/* AP_OFFLOAD */
+#define SET_H2CCMD_AP_OFFLOAD_ON(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_HIDDEN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_DENYANY(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_WAKEUP_EVT_RPT(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+
+/* Keep Alive Control*/
+#define SET_88E_H2CCMD_KEEP_ALIVE_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_88E_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_88E_H2CCMD_KEEP_ALIVE_PERIOD(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+
+/*REMOTE_WAKE_CTRL */
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_EN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 2, 1, __value)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 3, 1, __value)
+#else
+#define SET_88E_H2_REM_WAKE_ENC_ALG(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GROUP_ENC_ALG(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#endif
+
+/* GTK_OFFLOAD */
+#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+
+/* AOAC_RSVDPAGE_LOC */
+#define SET_88E_H2CCMD_AOAC_RSVD_LOC_REM_WAKE_CTRL_INFO(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd), 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __value)
+
+int rtl88e_download_fw(struct ieee80211_hw *hw,
+ bool buse_wake_on_wlan_fw);
+void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+ u32 cmd_len, u8 *p_cmdbuffer);
+void rtl88e_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
+ u8 mstatus);
+void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw, u8 enable);
+void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
+void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
new file mode 100644
index 000000000000..bcff49730a4e
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
@@ -0,0 +1,2530 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "led.h"
+#include "hw.h"
+#include "pwrseqcmd.h"
+#include "pwrseq.h"
+
+#define LLT_CONFIG 5
+
+static void _rtl88ee_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+ u8 set_bits, u8 clear_bits)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpci->reg_bcn_ctrl_val |= set_bits;
+ rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
+
+ rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+}
+
+static void _rtl88ee_stop_tx_beacon(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp1byte;
+
+ tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6)));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64);
+ tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+ tmp1byte &= ~(BIT(0));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl88ee_resume_tx_beacon(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp1byte;
+
+ tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+ tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+ tmp1byte |= BIT(0);
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl88ee_enable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(1));
+}
+
+static void _rtl88ee_return_beacon_queue_skb(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ while (skb_queue_len(&ring->queue)) {
+ struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+ struct sk_buff *skb = __skb_dequeue(&ring->queue);
+
+ pci_unmap_single(rtlpci->pdev,
+ rtlpriv->cfg->ops->get_desc(
+ (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+ skb->len, PCI_DMA_TODEVICE);
+ kfree_skb(skb);
+ ring->idx = (ring->idx + 1) % ring->entries;
+ }
+}
+
+static void _rtl88ee_disable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(1), 0);
+}
+
+static void _rtl88ee_set_fw_clock_on(struct ieee80211_hw *hw,
+ u8 rpwm_val, bool need_turn_off_ckk)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool support_remote_wake_up;
+ u32 count = 0, isr_regaddr, content;
+ bool schedule_timer = need_turn_off_ckk;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+ (u8 *)(&support_remote_wake_up));
+ if (!rtlhal->fw_ready)
+ return;
+ if (!rtlpriv->psc.fw_current_inpsmode)
+ return;
+
+ while (1) {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (rtlhal->fw_clk_change_in_progress) {
+ while (rtlhal->fw_clk_change_in_progress) {
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ udelay(100);
+ if (++count > 1000)
+ return;
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ }
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ } else {
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ }
+ }
+
+ if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) {
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ if (FW_PS_IS_ACK(rpwm_val)) {
+ isr_regaddr = REG_HISR;
+ content = rtl_read_dword(rtlpriv, isr_regaddr);
+ while (!(content & IMR_CPWM) && (count < 500)) {
+ udelay(50);
+ count++;
+ content = rtl_read_dword(rtlpriv, isr_regaddr);
+ }
+
+ if (content & IMR_CPWM) {
+ rtl_write_word(rtlpriv, isr_regaddr, 0x0100);
+ rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_88E;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "Receive CPWM INT!!! Set pHalData->FwPSState = %X\n",
+ rtlhal->fw_ps_state);
+ }
+ }
+
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (schedule_timer) {
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ }
+ } else {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ }
+}
+
+static void _rtl88ee_set_fw_clock_off(struct ieee80211_hw *hw,
+ u8 rpwm_val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ enum rf_pwrstate rtstate;
+ bool schedule_timer = false;
+ u8 queue;
+
+ if (!rtlhal->fw_ready)
+ return;
+ if (!rtlpriv->psc.fw_current_inpsmode)
+ return;
+ if (!rtlhal->allow_sw_to_change_hwclc)
+ return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, (u8 *)(&rtstate));
+ if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF)
+ return;
+
+ for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) {
+ ring = &rtlpci->tx_ring[queue];
+ if (skb_queue_len(&ring->queue)) {
+ schedule_timer = true;
+ break;
+ }
+ }
+
+ if (schedule_timer) {
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ return;
+ }
+
+ if (FW_PS_STATE(rtlhal->fw_ps_state) !=
+ FW_PS_STATE_RF_OFF_LOW_PWR_88E) {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (!rtlhal->fw_clk_change_in_progress) {
+ rtlhal->fw_clk_change_in_progress = true;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
+ rtl_write_word(rtlpriv, REG_HISR, 0x0100);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ } else {
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ }
+ }
+}
+
+static void _rtl88ee_set_fw_ps_rf_on(struct ieee80211_hw *hw)
+{
+ u8 rpwm_val = 0;
+
+ rpwm_val |= (FW_PS_STATE_RF_OFF_88E | FW_PS_ACK);
+ _rtl88ee_set_fw_clock_on(hw, rpwm_val, true);
+}
+
+static void _rtl88ee_set_fw_ps_rf_off_low_power(struct ieee80211_hw *hw)
+{
+ u8 rpwm_val = 0;
+
+ rpwm_val |= FW_PS_STATE_RF_OFF_LOW_PWR_88E;
+ _rtl88ee_set_fw_clock_off(hw, rpwm_val);
+}
+
+void rtl88ee_fw_clk_off_timer_callback(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+
+ _rtl88ee_set_fw_ps_rf_off_low_power(hw);
+}
+
+static void _rtl88ee_fwlps_leave(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool fw_current_inps = false;
+ u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE;
+
+ if (ppsc->low_power_enable) {
+ rpwm_val = (FW_PS_STATE_ALL_ON_88E|FW_PS_ACK);/* RF on */
+ _rtl88ee_set_fw_clock_on(hw, rpwm_val, false);
+ rtlhal->allow_sw_to_change_hwclc = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ } else {
+ rpwm_val = FW_PS_STATE_ALL_ON_88E; /* RF on */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+}
+
+static void _rtl88ee_fwlps_enter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool fw_current_inps = true;
+ u8 rpwm_val;
+
+ if (ppsc->low_power_enable) {
+ rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR_88E; /* RF off */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+ rtlhal->allow_sw_to_change_hwclc = true;
+ _rtl88ee_set_fw_clock_off(hw, rpwm_val);
+ } else {
+ rpwm_val = FW_PS_STATE_RF_OFF_88E; /* RF off */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ }
+}
+
+void rtl88ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ switch (variable) {
+ case HW_VAR_RCR:
+ *((u32 *)(val)) = rtlpci->receive_config;
+ break;
+ case HW_VAR_RF_STATE:
+ *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+ break;
+ case HW_VAR_FWLPS_RF_ON:{
+ enum rf_pwrstate rfstate;
+ u32 val_rcr;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE,
+ (u8 *)(&rfstate));
+ if (rfstate == ERFOFF) {
+ *((bool *)(val)) = true;
+ } else {
+ val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+ val_rcr &= 0x00070000;
+ if (val_rcr)
+ *((bool *)(val)) = false;
+ else
+ *((bool *)(val)) = true;
+ }
+ break;
+ }
+ case HW_VAR_FW_PSMODE_STATUS:
+ *((bool *)(val)) = ppsc->fw_current_inpsmode;
+ break;
+ case HW_VAR_CORRECT_TSF:{
+ u64 tsf;
+ u32 *ptsf_low = (u32 *)&tsf;
+ u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+ *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+ *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ *((u64 *)(val)) = tsf;
+ break; }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process %x\n", variable);
+ break;
+ }
+}
+
+void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 idx;
+
+ switch (variable) {
+ case HW_VAR_ETHER_ADDR:
+ for (idx = 0; idx < ETH_ALEN; idx++)
+ rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]);
+ break;
+ case HW_VAR_BASIC_RATE:{
+ u16 rate_cfg = ((u16 *)val)[0];
+ u8 rate_index = 0;
+ rate_cfg = rate_cfg & 0x15f;
+ rate_cfg |= 0x01;
+ rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
+ rtl_write_byte(rtlpriv, REG_RRSR + 1, (rate_cfg >> 8) & 0xff);
+ while (rate_cfg > 0x1) {
+ rate_cfg = (rate_cfg >> 1);
+ rate_index++;
+ }
+ rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, rate_index);
+ break; }
+ case HW_VAR_BSSID:
+ for (idx = 0; idx < ETH_ALEN; idx++)
+ rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]);
+ break;
+ case HW_VAR_SIFS:
+ rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+ rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
+
+ rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+ rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+ if (!mac->ht_enable)
+ rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, 0x0e0e);
+ else
+ rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+ *((u16 *)val));
+ break;
+ case HW_VAR_SLOT_TIME:{
+ u8 e_aci;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "HW_VAR_SLOT_TIME %x\n", val[0]);
+
+ rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+ for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ (u8 *)(&e_aci));
+ }
+ break; }
+ case HW_VAR_ACK_PREAMBLE:{
+ u8 reg_tmp;
+ u8 short_preamble = (bool) (*(u8 *)val);
+ reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL+2);
+ if (short_preamble) {
+ reg_tmp |= 0x02;
+ rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+ } else {
+ reg_tmp |= 0xFD;
+ rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+ }
+ break; }
+ case HW_VAR_WPA_CONFIG:
+ rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+ break;
+ case HW_VAR_AMPDU_MIN_SPACE:{
+ u8 min_spacing_to_set;
+ u8 sec_min_space;
+
+ min_spacing_to_set = *((u8 *)val);
+ if (min_spacing_to_set <= 7) {
+ sec_min_space = 0;
+
+ if (min_spacing_to_set < sec_min_space)
+ min_spacing_to_set = sec_min_space;
+
+ mac->min_space_cfg = ((mac->min_space_cfg &
+ 0xf8) | min_spacing_to_set);
+
+ *val = min_spacing_to_set;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+ mac->min_space_cfg);
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ }
+ break; }
+ case HW_VAR_SHORTGI_DENSITY:{
+ u8 density_to_set;
+
+ density_to_set = *((u8 *)val);
+ mac->min_space_cfg |= (density_to_set << 3);
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+ mac->min_space_cfg);
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ break; }
+ case HW_VAR_AMPDU_FACTOR:{
+ u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+ u8 factor;
+ u8 *reg = NULL;
+ u8 id = 0;
+
+ reg = regtoset_normal;
+
+ factor = *((u8 *)val);
+ if (factor <= 3) {
+ factor = (1 << (factor + 2));
+ if (factor > 0xf)
+ factor = 0xf;
+
+ for (id = 0; id < 4; id++) {
+ if ((reg[id] & 0xf0) > (factor << 4))
+ reg[id] = (reg[id] & 0x0f) |
+ (factor << 4);
+
+ if ((reg[id] & 0x0f) > factor)
+ reg[id] = (reg[id] & 0xf0) | (factor);
+
+ rtl_write_byte(rtlpriv, (REG_AGGLEN_LMT + id),
+ reg[id]);
+ }
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_AMPDU_FACTOR: %#x\n", factor);
+ }
+ break; }
+ case HW_VAR_AC_PARAM:{
+ u8 e_aci = *((u8 *)val);
+ rtl88e_dm_init_edca_turbo(hw);
+
+ if (rtlpci->acm_method != eAcmWay2_SW)
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
+ (u8 *)(&e_aci));
+ break; }
+ case HW_VAR_ACM_CTRL:{
+ u8 e_aci = *((u8 *)val);
+ union aci_aifsn *p_aci_aifsn =
+ (union aci_aifsn *)(&(mac->ac[0].aifs));
+ u8 acm = p_aci_aifsn->f.acm;
+ u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+
+ acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+ if (acm) {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl |= ACMHW_BEQEN;
+ break;
+ case AC2_VI:
+ acm_ctrl |= ACMHW_VIQEN;
+ break;
+ case AC3_VO:
+ acm_ctrl |= ACMHW_VOQEN;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n",
+ acm);
+ break;
+ }
+ } else {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl &= (~ACMHW_BEQEN);
+ break;
+ case AC2_VI:
+ acm_ctrl &= (~ACMHW_VIQEN);
+ break;
+ case AC3_VO:
+ acm_ctrl &= (~ACMHW_BEQEN);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+ "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n",
+ acm_ctrl);
+ rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+ break; }
+ case HW_VAR_RCR:
+ rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]);
+ rtlpci->receive_config = ((u32 *)(val))[0];
+ break;
+ case HW_VAR_RETRY_LIMIT:{
+ u8 retry_limit = ((u8 *)(val))[0];
+
+ rtl_write_word(rtlpriv, REG_RL,
+ retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+ retry_limit << RETRY_LIMIT_LONG_SHIFT);
+ break; }
+ case HW_VAR_DUAL_TSF_RST:
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
+ break;
+ case HW_VAR_EFUSE_BYTES:
+ rtlefuse->efuse_usedbytes = *((u16 *)val);
+ break;
+ case HW_VAR_EFUSE_USAGE:
+ rtlefuse->efuse_usedpercentage = *((u8 *)val);
+ break;
+ case HW_VAR_IO_CMD:
+ rtl88e_phy_set_io_cmd(hw, (*(enum io_type *)val));
+ break;
+ case HW_VAR_SET_RPWM:{
+ u8 rpwm_val;
+
+ rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+ udelay(1);
+
+ if (rpwm_val & BIT(7)) {
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+ (*(u8 *)val));
+ } else {
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+ ((*(u8 *)val) | BIT(7)));
+ }
+ break; }
+ case HW_VAR_H2C_FW_PWRMODE:
+ rtl88e_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+ break;
+ case HW_VAR_FW_PSMODE_STATUS:
+ ppsc->fw_current_inpsmode = *((bool *)val);
+ break;
+ case HW_VAR_RESUME_CLK_ON:
+ _rtl88ee_set_fw_ps_rf_on(hw);
+ break;
+ case HW_VAR_FW_LPS_ACTION:{
+ bool enter_fwlps = *((bool *)val);
+
+ if (enter_fwlps)
+ _rtl88ee_fwlps_enter(hw);
+ else
+ _rtl88ee_fwlps_leave(hw);
+ break; }
+ case HW_VAR_H2C_FW_JOINBSSRPT:{
+ u8 mstatus = (*(u8 *)val);
+ u8 tmp, tmp_reg422, uval;
+ u8 count = 0, dlbcn_count = 0;
+ bool recover = false;
+
+ if (mstatus == RT_MEDIA_CONNECT) {
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+
+ tmp = rtl_read_byte(rtlpriv, REG_CR + 1);
+ rtl_write_byte(rtlpriv, REG_CR + 1, (tmp | BIT(0)));
+
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(3));
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+ tmp_reg422 = rtl_read_byte(rtlpriv,
+ REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+ tmp_reg422 & (~BIT(6)));
+ if (tmp_reg422 & BIT(6))
+ recover = true;
+
+ do {
+ uval = rtl_read_byte(rtlpriv, REG_TDECTRL+2);
+ rtl_write_byte(rtlpriv, REG_TDECTRL+2,
+ (uval | BIT(0)));
+ _rtl88ee_return_beacon_queue_skb(hw);
+
+ rtl88e_set_fw_rsvdpagepkt(hw, 0);
+ uval = rtl_read_byte(rtlpriv, REG_TDECTRL+2);
+ count = 0;
+ while (!(uval & BIT(0)) && count < 20) {
+ count++;
+ udelay(10);
+ uval = rtl_read_byte(rtlpriv,
+ REG_TDECTRL+2);
+ }
+ dlbcn_count++;
+ } while (!(uval & BIT(0)) && dlbcn_count < 5);
+
+ if (uval & BIT(0))
+ rtl_write_byte(rtlpriv, REG_TDECTRL+2, BIT(0));
+
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+ if (recover) {
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+ tmp_reg422);
+ }
+ rtl_write_byte(rtlpriv, REG_CR + 1, (tmp & ~(BIT(0))));
+ }
+ rtl88e_set_fw_joinbss_report_cmd(hw, (*(u8 *)val));
+ break; }
+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+ rtl88e_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ break;
+ case HW_VAR_AID:{
+ u16 u2btmp;
+ u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+ u2btmp &= 0xC000;
+ rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp |
+ mac->assoc_id));
+ break; }
+ case HW_VAR_CORRECT_TSF:{
+ u8 btype_ibss = ((u8 *)(val))[0];
+
+ if (btype_ibss == true)
+ _rtl88ee_stop_tx_beacon(hw);
+
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+ rtl_write_dword(rtlpriv, REG_TSFTR,
+ (u32) (mac->tsf & 0xffffffff));
+ rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+ (u32) ((mac->tsf >> 32) & 0xffffffff));
+
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+ if (btype_ibss == true)
+ _rtl88ee_resume_tx_beacon(hw);
+ break; }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process %x\n", variable);
+ break;
+ }
+}
+
+static bool _rtl88ee_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool status = true;
+ long count = 0;
+ u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) |
+ _LLT_OP(_LLT_WRITE_ACCESS);
+
+ rtl_write_dword(rtlpriv, REG_LLT_INIT, value);
+
+ do {
+ value = rtl_read_dword(rtlpriv, REG_LLT_INIT);
+ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+ break;
+
+ if (count > POLLING_LLT_THRESHOLD) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Failed to polling write LLT done at address %d!\n",
+ address);
+ status = false;
+ break;
+ }
+ } while (++count);
+
+ return status;
+}
+
+static bool _rtl88ee_llt_table_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ unsigned short i;
+ u8 txpktbuf_bndy;
+ u8 maxpage;
+ bool status;
+
+ maxpage = 0xAF;
+ txpktbuf_bndy = 0xAB;
+
+ rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x01);
+ rtl_write_dword(rtlpriv, REG_RQPN, 0x80730d29);
+
+
+ rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x25FF0000 | txpktbuf_bndy));
+ rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
+
+ rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+ rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+
+ rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy);
+ rtl_write_byte(rtlpriv, REG_PBP, 0x11);
+ rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
+
+ for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+ status = _rtl88ee_llt_write(hw, i, i + 1);
+ if (true != status)
+ return status;
+ }
+
+ status = _rtl88ee_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+ if (true != status)
+ return status;
+
+ for (i = txpktbuf_bndy; i < maxpage; i++) {
+ status = _rtl88ee_llt_write(hw, i, (i + 1));
+ if (true != status)
+ return status;
+ }
+
+ status = _rtl88ee_llt_write(hw, maxpage, txpktbuf_bndy);
+ if (true != status)
+ return status;
+
+ return true;
+}
+
+static void _rtl88ee_gen_refresh_led_state(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+ if (rtlpriv->rtlhal.up_first_time)
+ return;
+
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+ rtl88ee_sw_led_on(hw, pLed0);
+ else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
+ rtl88ee_sw_led_on(hw, pLed0);
+ else
+ rtl88ee_sw_led_off(hw, pLed0);
+}
+
+static bool _rtl88ee_init_mac(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 bytetmp;
+ u16 wordtmp;
+
+ /*Disable XTAL OUTPUT for power saving. YJ, add, 111206. */
+ bytetmp = rtl_read_byte(rtlpriv, REG_XCK_OUT_CTRL) & (~BIT(0));
+ rtl_write_byte(rtlpriv, REG_XCK_OUT_CTRL, bytetmp);
+ /*Auto Power Down to CHIP-off State*/
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) & (~BIT(7));
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp);
+
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+ /* HW Power on sequence */
+ if (!rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
+ PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
+ Rtl8188E_NIC_ENABLE_FLOW)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "init MAC Fail as rtl88_hal_pwrseqcmdparsing\n");
+ return false;
+ }
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO) | BIT(4);
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO, bytetmp);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+2);
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+2, bytetmp|BIT(2));
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_WATCH_DOG+1);
+ rtl_write_byte(rtlpriv, REG_WATCH_DOG+1, bytetmp|BIT(7));
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL_EXT+1);
+ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL_EXT+1, bytetmp|BIT(1));
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_TX_RPT_CTRL);
+ rtl_write_byte(rtlpriv, REG_TX_RPT_CTRL, bytetmp|BIT(1)|BIT(0));
+ rtl_write_byte(rtlpriv, REG_TX_RPT_CTRL+1, 2);
+ rtl_write_word(rtlpriv, REG_TX_RPT_TIME, 0xcdf0);
+
+ /*Add for wake up online*/
+ bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR);
+
+ rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp|BIT(3));
+ bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG+1);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG+1, (bytetmp & (~BIT(4))));
+ rtl_write_byte(rtlpriv, 0x367, 0x80);
+
+ rtl_write_word(rtlpriv, REG_CR, 0x2ff);
+ rtl_write_byte(rtlpriv, REG_CR+1, 0x06);
+ rtl_write_byte(rtlpriv, REG_CR+2, 0x00);
+
+ if (!rtlhal->mac_func_enable) {
+ if (_rtl88ee_llt_table_init(hw) == false) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "LLT table init fail\n");
+ return false;
+ }
+ }
+
+
+ rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
+ rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff);
+
+ wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL);
+ wordtmp &= 0xf;
+ wordtmp |= 0xE771;
+ rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
+
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+ rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xffff);
+ rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config);
+
+ rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+ ((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+ (u64) rtlpci->tx_ring[MGNT_QUEUE].dma &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+ (u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+ (u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+ (u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+ (u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_HQ_DESA,
+ (u64) rtlpci->tx_ring[HIGH_QUEUE].dma &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_RX_DESA,
+ (u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma &
+ DMA_BIT_MASK(32));
+
+ /* if we want to support 64 bit DMA, we should set it here,
+ * but at the moment we do not support 64 bit DMA
+ */
+
+ rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
+
+ rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0);/*Enable RX DMA */
+
+ if (rtlhal->earlymode_enable) {/*Early mode enable*/
+ bytetmp = rtl_read_byte(rtlpriv, REG_EARLY_MODE_CONTROL);
+ bytetmp |= 0x1f;
+ rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, bytetmp);
+ rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL+3, 0x81);
+ }
+ _rtl88ee_gen_refresh_led_state(hw);
+ return true;
+}
+
+static void _rtl88ee_hw_configure(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 reg_prsr;
+
+ reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+ rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
+ rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF);
+}
+
+static void _rtl88ee_enable_aspm_back_door(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 tmp1byte = 0;
+ u32 tmp4Byte = 0, count;
+
+ rtl_write_word(rtlpriv, 0x354, 0x8104);
+ rtl_write_word(rtlpriv, 0x358, 0x24);
+
+ rtl_write_word(rtlpriv, 0x350, 0x70c);
+ rtl_write_byte(rtlpriv, 0x352, 0x2);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count = 0;
+ while (tmp1byte && count < 20) {
+ udelay(10);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count++;
+ }
+ if (0 == tmp1byte) {
+ tmp4Byte = rtl_read_dword(rtlpriv, 0x34c);
+ rtl_write_dword(rtlpriv, 0x348, tmp4Byte|BIT(31));
+ rtl_write_word(rtlpriv, 0x350, 0xf70c);
+ rtl_write_byte(rtlpriv, 0x352, 0x1);
+ }
+
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count = 0;
+ while (tmp1byte && count < 20) {
+ udelay(10);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count++;
+ }
+
+ rtl_write_word(rtlpriv, 0x350, 0x718);
+ rtl_write_byte(rtlpriv, 0x352, 0x2);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count = 0;
+ while (tmp1byte && count < 20) {
+ udelay(10);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count++;
+ }
+ if (ppsc->support_backdoor || (0 == tmp1byte)) {
+ tmp4Byte = rtl_read_dword(rtlpriv, 0x34c);
+ rtl_write_dword(rtlpriv, 0x348, tmp4Byte|BIT(11)|BIT(12));
+ rtl_write_word(rtlpriv, 0x350, 0xf718);
+ rtl_write_byte(rtlpriv, 0x352, 0x1);
+ }
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count = 0;
+ while (tmp1byte && count < 20) {
+ udelay(10);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count++;
+ }
+}
+
+void rtl88ee_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 sec_reg_value;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
+ rtlpriv->sec.pairwise_enc_algorithm,
+ rtlpriv->sec.group_enc_algorithm);
+
+ if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "not open hw encryption\n");
+ return;
+ }
+ sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
+
+ if (rtlpriv->sec.use_defaultkey) {
+ sec_reg_value |= SCR_TXUSEDK;
+ sec_reg_value |= SCR_RXUSEDK;
+ }
+
+ sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
+
+ rtl_write_byte(rtlpriv, REG_CR + 1, 0x02);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "The SECR-value %x\n", sec_reg_value);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+}
+
+int rtl88ee_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ bool rtstatus = true;
+ int err = 0;
+ u8 tmp_u1b, u1byte;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Rtl8188EE hw init\n");
+ rtlpriv->rtlhal.being_init_adapter = true;
+ rtlpriv->intf_ops->disable_aspm(hw);
+
+ tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CLKR+1);
+ u1byte = rtl_read_byte(rtlpriv, REG_CR);
+ if ((tmp_u1b & BIT(3)) && (u1byte != 0 && u1byte != 0xEA)) {
+ rtlhal->mac_func_enable = true;
+ } else {
+ rtlhal->mac_func_enable = false;
+ rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_88E;
+ }
+
+ rtstatus = _rtl88ee_init_mac(hw);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+ err = 1;
+ return err;
+ }
+
+ err = rtl88e_download_fw(hw, false);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Failed to download FW. Init HW without FW now..\n");
+ err = 1;
+ rtlhal->fw_ready = false;
+ return err;
+ } else {
+ rtlhal->fw_ready = true;
+ }
+ /*fw related variable initialize */
+ rtlhal->last_hmeboxnum = 0;
+ rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_88E;
+ rtlhal->fw_clk_change_in_progress = false;
+ rtlhal->allow_sw_to_change_hwclc = false;
+ ppsc->fw_current_inpsmode = false;
+
+ rtl88e_phy_mac_config(hw);
+ /* because last function modifies RCR, we update
+ * rcr var here, or TP will be unstable for receive_config
+ * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx
+ * RCR_APP_ICV will cause mac80211 disassoc for cisco 1252
+ */
+ rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+ rtl88e_phy_bb_config(hw);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+
+ rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
+ rtl88e_phy_rf_config(hw);
+
+ rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
+ RF_CHNLBW, RFREG_OFFSET_MASK);
+ rtlphy->rfreg_chnlval[0] = rtlphy->rfreg_chnlval[0] & 0xfff00fff;
+
+ _rtl88ee_hw_configure(hw);
+ rtl_cam_reset_all_entry(hw);
+ rtl88ee_enable_hw_security_config(hw);
+
+ rtlhal->mac_func_enable = true;
+ ppsc->rfpwr_state = ERFON;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+ _rtl88ee_enable_aspm_back_door(hw);
+ rtlpriv->intf_ops->enable_aspm(hw);
+
+ if (ppsc->rfpwr_state == ERFON) {
+ if ((rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) ||
+ ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) &&
+ (rtlhal->oem_id == RT_CID_819x_HP))) {
+ rtl88e_phy_set_rfpath_switch(hw, true);
+ rtlpriv->dm.fat_table.rx_idle_ant = MAIN_ANT;
+ } else {
+ rtl88e_phy_set_rfpath_switch(hw, false);
+ rtlpriv->dm.fat_table.rx_idle_ant = AUX_ANT;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "rx idle ant %s\n",
+ (rtlpriv->dm.fat_table.rx_idle_ant == MAIN_ANT) ?
+ ("MAIN_ANT") : ("AUX_ANT"));
+
+ if (rtlphy->iqk_initialized) {
+ rtl88e_phy_iq_calibrate(hw, true);
+ } else {
+ rtl88e_phy_iq_calibrate(hw, false);
+ rtlphy->iqk_initialized = true;
+ }
+ rtl88e_dm_check_txpower_tracking(hw);
+ rtl88e_phy_lc_calibrate(hw);
+ }
+
+ tmp_u1b = efuse_read_1byte(hw, 0x1FA);
+ if (!(tmp_u1b & BIT(0))) {
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "PA BIAS path A\n");
+ }
+
+ if (!(tmp_u1b & BIT(4))) {
+ tmp_u1b = rtl_read_byte(rtlpriv, 0x16);
+ tmp_u1b &= 0x0F;
+ rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80);
+ udelay(10);
+ rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "under 1.5V\n");
+ }
+ rtl_write_byte(rtlpriv, REG_NAV_CTRL+2, ((30000+127)/128));
+ rtl88e_dm_init(hw);
+ rtlpriv->rtlhal.being_init_adapter = false;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "end of Rtl8188EE hw init %x\n",
+ err);
+ return 0;
+}
+
+static enum version_8188e _rtl88ee_read_chip_version(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ enum version_8188e version = VERSION_UNKNOWN;
+ u32 value32;
+
+ value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG);
+ if (value32 & TRP_VAUX_EN) {
+ version = (enum version_8188e) VERSION_TEST_CHIP_88E;
+ } else {
+ version = NORMAL_CHIP;
+ version = version | ((value32 & TYPE_ID) ? RF_TYPE_2T2R : 0);
+ version = version | ((value32 & VENDOR_ID) ?
+ CHIP_VENDOR_UMC : 0);
+ }
+
+ rtlphy->rf_type = RF_1T1R;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ?
+ "RF_2T2R" : "RF_1T1R");
+
+ return version;
+}
+
+static int _rtl88ee_set_media_status(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
+ enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+ bt_msr &= 0xfc;
+
+ if (type == NL80211_IFTYPE_UNSPECIFIED ||
+ type == NL80211_IFTYPE_STATION) {
+ _rtl88ee_stop_tx_beacon(hw);
+ _rtl88ee_enable_bcn_sub_func(hw);
+ } else if (type == NL80211_IFTYPE_ADHOC ||
+ type == NL80211_IFTYPE_AP ||
+ type == NL80211_IFTYPE_MESH_POINT) {
+ _rtl88ee_resume_tx_beacon(hw);
+ _rtl88ee_disable_bcn_sub_func(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+ type);
+ }
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bt_msr |= MSR_NOLINK;
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to NO LINK!\n");
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ bt_msr |= MSR_ADHOC;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to Ad Hoc!\n");
+ break;
+ case NL80211_IFTYPE_STATION:
+ bt_msr |= MSR_INFRA;
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to STA!\n");
+ break;
+ case NL80211_IFTYPE_AP:
+ bt_msr |= MSR_AP;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to AP!\n");
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ bt_msr |= MSR_ADHOC;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to Mesh Point!\n");
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Network type %d not support!\n", type);
+ return 1;
+ }
+
+ rtl_write_byte(rtlpriv, (MSR), bt_msr);
+ rtlpriv->cfg->ops->led_control(hw, ledaction);
+ if ((bt_msr & 0xfc) == MSR_AP)
+ rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
+ else
+ rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
+ return 0;
+}
+
+void rtl88ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u32 reg_rcr = rtlpci->receive_config;
+
+ if (rtlpriv->psc.rfpwr_state != ERFON)
+ return;
+
+ if (check_bssid == true) {
+ reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+ (u8 *)(&reg_rcr));
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(4));
+ } else if (check_bssid == false) {
+ reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(4), 0);
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_RCR, (u8 *)(&reg_rcr));
+ }
+}
+
+int rtl88ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (_rtl88ee_set_media_status(hw, type))
+ return -EOPNOTSUPP;
+
+ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+ if (type != NL80211_IFTYPE_AP &&
+ type != NL80211_IFTYPE_MESH_POINT)
+ rtl88ee_set_check_bssid(hw, true);
+ } else {
+ rtl88ee_set_check_bssid(hw, false);
+ }
+
+ return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
+void rtl88ee_set_qos(struct ieee80211_hw *hw, int aci)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl88e_dm_init_edca_turbo(hw);
+ switch (aci) {
+ case AC1_BK:
+ rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
+ break;
+ case AC0_BE:
+ break;
+ case AC2_VI:
+ rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
+ break;
+ case AC3_VO:
+ rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
+ break;
+ default:
+ RT_ASSERT(false, "invalid aci: %d !\n", aci);
+ break;
+ }
+}
+
+void rtl88ee_enable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
+ rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+ rtlpci->irq_enabled = true;
+ /* there are some C2H CMDs have been sent before system interrupt
+ * is enabled, e.g., C2H, CPWM.
+ * So we need to clear all C2H events that FW has notified, otherwise
+ * FW won't schedule any commands anymore.
+ */
+ rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0);
+ /*enable system interrupt*/
+ rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF);
+}
+
+void rtl88ee_disable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED);
+ rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED);
+ rtlpci->irq_enabled = false;
+ synchronize_irq(rtlpci->pdev->irq);
+}
+
+static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 u1b_tmp;
+ u32 count = 0;
+ rtlhal->mac_func_enable = false;
+ rtlpriv->intf_ops->enable_aspm(hw);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "POWER OFF adapter\n");
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_TX_RPT_CTRL);
+ rtl_write_byte(rtlpriv, REG_TX_RPT_CTRL, u1b_tmp & (~BIT(1)));
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ while (!(u1b_tmp & BIT(1)) && (count++ < 100)) {
+ udelay(10);
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ count++;
+ }
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0xFF);
+
+ rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+ PWR_INTF_PCI_MSK,
+ Rtl8188E_NIC_LPS_ENTER_FLOW);
+
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
+
+ if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->fw_ready)
+ rtl88e_firmware_selfreset(hw);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_32K_CTRL);
+ rtl_write_byte(rtlpriv, REG_32K_CTRL, (u1b_tmp & (~BIT(0))));
+
+ rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+ PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3))));
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp | BIT(3)));
+
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0E);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, GPIO_IN);
+ rtl_write_byte(rtlpriv, GPIO_OUT, u1b_tmp);
+ rtl_write_byte(rtlpriv, GPIO_IO_SEL, 0x7F);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL);
+ rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL, (u1b_tmp << 4) | u1b_tmp);
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL+1);
+ rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL+1, u1b_tmp | 0x0F);
+
+ rtl_write_dword(rtlpriv, REG_GPIO_IO_SEL_2+2, 0x00080808);
+}
+
+void rtl88ee_card_disable(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ enum nl80211_iftype opmode;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "RTL8188ee card disable\n");
+
+ mac->link_state = MAC80211_NOLINK;
+ opmode = NL80211_IFTYPE_UNSPECIFIED;
+
+ _rtl88ee_set_media_status(hw, opmode);
+
+ if (rtlpriv->rtlhal.driver_is_goingto_unload ||
+ ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ _rtl88ee_poweroff_adapter(hw);
+
+ /* after power off we should do iqk again */
+ rtlpriv->phy.iqk_initialized = false;
+}
+
+void rtl88ee_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+ rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+ *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1];
+ rtl_write_dword(rtlpriv, REG_HISRE, *p_intb);
+}
+
+void rtl88ee_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u16 bcn_interval, atim_window;
+
+ bcn_interval = mac->beacon_interval;
+ atim_window = 2; /*FIX MERGE */
+ rtl88ee_disable_interrupt(hw);
+ rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
+ rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+ rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
+ rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
+ rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
+ rtl_write_byte(rtlpriv, 0x606, 0x30);
+ rtlpci->reg_bcn_ctrl_val |= BIT(3);
+ rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+ /*rtl88ee_enable_interrupt(hw);*/
+}
+
+void rtl88ee_set_beacon_interval(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcn_interval = mac->beacon_interval;
+
+ RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
+ "beacon_interval:%d\n", bcn_interval);
+ /*rtl88ee_disable_interrupt(hw);*/
+ rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+ /*rtl88ee_enable_interrupt(hw);*/
+}
+
+void rtl88ee_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+ "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr);
+
+ rtl88ee_disable_interrupt(hw);
+ if (add_msr)
+ rtlpci->irq_mask[0] |= add_msr;
+ if (rm_msr)
+ rtlpci->irq_mask[0] &= (~rm_msr);
+ rtl88ee_enable_interrupt(hw);
+}
+
+static inline u8 get_chnl_group(u8 chnl)
+{
+ u8 group;
+
+ group = chnl / 3;
+ if (chnl == 14)
+ group = 5;
+
+ return group;
+}
+
+static void set_diff0_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ pwr2g->bw40_diff[path][i] = 0;
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->bw20_diff[path][i] = 0x02;
+ } else {
+ pwr2g->bw20_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ /*bit sign number to 8 bit sign number*/
+ if (pwr2g->bw20_diff[path][i] & BIT(3))
+ pwr2g->bw20_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->ofdm_diff[path][i] = 0x04;
+ } else {
+ pwr2g->ofdm_diff[path][i] = (hwinfo[eadr] & 0x0f);
+ /*bit sign number to 8 bit sign number*/
+ if (pwr2g->ofdm_diff[path][i] & BIT(3))
+ pwr2g->ofdm_diff[path][i] |= 0xF0;
+ }
+ pwr2g->cck_diff[path][i] = 0;
+}
+
+static void set_diff0_5g(struct txpower_info_5g *pwr5g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ pwr5g->bw40_diff[path][i] = 0;
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->bw20_diff[path][i] = 0;
+ } else {
+ pwr5g->bw20_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ /*bit sign number to 8 bit sign number*/
+ if (pwr5g->bw20_diff[path][i] & BIT(3))
+ pwr5g->bw20_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->ofdm_diff[path][i] = 0x04;
+ } else {
+ pwr5g->ofdm_diff[path][i] = (hwinfo[eadr] & 0x0f);
+ /*bit sign number to 8 bit sign number*/
+ if (pwr5g->ofdm_diff[path][i] & BIT(3))
+ pwr5g->ofdm_diff[path][i] |= 0xF0;
+ }
+}
+
+static void set_diff1_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->bw40_diff[path][i] = 0xFE;
+ } else {
+ pwr2g->bw40_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ if (pwr2g->bw40_diff[path][i] & BIT(3))
+ pwr2g->bw40_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->bw20_diff[path][i] = 0xFE;
+ } else {
+ pwr2g->bw20_diff[path][i] = (hwinfo[eadr]&0x0f);
+ if (pwr2g->bw20_diff[path][i] & BIT(3))
+ pwr2g->bw20_diff[path][i] |= 0xF0;
+ }
+}
+
+static void set_diff1_5g(struct txpower_info_5g *pwr5g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->bw40_diff[path][i] = 0xFE;
+ } else {
+ pwr5g->bw40_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ if (pwr5g->bw40_diff[path][i] & BIT(3))
+ pwr5g->bw40_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->bw20_diff[path][i] = 0xFE;
+ } else {
+ pwr5g->bw20_diff[path][i] = (hwinfo[eadr] & 0x0f);
+ if (pwr5g->bw20_diff[path][i] & BIT(3))
+ pwr5g->bw20_diff[path][i] |= 0xF0;
+ }
+}
+
+static void set_diff2_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->ofdm_diff[path][i] = 0xFE;
+ } else {
+ pwr2g->ofdm_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ if (pwr2g->ofdm_diff[path][i] & BIT(3))
+ pwr2g->ofdm_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->cck_diff[path][i] = 0xFE;
+ } else {
+ pwr2g->cck_diff[path][i] = (hwinfo[eadr]&0x0f);
+ if (pwr2g->cck_diff[path][i] & BIT(3))
+ pwr2g->cck_diff[path][i] |= 0xF0;
+ }
+}
+
+static void _rtl8188e_read_power_value_fromprom(struct ieee80211_hw *hw,
+ struct txpower_info_2g *pwr2g,
+ struct txpower_info_5g *pwr5g,
+ bool autoload_fail,
+ u8 *hwinfo)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 path, eadr = EEPROM_TX_PWR_INX, i;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "hal_ReadPowerValueFromPROM88E(): PROMContent[0x%x]= 0x%x\n",
+ (eadr+1), hwinfo[eadr+1]);
+ if (0xFF == hwinfo[eadr+1])
+ autoload_fail = true;
+
+ if (autoload_fail) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "auto load fail : Use Default value!\n");
+ for (path = 0; path < MAX_RF_PATH; path++) {
+ /* 2.4G default value */
+ for (i = 0; i < MAX_CHNL_GROUP_24G; i++) {
+ pwr2g->index_cck_base[path][i] = 0x2D;
+ pwr2g->index_bw40_base[path][i] = 0x2D;
+ }
+ for (i = 0; i < MAX_TX_COUNT; i++) {
+ if (i == 0) {
+ pwr2g->bw20_diff[path][0] = 0x02;
+ pwr2g->ofdm_diff[path][0] = 0x04;
+ } else {
+ pwr2g->bw20_diff[path][i] = 0xFE;
+ pwr2g->bw40_diff[path][i] = 0xFE;
+ pwr2g->cck_diff[path][i] = 0xFE;
+ pwr2g->ofdm_diff[path][i] = 0xFE;
+ }
+ }
+ }
+ return;
+ }
+
+ for (path = 0; path < MAX_RF_PATH; path++) {
+ /*2.4G default value*/
+ for (i = 0; i < MAX_CHNL_GROUP_24G; i++) {
+ pwr2g->index_cck_base[path][i] = hwinfo[eadr++];
+ if (pwr2g->index_cck_base[path][i] == 0xFF)
+ pwr2g->index_cck_base[path][i] = 0x2D;
+ }
+ for (i = 0; i < MAX_CHNL_GROUP_24G-1; i++) {
+ pwr2g->index_bw40_base[path][i] = hwinfo[eadr++];
+ if (pwr2g->index_bw40_base[path][i] == 0xFF)
+ pwr2g->index_bw40_base[path][i] = 0x2D;
+ }
+ for (i = 0; i < MAX_TX_COUNT; i++) {
+ if (i == 0) {
+ set_diff0_2g(pwr2g, hwinfo, path, i, eadr);
+ eadr++;
+ } else {
+ set_diff1_2g(pwr2g, hwinfo, path, i, eadr);
+ eadr++;
+
+ set_diff2_2g(pwr2g, hwinfo, path, i, eadr);
+ eadr++;
+ }
+ }
+
+ /*5G default value*/
+ for (i = 0; i < MAX_CHNL_GROUP_5G; i++) {
+ pwr5g->index_bw40_base[path][i] = hwinfo[eadr++];
+ if (pwr5g->index_bw40_base[path][i] == 0xFF)
+ pwr5g->index_bw40_base[path][i] = 0xFE;
+ }
+
+ for (i = 0; i < MAX_TX_COUNT; i++) {
+ if (i == 0) {
+ set_diff0_5g(pwr5g, hwinfo, path, i, eadr);
+ eadr++;
+ } else {
+ set_diff1_5g(pwr5g, hwinfo, path, i, eadr);
+ eadr++;
+ }
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->ofdm_diff[path][1] = 0xFE;
+ pwr5g->ofdm_diff[path][2] = 0xFE;
+ } else {
+ pwr5g->ofdm_diff[path][1] = (hwinfo[eadr] & 0xf0) >> 4;
+ pwr5g->ofdm_diff[path][2] = (hwinfo[eadr] & 0x0f);
+ }
+ eadr++;
+
+ if (hwinfo[eadr] == 0xFF)
+ pwr5g->ofdm_diff[path][3] = 0xFE;
+ else
+ pwr5g->ofdm_diff[path][3] = (hwinfo[eadr]&0x0f);
+ eadr++;
+
+ for (i = 1; i < MAX_TX_COUNT; i++) {
+ if (pwr5g->ofdm_diff[path][i] == 0xFF)
+ pwr5g->ofdm_diff[path][i] = 0xFE;
+ else if (pwr5g->ofdm_diff[path][i] & BIT(3))
+ pwr5g->ofdm_diff[path][i] |= 0xF0;
+ }
+ }
+}
+
+static void _rtl88ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+ bool autoload_fail,
+ u8 *hwinfo)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct txpower_info_2g pwrinfo24g;
+ struct txpower_info_5g pwrinfo5g;
+ u8 rf_path, index;
+ u8 i;
+ int jj = EEPROM_RF_BOARD_OPTION_88E;
+ int kk = EEPROM_THERMAL_METER_88E;
+
+ _rtl8188e_read_power_value_fromprom(hw, &pwrinfo24g, &pwrinfo5g,
+ autoload_fail, hwinfo);
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 14; i++) {
+ index = get_chnl_group(i+1);
+
+ rtlefuse->txpwrlevel_cck[rf_path][i] =
+ pwrinfo24g.index_cck_base[rf_path][index];
+ if (i == 13)
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+ pwrinfo24g.index_bw40_base[rf_path][4];
+ else
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+ pwrinfo24g.index_bw40_base[rf_path][index];
+ rtlefuse->txpwr_ht20diff[rf_path][i] =
+ pwrinfo24g.bw20_diff[rf_path][0];
+ rtlefuse->txpwr_legacyhtdiff[rf_path][i] =
+ pwrinfo24g.ofdm_diff[rf_path][0];
+ }
+
+ for (i = 0; i < 14; i++) {
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+ "RF(%d)-Ch(%d) [CCK / HT40_1S ] = "
+ "[0x%x / 0x%x ]\n", rf_path, i,
+ rtlefuse->txpwrlevel_cck[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i]);
+ }
+ }
+
+ if (!autoload_fail)
+ rtlefuse->eeprom_thermalmeter = hwinfo[kk];
+ else
+ rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+
+ if (rtlefuse->eeprom_thermalmeter == 0xff || autoload_fail) {
+ rtlefuse->apk_thermalmeterignore = true;
+ rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+ }
+
+ rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+ "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
+
+ if (!autoload_fail) {
+ rtlefuse->eeprom_regulatory = hwinfo[jj] & 0x07;/*bit0~2*/
+ if (hwinfo[jj] == 0xFF)
+ rtlefuse->eeprom_regulatory = 0;
+ } else {
+ rtlefuse->eeprom_regulatory = 0;
+ }
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+ "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
+}
+
+static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+ u16 i, usvalue;
+ u8 hwinfo[HWSET_MAX_SIZE];
+ u16 eeprom_id;
+ int jj = EEPROM_RF_BOARD_OPTION_88E;
+ int kk = EEPROM_RF_FEATURE_OPTION_88E;
+
+ if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+ rtl_efuse_shadow_map_update(hw);
+
+ memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ HWSET_MAX_SIZE);
+ } else if (rtlefuse->epromtype == EEPROM_93C46) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "RTL819X Not boot from eeprom, check it !!");
+ }
+
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+ hwinfo, HWSET_MAX_SIZE);
+
+ eeprom_id = *((u16 *)&hwinfo[0]);
+ if (eeprom_id != RTL8188E_EEPROM_ID) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "EEPROM ID(%#x) is invalid!!\n", eeprom_id);
+ rtlefuse->autoload_failflag = true;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+ rtlefuse->autoload_failflag = false;
+ }
+
+ if (rtlefuse->autoload_failflag == true)
+ return;
+ /*VID DID SVID SDID*/
+ rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+ rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+ rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+ rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROMId = 0x%4x\n", eeprom_id);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+ /*customer ID*/
+ rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+ if (rtlefuse->eeprom_oemid == 0xFF)
+ rtlefuse->eeprom_oemid = 0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
+ /*EEPROM version*/
+ rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
+ /*mac address*/
+ for (i = 0; i < 6; i += 2) {
+ usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+ *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "dev_addr: %pM\n", rtlefuse->dev_addr);
+ /*channel plan */
+ rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+ /* set channel paln to world wide 13 */
+ rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+ /*tx power*/
+ _rtl88ee_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+ hwinfo);
+ rtlefuse->txpwr_fromeprom = true;
+
+ rtl8188ee_read_bt_coexist_info_from_hwpg(hw,
+ rtlefuse->autoload_failflag,
+ hwinfo);
+ /*board type*/
+ rtlefuse->board_type = (((*(u8 *)&hwinfo[jj]) & 0xE0) >> 5);
+ /*Wake on wlan*/
+ rtlefuse->wowlan_enable = ((hwinfo[kk] & 0x40) >> 6);
+ /*parse xtal*/
+ rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_88E];
+ if (hwinfo[EEPROM_XTAL_88E])
+ rtlefuse->crystalcap = 0x20;
+ /*antenna diversity*/
+ rtlefuse->antenna_div_cfg = (hwinfo[jj] & 0x18) >> 3;
+ if (hwinfo[jj] == 0xFF)
+ rtlefuse->antenna_div_cfg = 0;
+ if (rppriv->bt_coexist.eeprom_bt_coexist != 0 &&
+ rppriv->bt_coexist.eeprom_bt_ant_num == ANT_X1)
+ rtlefuse->antenna_div_cfg = 0;
+
+ rtlefuse->antenna_div_type = hwinfo[EEPROM_RF_ANTENNA_OPT_88E];
+ if (rtlefuse->antenna_div_type == 0xFF)
+ rtlefuse->antenna_div_type = 0x01;
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV ||
+ rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtlefuse->antenna_div_cfg = 1;
+
+ if (rtlhal->oem_id == RT_CID_DEFAULT) {
+ switch (rtlefuse->eeprom_oemid) {
+ case EEPROM_CID_DEFAULT:
+ if (rtlefuse->eeprom_did == 0x8179) {
+ if (rtlefuse->eeprom_svid == 0x1025) {
+ rtlhal->oem_id = RT_CID_819x_Acer;
+ } else if ((rtlefuse->eeprom_svid == 0x10EC &&
+ rtlefuse->eeprom_smid == 0x0179) ||
+ (rtlefuse->eeprom_svid == 0x17AA &&
+ rtlefuse->eeprom_smid == 0x0179)) {
+ rtlhal->oem_id = RT_CID_819x_Lenovo;
+ } else if (rtlefuse->eeprom_svid == 0x103c &&
+ rtlefuse->eeprom_smid == 0x197d) {
+ rtlhal->oem_id = RT_CID_819x_HP;
+ } else {
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ }
+ } else {
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ }
+ break;
+ case EEPROM_CID_TOSHIBA:
+ rtlhal->oem_id = RT_CID_TOSHIBA;
+ break;
+ case EEPROM_CID_QMI:
+ rtlhal->oem_id = RT_CID_819x_QMI;
+ break;
+ case EEPROM_CID_WHQL:
+ default:
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ break;
+ }
+ }
+}
+
+static void _rtl88ee_hal_customized_behavior(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ pcipriv->ledctl.led_opendrain = true;
+
+ switch (rtlhal->oem_id) {
+ case RT_CID_819x_HP:
+ pcipriv->ledctl.led_opendrain = true;
+ break;
+ case RT_CID_819x_Lenovo:
+ case RT_CID_DEFAULT:
+ case RT_CID_TOSHIBA:
+ case RT_CID_CCX:
+ case RT_CID_819x_Acer:
+ case RT_CID_WHQL:
+ default:
+ break;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "RT Customized ID: 0x%02X\n", rtlhal->oem_id);
+}
+
+void rtl88ee_read_eeprom_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp_u1b;
+
+ rtlhal->version = _rtl88ee_read_chip_version(hw);
+ if (get_rf_type(rtlphy) == RF_1T1R) {
+ rtlpriv->dm.rfpath_rxenable[0] = true;
+ } else {
+ rtlpriv->dm.rfpath_rxenable[0] = true;
+ rtlpriv->dm.rfpath_rxenable[1] = true;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
+ rtlhal->version);
+ tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
+ if (tmp_u1b & BIT(4)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n");
+ rtlefuse->epromtype = EEPROM_93C46;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n");
+ rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+ }
+ if (tmp_u1b & BIT(5)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+ rtlefuse->autoload_failflag = false;
+ _rtl88ee_read_adapter_info(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+ }
+ _rtl88ee_hal_customized_behavior(hw);
+}
+
+static void rtl88ee_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 ratr_value;
+ u8 ratr_index = 0;
+ u8 nmode = mac->ht_enable;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+ u16 shortgi_rate;
+ u32 tmp_ratr_value;
+ u8 ctx40 = mac->bw_40;
+ u16 cap = sta->ht_cap.cap;
+ u8 short40 = (cap & IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
+ u8 short20 = (cap & IEEE80211_HT_CAP_SGI_20) ? 1 : 0;
+ enum wireless_mode wirelessmode = mac->mode;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_value = sta->supp_rates[1] << 4;
+ else
+ ratr_value = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_value = 0xfff;
+ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ if (ratr_value & 0x0000000c)
+ ratr_value &= 0x0000000d;
+ else
+ ratr_value &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_value &= 0x00000FF5;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ nmode = 1;
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ ratr_value &= 0x0007F005;
+ } else {
+ u32 ratr_mask;
+
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R)
+ ratr_mask = 0x000ff005;
+ else
+ ratr_mask = 0x0f0ff005;
+
+ ratr_value &= ratr_mask;
+ }
+ break;
+ default:
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_value &= 0x000ff0ff;
+ else
+ ratr_value &= 0x0f0ff0ff;
+
+ break;
+ }
+
+ if ((rppriv->bt_coexist.bt_coexistence) &&
+ (rppriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) &&
+ (rppriv->bt_coexist.bt_cur_state) &&
+ (rppriv->bt_coexist.bt_ant_isolation) &&
+ ((rppriv->bt_coexist.bt_service == BT_SCO) ||
+ (rppriv->bt_coexist.bt_service == BT_BUSY)))
+ ratr_value &= 0x0fffcfc0;
+ else
+ ratr_value &= 0x0FFFFFFF;
+
+ if (nmode && ((ctx40 && short40) ||
+ (!ctx40 && short20))) {
+ ratr_value |= 0x10000000;
+ tmp_ratr_value = (ratr_value >> 12);
+
+ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+ if ((1 << shortgi_rate) & tmp_ratr_value)
+ break;
+ }
+
+ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+ (shortgi_rate << 4) | (shortgi_rate);
+ }
+
+ rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
+}
+
+static void rtl88ee_update_hal_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
+ u32 ratr_bitmap;
+ u8 ratr_index;
+ u16 cap = sta->ht_cap.cap;
+ u8 ctx40 = (cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0;
+ u8 short40 = (cap & IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
+ u8 short20 = (cap & IEEE80211_HT_CAP_SGI_20) ? 1 : 0;
+ enum wireless_mode wirelessmode = 0;
+ bool shortgi = false;
+ u8 rate_mask[5];
+ u8 macid = 0;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ wirelessmode = sta_entry->wireless_mode;
+ if (mac->opmode == NL80211_IFTYPE_STATION ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
+ ctx40 = mac->bw_40;
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ macid = sta->aid + 1;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_bitmap = sta->supp_rates[1] << 4;
+ else
+ ratr_bitmap = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_bitmap = 0xfff;
+ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ ratr_index = RATR_INX_WIRELESS_B;
+ if (ratr_bitmap & 0x0000000c)
+ ratr_bitmap &= 0x0000000d;
+ else
+ ratr_bitmap &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_index = RATR_INX_WIRELESS_GB;
+
+ if (rssi == 1)
+ ratr_bitmap &= 0x00000f00;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x00000ff0;
+ else
+ ratr_bitmap &= 0x00000ff5;
+ break;
+ case WIRELESS_MODE_A:
+ ratr_index = RATR_INX_WIRELESS_A;
+ ratr_bitmap &= 0x00000ff0;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ if (rssi == 1)
+ ratr_bitmap &= 0x00070000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x0007f000;
+ else
+ ratr_bitmap &= 0x0007f005;
+ } else {
+ if (rtlphy->rf_type == RF_1T2R ||
+ rtlphy->rf_type == RF_1T1R) {
+ if (ctx40) {
+ if (rssi == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff015;
+ } else {
+ if (rssi == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff005;
+ }
+ } else {
+ if (ctx40) {
+ if (rssi == 1)
+ ratr_bitmap &= 0x0f8f0000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x0f8ff000;
+ else
+ ratr_bitmap &= 0x0f8ff015;
+ } else {
+ if (rssi == 1)
+ ratr_bitmap &= 0x0f8f0000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x0f8ff000;
+ else
+ ratr_bitmap &= 0x0f8ff005;
+ }
+ }
+ }
+
+ if ((ctx40 && short40) || (!ctx40 && short20)) {
+ if (macid == 0)
+ shortgi = true;
+ else if (macid == 1)
+ shortgi = false;
+ }
+ break;
+ default:
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_bitmap &= 0x000ff0ff;
+ else
+ ratr_bitmap &= 0x0f0ff0ff;
+ break;
+ }
+ sta_entry->ratr_index = ratr_index;
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "ratr_bitmap :%x\n", ratr_bitmap);
+ *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+ (ratr_index << 28);
+ rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x\n",
+ ratr_index, ratr_bitmap, rate_mask[0], rate_mask[1],
+ rate_mask[2], rate_mask[3], rate_mask[4]);
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_RA_MASK, 5, rate_mask);
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+}
+
+void rtl88ee_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->dm.useramask)
+ rtl88ee_update_hal_rate_mask(hw, sta, rssi);
+ else
+ rtl88ee_update_hal_rate_table(hw, sta);
+}
+
+void rtl88ee_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 sifs_timer;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+ (u8 *)&mac->slot_time);
+ if (!mac->ht_enable)
+ sifs_timer = 0x0a0a;
+ else
+ sifs_timer = 0x0e0e;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+}
+
+bool rtl88ee_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ enum rf_pwrstate state_toset;
+ u32 u4tmp;
+ bool actuallyset = false;
+
+ if (rtlpriv->rtlhal.being_init_adapter)
+ return false;
+
+ if (ppsc->swrf_processing)
+ return false;
+
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ if (ppsc->rfchange_inprogress) {
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ return false;
+ } else {
+ ppsc->rfchange_inprogress = true;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ }
+
+ u4tmp = rtl_read_dword(rtlpriv, REG_GPIO_OUTPUT);
+ state_toset = (u4tmp & BIT(31)) ? ERFON : ERFOFF;
+
+
+ if ((ppsc->hwradiooff == true) && (state_toset == ERFON)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "GPIOChangeRF - HW Radio ON, RF ON\n");
+
+ state_toset = ERFON;
+ ppsc->hwradiooff = false;
+ actuallyset = true;
+ } else if ((ppsc->hwradiooff == false) && (state_toset == ERFOFF)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "GPIOChangeRF - HW Radio OFF, RF OFF\n");
+
+ state_toset = ERFOFF;
+ ppsc->hwradiooff = true;
+ actuallyset = true;
+ }
+
+ if (actuallyset) {
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ } else {
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ }
+
+ *valid = 1;
+ return !ppsc->hwradiooff;
+}
+
+static void add_one_key(struct ieee80211_hw *hw, u8 *macaddr,
+ struct rtl_mac *mac, u32 key, u32 id,
+ u8 enc_algo, bool is_pairwise)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "add one entry\n");
+ if (is_pairwise) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set Pairwise key\n");
+
+ rtl_cam_add_one_entry(hw, macaddr, key, id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[key]);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set group key\n");
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ rtl_cam_add_one_entry(hw, rtlefuse->dev_addr,
+ PAIRWISE_KEYIDX,
+ CAM_PAIRWISE_KEY_POSITION,
+ enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[id]);
+ }
+
+ rtl_cam_add_one_entry(hw, macaddr, key, id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[id]);
+ }
+}
+
+void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key,
+ u8 *mac_ad, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 *macaddr = mac_ad;
+ u32 id = 0;
+ bool is_pairwise = false;
+
+ static u8 cam_const_addr[4][6] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+ };
+ static u8 cam_const_broad[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (clear_all) {
+ u8 idx = 0;
+ u8 cam_offset = 0;
+ u8 clear_number = 5;
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n");
+
+ for (idx = 0; idx < clear_number; idx++) {
+ rtl_cam_mark_invalid(hw, cam_offset + idx);
+ rtl_cam_empty_entry(hw, cam_offset + idx);
+
+ if (idx < 5) {
+ memset(rtlpriv->sec.key_buf[idx], 0,
+ MAX_KEY_LEN);
+ rtlpriv->sec.key_len[idx] = 0;
+ }
+ }
+
+ } else {
+ switch (enc_algo) {
+ case WEP40_ENCRYPTION:
+ enc_algo = CAM_WEP40;
+ break;
+ case WEP104_ENCRYPTION:
+ enc_algo = CAM_WEP104;
+ break;
+ case TKIP_ENCRYPTION:
+ enc_algo = CAM_TKIP;
+ break;
+ case AESCCMP_ENCRYPTION:
+ enc_algo = CAM_AES;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ enc_algo = CAM_TKIP;
+ break;
+ }
+
+ if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+ macaddr = cam_const_addr[key];
+ id = key;
+ } else {
+ if (is_group) {
+ macaddr = cam_const_broad;
+ id = key;
+ } else {
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+ id = rtl_cam_get_free_entry(hw, mac_ad);
+ if (id >= TOTAL_CAM_ENTRY) {
+ RT_TRACE(rtlpriv, COMP_SEC,
+ DBG_EMERG,
+ "Can not find free hw security cam entry\n");
+ return;
+ }
+ } else {
+ id = CAM_PAIRWISE_KEY_POSITION;
+ }
+
+ key = PAIRWISE_KEYIDX;
+ is_pairwise = true;
+ }
+ }
+
+ if (rtlpriv->sec.key_len[key] == 0) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "delete one entry, id is %d\n", id);
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
+ rtl_cam_del_entry(hw, mac_ad);
+ rtl_cam_delete_one_entry(hw, mac_ad, id);
+ } else {
+ add_one_key(hw, macaddr, mac, key, id, enc_algo,
+ is_pairwise);
+ }
+ }
+}
+
+static void rtl8188ee_bt_var_init(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+ struct bt_coexist_info coexist = rppriv->bt_coexist;
+
+ coexist.bt_coexistence = rppriv->bt_coexist.eeprom_bt_coexist;
+ coexist.bt_ant_num = coexist.eeprom_bt_ant_num;
+ coexist.bt_coexist_type = coexist.eeprom_bt_type;
+
+ if (coexist.reg_bt_iso == 2)
+ coexist.bt_ant_isolation = coexist.eeprom_bt_ant_isol;
+ else
+ coexist.bt_ant_isolation = coexist.reg_bt_iso;
+
+ coexist.bt_radio_shared_type = coexist.eeprom_bt_radio_shared;
+
+ if (coexist.bt_coexistence) {
+ if (coexist.reg_bt_sco == 1)
+ coexist.bt_service = BT_OTHER_ACTION;
+ else if (coexist.reg_bt_sco == 2)
+ coexist.bt_service = BT_SCO;
+ else if (coexist.reg_bt_sco == 4)
+ coexist.bt_service = BT_BUSY;
+ else if (coexist.reg_bt_sco == 5)
+ coexist.bt_service = BT_OTHERBUSY;
+ else
+ coexist.bt_service = BT_IDLE;
+
+ coexist.bt_edca_ul = 0;
+ coexist.bt_edca_dl = 0;
+ coexist.bt_rssi_state = 0xff;
+ }
+}
+
+void rtl8188ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+ bool auto_load_fail, u8 *hwinfo)
+{
+ rtl8188ee_bt_var_init(hw);
+}
+
+void rtl8188ee_bt_reg_init(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+
+ /* 0:Low, 1:High, 2:From Efuse. */
+ rppriv->bt_coexist.reg_bt_iso = 2;
+ /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+ rppriv->bt_coexist.reg_bt_sco = 3;
+ /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+ rppriv->bt_coexist.reg_bt_sco = 0;
+}
+
+void rtl8188ee_bt_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+ struct bt_coexist_info coexist = rppriv->bt_coexist;
+ u8 u1_tmp;
+
+ if (coexist.bt_coexistence &&
+ ((coexist.bt_coexist_type == BT_CSR_BC4) ||
+ coexist.bt_coexist_type == BT_CSR_BC8)) {
+ if (coexist.bt_ant_isolation)
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+
+ u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) &
+ BIT_OFFSET_LEN_MASK_32(0, 1);
+ u1_tmp = u1_tmp | ((coexist.bt_ant_isolation == 1) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+ ((coexist.bt_service == BT_SCO) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(2, 1));
+ rtl_write_byte(rtlpriv, 0x4fd, u1_tmp);
+
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa);
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040);
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010);
+
+ /* Config to 1T1R. */
+ if (rtlphy->rf_type == RF_1T1R) {
+ u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE);
+ u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1));
+ rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp);
+
+ u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE);
+ u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1));
+ rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp);
+ }
+ }
+}
+
+void rtl88ee_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl88ee_resume(struct ieee80211_hw *hw)
+{
+}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl88ee_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ if (allow_all_da) /* Set BIT0 */
+ rtlpci->receive_config |= RCR_AAP;
+ else /* Clear BIT0 */
+ rtlpci->receive_config &= ~RCR_AAP;
+
+ if (write_into_reg)
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+ RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+ "receive_config = 0x%08X, write_into_reg =%d\n",
+ rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.h
new file mode 100644
index 000000000000..b4460a41bd01
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_HW_H__
+#define __RTL92CE_HW_H__
+
+void rtl88ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl88ee_read_eeprom_info(struct ieee80211_hw *hw);
+void rtl88ee_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb);
+int rtl88ee_hw_init(struct ieee80211_hw *hw);
+void rtl88ee_card_disable(struct ieee80211_hw *hw);
+void rtl88ee_enable_interrupt(struct ieee80211_hw *hw);
+void rtl88ee_disable_interrupt(struct ieee80211_hw *hw);
+int rtl88ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type);
+void rtl88ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl88ee_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl88ee_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl88ee_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl88ee_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr);
+void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl88ee_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
+void rtl88ee_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl88ee_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl88ee_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key_index,
+ u8 *p_macaddr, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all);
+
+void rtl8188ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+ bool autoload_fail, u8 *hwinfo);
+void rtl8188ee_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8188ee_bt_hw_init(struct ieee80211_hw *hw);
+void rtl88ee_suspend(struct ieee80211_hw *hw);
+void rtl88ee_resume(struct ieee80211_hw *hw);
+void rtl88ee_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg);
+void rtl88ee_fw_clk_off_timer_callback(unsigned long data);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/led.c b/drivers/net/wireless/rtlwifi/rtl8188ee/led.c
new file mode 100644
index 000000000000..c81a9cb6894c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/led.c
@@ -0,0 +1,157 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void rtl88ee_init_led(struct ieee80211_hw *hw,
+ struct rtl_led *pled, enum rtl_led_pin ledpin)
+{
+ pled->hw = hw;
+ pled->ledpin = ledpin;
+ pled->ledon = false;
+}
+
+void rtl88ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ u8 ledcfg;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+ rtl_write_byte(rtlpriv, REG_LEDCFG2,
+ (ledcfg & 0xf0) | BIT(5) | BIT(6));
+ break;
+ case LED_PIN_LED1:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+ rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ pled->ledon = true;
+}
+
+void rtl88ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ u8 ledcfg;
+ u8 val;
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+ ledcfg &= 0xf0;
+ val = ledcfg | BIT(3) | BIT(5) | BIT(6);
+ if (pcipriv->ledctl.led_opendrain == true) {
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, val);
+ ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
+ val = ledcfg & 0xFE;
+ rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, val);
+ } else {
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, val);
+ }
+ break;
+ case LED_PIN_LED1:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+ ledcfg &= 0x10;
+ rtl_write_byte(rtlpriv, REG_LEDCFG1, (ledcfg | BIT(3)));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ pled->ledon = false;
+}
+
+void rtl88ee_init_sw_leds(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+ rtl88ee_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+ rtl88ee_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+}
+
+static void rtl88ee_sw_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+ switch (ledaction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_LINK:
+ case LED_CTL_NO_LINK:
+ rtl88ee_sw_led_on(hw, pLed0);
+ break;
+ case LED_CTL_POWER_OFF:
+ rtl88ee_sw_led_off(hw, pLed0);
+ break;
+ default:
+ break;
+ }
+}
+
+void rtl88ee_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+ (ledaction == LED_CTL_TX ||
+ ledaction == LED_CTL_RX ||
+ ledaction == LED_CTL_SITE_SURVEY ||
+ ledaction == LED_CTL_LINK ||
+ ledaction == LED_CTL_NO_LINK ||
+ ledaction == LED_CTL_START_TO_LINK ||
+ ledaction == LED_CTL_POWER_ON)) {
+ return;
+ }
+ RT_TRACE(rtlpriv, COMP_LED, DBG_TRACE, "ledaction %d,\n",
+ ledaction);
+ rtl88ee_sw_led_control(hw, ledaction);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/led.h b/drivers/net/wireless/rtlwifi/rtl8188ee/led.h
new file mode 100644
index 000000000000..4073f6f847b2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/led.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_LED_H__
+#define __RTL92CE_LED_H__
+
+void rtl88ee_init_sw_leds(struct ieee80211_hw *hw);
+void rtl88ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl88ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl88ee_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
new file mode 100644
index 000000000000..e655c0473225
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
@@ -0,0 +1,2202 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+#include "table.h"
+
+static void set_baseband_phy_config(struct ieee80211_hw *hw);
+static void set_baseband_agc_config(struct ieee80211_hw *hw);
+static void store_pwrindex_offset(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask,
+ u32 data);
+static bool check_cond(struct ieee80211_hw *hw, const u32 condition);
+
+static u32 rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *phreg = &rtlphy->phyreg_def[rfpath];
+ u32 newoffset;
+ u32 tmplong, tmplong2;
+ u8 rfpi_enable = 0;
+ u32 ret;
+ int jj = RF90_PATH_A;
+ int kk = RF90_PATH_B;
+
+ offset &= 0xff;
+ newoffset = offset;
+ if (RT_CANNOT_IO(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+ return 0xFFFFFFFF;
+ }
+ tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+ if (rfpath == jj)
+ tmplong2 = tmplong;
+ else
+ tmplong2 = rtl_get_bbreg(hw, phreg->rfhssi_para2, MASKDWORD);
+ tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
+ (newoffset << 23) | BLSSIREADEDGE;
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+ tmplong & (~BLSSIREADEDGE));
+ mdelay(1);
+ rtl_set_bbreg(hw, phreg->rfhssi_para2, MASKDWORD, tmplong2);
+ mdelay(2);
+ if (rfpath == jj)
+ rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+ BIT(8));
+ else if (rfpath == kk)
+ rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+ BIT(8));
+ if (rfpi_enable)
+ ret = rtl_get_bbreg(hw, phreg->rf_rbpi, BLSSIREADBACKDATA);
+ else
+ ret = rtl_get_bbreg(hw, phreg->rf_rb, BLSSIREADBACKDATA);
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]= 0x%x\n",
+ rfpath, phreg->rf_rb, ret);
+ return ret;
+}
+
+static void rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data)
+{
+ u32 data_and_addr;
+ u32 newoffset;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *phreg = &rtlphy->phyreg_def[rfpath];
+
+ if (RT_CANNOT_IO(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+ return;
+ }
+ offset &= 0xff;
+ newoffset = offset;
+ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+ rtl_set_bbreg(hw, phreg->rf3wire_offset, MASKDWORD, data_and_addr);
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]= 0x%x\n",
+ rfpath, phreg->rf3wire_offset, data_and_addr);
+}
+
+static u32 cal_bit_shift(u32 bitmask)
+{
+ u32 i;
+
+ for (i = 0; i <= 31; i++) {
+ if (((bitmask >> i) & 0x1) == 1)
+ break;
+ }
+ return i;
+}
+
+static bool config_bb_with_header(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ if (configtype == BASEBAND_CONFIG_PHY_REG)
+ set_baseband_phy_config(hw);
+ else if (configtype == BASEBAND_CONFIG_AGC_TAB)
+ set_baseband_agc_config(hw);
+ return true;
+}
+
+static bool config_bb_with_pgheader(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int i;
+ u32 *table_pg;
+ u16 tbl_page_len;
+ u32 v1 = 0, v2 = 0;
+
+ tbl_page_len = RTL8188EEPHY_REG_ARRAY_PGLEN;
+ table_pg = RTL8188EEPHY_REG_ARRAY_PG;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < tbl_page_len; i = i + 3) {
+ v1 = table_pg[i];
+ v2 = table_pg[i + 1];
+
+ if (v1 < 0xcdcdcdcd) {
+ if (table_pg[i] == 0xfe)
+ mdelay(50);
+ else if (table_pg[i] == 0xfd)
+ mdelay(5);
+ else if (table_pg[i] == 0xfc)
+ mdelay(1);
+ else if (table_pg[i] == 0xfb)
+ udelay(50);
+ else if (table_pg[i] == 0xfa)
+ udelay(5);
+ else if (table_pg[i] == 0xf9)
+ udelay(1);
+
+ store_pwrindex_offset(hw, table_pg[i],
+ table_pg[i + 1],
+ table_pg[i + 2]);
+ continue;
+ } else {
+ if (!check_cond(hw, table_pg[i])) {
+ /*don't need the hw_body*/
+ i += 2; /* skip the pair of expression*/
+ v1 = table_pg[i];
+ v2 = table_pg[i + 1];
+ while (v2 != 0xDEAD) {
+ i += 3;
+ v1 = table_pg[i];
+ v2 = table_pg[i + 1];
+ }
+ }
+ }
+ }
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "configtype != BaseBand_Config_PHY_REG\n");
+ }
+ return true;
+}
+
+static bool config_parafile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ bool rtstatus;
+
+ rtstatus = config_bb_with_header(hw, BASEBAND_CONFIG_PHY_REG);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
+ return false;
+ }
+
+ if (fuse->autoload_failflag == false) {
+ rtlphy->pwrgroup_cnt = 0;
+ rtstatus = config_bb_with_pgheader(hw, BASEBAND_CONFIG_PHY_REG);
+ }
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
+ return false;
+ }
+ rtstatus = config_bb_with_header(hw, BASEBAND_CONFIG_AGC_TAB);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+ return false;
+ }
+ rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2, 0x200));
+
+ return true;
+}
+
+static void rtl88e_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ int jj = RF90_PATH_A;
+ int kk = RF90_PATH_B;
+
+ rtlphy->phyreg_def[jj].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[kk].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+ rtlphy->phyreg_def[jj].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[kk].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+ rtlphy->phyreg_def[jj].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[kk].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+ rtlphy->phyreg_def[jj].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[kk].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+ rtlphy->phyreg_def[jj].rf3wire_offset = RFPGA0_XA_LSSIPARAMETER;
+ rtlphy->phyreg_def[kk].rf3wire_offset = RFPGA0_XB_LSSIPARAMETER;
+
+ rtlphy->phyreg_def[jj].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[kk].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+
+ rtlphy->phyreg_def[jj].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[kk].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+ rtlphy->phyreg_def[jj].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+ rtlphy->phyreg_def[kk].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+
+ rtlphy->phyreg_def[jj].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+ rtlphy->phyreg_def[kk].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+
+ rtlphy->phyreg_def[jj].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[kk].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+
+ rtlphy->phyreg_def[jj].rfagc_control1 = ROFDM0_XAAGCCORE1;
+ rtlphy->phyreg_def[kk].rfagc_control1 = ROFDM0_XBAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+ rtlphy->phyreg_def[jj].rfagc_control2 = ROFDM0_XAAGCCORE2;
+ rtlphy->phyreg_def[kk].rfagc_control2 = ROFDM0_XBAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+ rtlphy->phyreg_def[jj].rfrxiq_imbal = ROFDM0_XARXIQIMBAL;
+ rtlphy->phyreg_def[kk].rfrxiq_imbal = ROFDM0_XBRXIQIMBAL;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBAL;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBAL;
+
+ rtlphy->phyreg_def[jj].rfrx_afe = ROFDM0_XARXAFE;
+ rtlphy->phyreg_def[kk].rfrx_afe = ROFDM0_XBRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+ rtlphy->phyreg_def[jj].rftxiq_imbal = ROFDM0_XATXIQIMBAL;
+ rtlphy->phyreg_def[kk].rftxiq_imbal = ROFDM0_XBTXIQIMBAL;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBAL;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBAL;
+
+ rtlphy->phyreg_def[jj].rftx_afe = ROFDM0_XATXAFE;
+ rtlphy->phyreg_def[kk].rftx_afe = ROFDM0_XBTXAFE;
+
+ rtlphy->phyreg_def[jj].rf_rb = RFPGA0_XA_LSSIREADBACK;
+ rtlphy->phyreg_def[kk].rf_rb = RFPGA0_XB_LSSIREADBACK;
+
+ rtlphy->phyreg_def[jj].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
+ rtlphy->phyreg_def[kk].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
+}
+
+static bool rtl88e_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx, u32 cmdtablesz,
+ enum swchnlcmd_id cmdid,
+ u32 para1, u32 para2, u32 msdelay)
+{
+ struct swchnlcmd *pcmd;
+
+ if (cmdtable == NULL) {
+ RT_ASSERT(false, "cmdtable cannot be NULL.\n");
+ return false;
+ }
+
+ if (cmdtableidx >= cmdtablesz)
+ return false;
+
+ pcmd = cmdtable + cmdtableidx;
+ pcmd->cmdid = cmdid;
+ pcmd->para1 = para1;
+ pcmd->para2 = para2;
+ pcmd->msdelay = msdelay;
+ return true;
+}
+
+static bool chnl_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage, u8 *step,
+ u32 *delay)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+ u32 precommoncmdcnt;
+ struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+ u32 postcommoncmdcnt;
+ struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+ u32 rfdependcmdcnt;
+ struct swchnlcmd *currentcmd = NULL;
+ u8 rfpath;
+ u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+ precommoncmdcnt = 0;
+ rtl88e_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT,
+ CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
+ rtl88e_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
+ postcommoncmdcnt = 0;
+
+ rtl88e_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+ MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+
+ rfdependcmdcnt = 0;
+
+ RT_ASSERT((channel >= 1 && channel <= 14),
+ "illegal channel for Zebra: %d\n", channel);
+
+ rtl88e_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+ RF_CHNLBW, channel, 10);
+
+ rtl88e_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0,
+ 0);
+
+ do {
+ switch (*stage) {
+ case 0:
+ currentcmd = &precommoncmd[*step];
+ break;
+ case 1:
+ currentcmd = &rfdependcmd[*step];
+ break;
+ case 2:
+ currentcmd = &postcommoncmd[*step];
+ break;
+ }
+
+ if (currentcmd->cmdid == CMDID_END) {
+ if ((*stage) == 2) {
+ return true;
+ } else {
+ (*stage)++;
+ (*step) = 0;
+ continue;
+ }
+ }
+
+ switch (currentcmd->cmdid) {
+ case CMDID_SET_TXPOWEROWER_LEVEL:
+ rtl88e_phy_set_txpower_level(hw, channel);
+ break;
+ case CMDID_WRITEPORT_ULONG:
+ rtl_write_dword(rtlpriv, currentcmd->para1,
+ currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_USHORT:
+ rtl_write_word(rtlpriv, currentcmd->para1,
+ (u16) currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_UCHAR:
+ rtl_write_byte(rtlpriv, currentcmd->para1,
+ (u8) currentcmd->para2);
+ break;
+ case CMDID_RF_WRITEREG:
+ for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+ rtlphy->rfreg_chnlval[rfpath] =
+ ((rtlphy->rfreg_chnlval[rfpath] &
+ 0xfffffc00) | currentcmd->para2);
+
+ rtl_set_rfreg(hw, (enum radio_path)rfpath,
+ currentcmd->para1,
+ RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[rfpath]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+
+ break;
+ } while (true);
+
+ (*delay) = currentcmd->msdelay;
+ (*step)++;
+ return false;
+}
+
+static long rtl88e_pwr_idx_dbm(struct ieee80211_hw *hw,
+ enum wireless_mode wirelessmode,
+ u8 txpwridx)
+{
+ long offset;
+ long pwrout_dbm;
+
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ offset = -7;
+ break;
+ case WIRELESS_MODE_G:
+ case WIRELESS_MODE_N_24G:
+ offset = -8;
+ break;
+ default:
+ offset = -8;
+ break;
+ }
+ pwrout_dbm = txpwridx / 2 + offset;
+ return pwrout_dbm;
+}
+
+static void rtl88e_phy_set_io(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "--->Cmd(%#x), set_io_inprogress(%d)\n",
+ rtlphy->current_io_type, rtlphy->set_io_inprogress);
+ switch (rtlphy->current_io_type) {
+ case IO_CMD_RESUME_DM_BY_SCAN:
+ dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1;
+ /*rtl92c_dm_write_dig(hw);*/
+ rtl88e_phy_set_txpower_level(hw, rtlphy->current_channel);
+ rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83);
+ break;
+ case IO_CMD_PAUSE_DM_BY_SCAN:
+ rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
+ dm_digtable->cur_igvalue = 0x17;
+ rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ rtlphy->set_io_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "(%#x)\n", rtlphy->current_io_type);
+}
+
+u32 rtl88e_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 returnvalue, originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = cal_bit_shift(bitmask);
+ returnvalue = (originalvalue & bitmask) >> bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "BBR MASK = 0x%x Addr[0x%x]= 0x%x\n", bitmask,
+ regaddr, originalvalue);
+
+ return returnvalue;
+}
+
+void rtl88e_phy_set_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x),data(%#x)\n",
+ regaddr, bitmask, data);
+
+ if (bitmask != MASKDWORD) {
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = cal_bit_shift(bitmask);
+ data = ((originalvalue & (~bitmask)) | (data << bitshift));
+ }
+
+ rtl_write_dword(rtlpriv, regaddr, data);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+ regaddr, bitmask, data);
+}
+
+u32 rtl88e_phy_query_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, readback_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
+ regaddr, rfpath, bitmask);
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+
+ original_value = rf_serial_read(hw, rfpath, regaddr);
+ bitshift = cal_bit_shift(bitmask);
+ readback_value = (original_value & bitmask) >> bitshift;
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
+ regaddr, rfpath, bitmask, original_value);
+
+ return readback_value;
+}
+
+void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+ regaddr, bitmask, data, rfpath);
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ if (bitmask != RFREG_OFFSET_MASK) {
+ original_value = rf_serial_read(hw, rfpath, regaddr);
+ bitshift = cal_bit_shift(bitmask);
+ data = ((original_value & (~bitmask)) |
+ (data << bitshift));
+ }
+
+ rf_serial_write(hw, rfpath, regaddr, data);
+
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+ regaddr, bitmask, data, rfpath);
+}
+
+static bool config_mac_with_header(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+ u32 arraylength;
+ u32 *ptrarray;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl8188EMACPHY_Array\n");
+ arraylength = RTL8188EEMAC_1T_ARRAYLEN;
+ ptrarray = RTL8188EEMAC_1T_ARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Img:RTL8188EEMAC_1T_ARRAY LEN %d\n", arraylength);
+ for (i = 0; i < arraylength; i = i + 2)
+ rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
+ return true;
+}
+
+bool rtl88e_phy_mac_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool rtstatus = config_mac_with_header(hw);
+
+ rtl_write_byte(rtlpriv, 0x04CA, 0x0B);
+ return rtstatus;
+}
+
+bool rtl88e_phy_bb_config(struct ieee80211_hw *hw)
+{
+ bool rtstatus = true;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 regval;
+ u8 reg_hwparafile = 1;
+ u32 tmp;
+ rtl88e_phy_init_bb_rf_register_definition(hw);
+ regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
+ regval | BIT(13) | BIT(0) | BIT(1));
+
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+ FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
+ FEN_BB_GLB_RSTN | FEN_BBRSTB);
+ tmp = rtl_read_dword(rtlpriv, 0x4c);
+ rtl_write_dword(rtlpriv, 0x4c, tmp | BIT(23));
+ if (reg_hwparafile == 1)
+ rtstatus = config_parafile(hw);
+ return rtstatus;
+}
+
+bool rtl88e_phy_rf_config(struct ieee80211_hw *hw)
+{
+ return rtl88e_phy_rf6052_config(hw);
+}
+
+static bool check_cond(struct ieee80211_hw *hw,
+ const u32 condition)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ u32 _board = fuse->board_type; /*need efuse define*/
+ u32 _interface = rtlhal->interface;
+ u32 _platform = 0x08;/*SupportPlatform */
+ u32 cond = condition;
+
+ if (condition == 0xCDCDCDCD)
+ return true;
+
+ cond = condition & 0xFF;
+ if ((_board & cond) == 0 && cond != 0x1F)
+ return false;
+
+ cond = condition & 0xFF00;
+ cond = cond >> 8;
+ if ((_interface & cond) == 0 && cond != 0x07)
+ return false;
+
+ cond = condition & 0xFF0000;
+ cond = cond >> 16;
+ if ((_platform & cond) == 0 && cond != 0x0F)
+ return false;
+ return true;
+}
+
+static void _rtl8188e_config_rf_reg(struct ieee80211_hw *hw,
+ u32 addr, u32 data, enum radio_path rfpath,
+ u32 regaddr)
+{
+ if (addr == 0xffe) {
+ mdelay(50);
+ } else if (addr == 0xfd) {
+ mdelay(5);
+ } else if (addr == 0xfc) {
+ mdelay(1);
+ } else if (addr == 0xfb) {
+ udelay(50);
+ } else if (addr == 0xfa) {
+ udelay(5);
+ } else if (addr == 0xf9) {
+ udelay(1);
+ } else {
+ rtl_set_rfreg(hw, rfpath, regaddr,
+ RFREG_OFFSET_MASK,
+ data);
+ udelay(1);
+ }
+}
+
+static void rtl88_config_s(struct ieee80211_hw *hw,
+ u32 addr, u32 data)
+{
+ u32 content = 0x1000; /*RF Content: radio_a_txt*/
+ u32 maskforphyset = (u32)(content & 0xE000);
+
+ _rtl8188e_config_rf_reg(hw, addr, data, RF90_PATH_A,
+ addr | maskforphyset);
+}
+
+static void _rtl8188e_config_bb_reg(struct ieee80211_hw *hw,
+ u32 addr, u32 data)
+{
+ if (addr == 0xfe) {
+ mdelay(50);
+ } else if (addr == 0xfd) {
+ mdelay(5);
+ } else if (addr == 0xfc) {
+ mdelay(1);
+ } else if (addr == 0xfb) {
+ udelay(50);
+ } else if (addr == 0xfa) {
+ udelay(5);
+ } else if (addr == 0xf9) {
+ udelay(1);
+ } else {
+ rtl_set_bbreg(hw, addr, MASKDWORD, data);
+ udelay(1);
+ }
+}
+
+
+#define NEXT_PAIR(v1, v2, i) \
+ do { \
+ i += 2; v1 = array_table[i]; \
+ v2 = array_table[i + 1]; \
+ } while (0)
+
+static void set_baseband_agc_config(struct ieee80211_hw *hw)
+{
+ int i;
+ u32 *array_table;
+ u16 arraylen;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 v1 = 0, v2 = 0;
+
+ arraylen = RTL8188EEAGCTAB_1TARRAYLEN;
+ array_table = RTL8188EEAGCTAB_1TARRAY;
+
+ for (i = 0; i < arraylen; i += 2) {
+ v1 = array_table[i];
+ v2 = array_table[i + 1];
+ if (v1 < 0xCDCDCDCD) {
+ rtl_set_bbreg(hw, array_table[i], MASKDWORD,
+ array_table[i + 1]);
+ udelay(1);
+ continue;
+ } else {/*This line is the start line of branch.*/
+ if (!check_cond(hw, array_table[i])) {
+ /*Discard the following (offset, data) pairs*/
+ NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD && v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2) {
+ NEXT_PAIR(v1, v2, i);
+ }
+ i -= 2; /* compensate for loop's += 2*/
+ } else {
+ /* Configure matched pairs and skip to end */
+ NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD && v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2) {
+ rtl_set_bbreg(hw, array_table[i],
+ MASKDWORD,
+ array_table[i + 1]);
+ udelay(1);
+ NEXT_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < arraylen - 2)
+ NEXT_PAIR(v1, v2, i);
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "The agctab_array_table[0] is %x Rtl818EEPHY_REGArray[1] is %x\n",
+ array_table[i],
+ array_table[i + 1]);
+ }
+}
+
+static void set_baseband_phy_config(struct ieee80211_hw *hw)
+{
+ int i;
+ u32 *array_table;
+ u16 arraylen;
+ u32 v1 = 0, v2 = 0;
+
+ arraylen = RTL8188EEPHY_REG_1TARRAYLEN;
+ array_table = RTL8188EEPHY_REG_1TARRAY;
+
+ for (i = 0; i < arraylen; i += 2) {
+ v1 = array_table[i];
+ v2 = array_table[i + 1];
+ if (v1 < 0xcdcdcdcd) {
+ _rtl8188e_config_bb_reg(hw, v1, v2);
+ } else {/*This line is the start line of branch.*/
+ if (!check_cond(hw, array_table[i])) {
+ /*Discard the following (offset, data) pairs*/
+ NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2)
+ NEXT_PAIR(v1, v2, i);
+ i -= 2; /* prevent from for-loop += 2*/
+ } else {
+ /* Configure matched pairs and skip to end */
+ NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2) {
+ _rtl8188e_config_bb_reg(hw, v1, v2);
+ NEXT_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < arraylen - 2)
+ NEXT_PAIR(v1, v2, i);
+ }
+ }
+ }
+}
+
+static void store_pwrindex_offset(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask,
+ u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (regaddr == RTXAGC_A_RATE18_06) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0]);
+ }
+ if (regaddr == RTXAGC_A_RATE54_24) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1]);
+ }
+ if (regaddr == RTXAGC_A_CCK1_MCS32) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6]);
+ }
+ if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7]);
+ }
+ if (regaddr == RTXAGC_A_MCS03_MCS00) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2]);
+ }
+ if (regaddr == RTXAGC_A_MCS07_MCS04) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3]);
+ }
+ if (regaddr == RTXAGC_A_MCS11_MCS08) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4]);
+ }
+ if (regaddr == RTXAGC_A_MCS15_MCS12) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5] = data;
+ if (get_rf_type(rtlphy) == RF_1T1R)
+ rtlphy->pwrgroup_cnt++;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5]);
+ }
+ if (regaddr == RTXAGC_B_RATE18_06) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8]);
+ }
+ if (regaddr == RTXAGC_B_RATE54_24) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9]);
+ }
+ if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14]);
+ }
+ if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15]);
+ }
+ if (regaddr == RTXAGC_B_MCS03_MCS00) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10]);
+ }
+ if (regaddr == RTXAGC_B_MCS07_MCS04) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11]);
+ }
+ if (regaddr == RTXAGC_B_MCS11_MCS08) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12]);
+ }
+ if (regaddr == RTXAGC_B_MCS15_MCS12) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13]);
+ if (get_rf_type(rtlphy) != RF_1T1R)
+ rtlphy->pwrgroup_cnt++;
+ }
+}
+
+#define READ_NEXT_RF_PAIR(v1, v2, i) \
+ do { \
+ i += 2; v1 = a_table[i]; \
+ v2 = a_table[i + 1]; \
+ } while (0)
+
+bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath)
+{
+ int i;
+ u32 *a_table;
+ u16 a_len;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 v1 = 0, v2 = 0;
+
+ a_len = RTL8188EE_RADIOA_1TARRAYLEN;
+ a_table = RTL8188EE_RADIOA_1TARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Radio_A:RTL8188EE_RADIOA_1TARRAY %d\n", a_len);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+ switch (rfpath) {
+ case RF90_PATH_A:
+ for (i = 0; i < a_len; i = i + 2) {
+ v1 = a_table[i];
+ v2 = a_table[i + 1];
+ if (v1 < 0xcdcdcdcd) {
+ rtl88_config_s(hw, v1, v2);
+ } else {/*This line is the start line of branch.*/
+ if (!check_cond(hw, a_table[i])) {
+ /* Discard the following (offset, data)
+ * pairs
+ */
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD && v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < a_len - 2)
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ i -= 2; /* prevent from for-loop += 2*/
+ } else {
+ /* Configure matched pairs and skip to
+ * end of if-else.
+ */
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD && v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < a_len - 2) {
+ rtl88_config_s(hw, v1, v2);
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < a_len - 2)
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ }
+ }
+ }
+
+ if (rtlhal->oem_id == RT_CID_819x_HP)
+ rtl88_config_s(hw, 0x52, 0x7E4BD);
+
+ break;
+
+ case RF90_PATH_B:
+ case RF90_PATH_C:
+ case RF90_PATH_D:
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ return true;
+}
+
+void rtl88e_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->default_initialgain[0] = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1,
+ MASKBYTE0);
+ rtlphy->default_initialgain[1] = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1,
+ MASKBYTE0);
+ rtlphy->default_initialgain[2] = rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1,
+ MASKBYTE0);
+ rtlphy->default_initialgain[3] = rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1,
+ MASKBYTE0);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Default initial gain (c50 = 0x%x, c58 = 0x%x, c60 = 0x%x, c68 = 0x%x\n",
+ rtlphy->default_initialgain[0],
+ rtlphy->default_initialgain[1],
+ rtlphy->default_initialgain[2],
+ rtlphy->default_initialgain[3]);
+
+ rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
+ MASKBYTE0);
+ rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
+ MASKDWORD);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Default framesync (0x%x) = 0x%x\n",
+ ROFDM0_RXDETECTOR3, rtlphy->framesync);
+}
+
+void rtl88e_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 level;
+ long dbm;
+
+ level = rtlphy->cur_cck_txpwridx;
+ dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_B, level);
+ level = rtlphy->cur_ofdm24g_txpwridx;
+ if (rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_G, level) > dbm)
+ dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_G, level);
+ level = rtlphy->cur_ofdm24g_txpwridx;
+ if (rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_N_24G, level) > dbm)
+ dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_N_24G, level);
+ *powerlevel = dbm;
+}
+
+static void _rtl88e_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
+ u8 *cckpower, u8 *ofdm, u8 *bw20_pwr,
+ u8 *bw40_pwr)
+{
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ u8 i = (channel - 1);
+ u8 rf_path = 0;
+ int jj = RF90_PATH_A;
+ int kk = RF90_PATH_B;
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ if (rf_path == jj) {
+ cckpower[jj] = fuse->txpwrlevel_cck[jj][i];
+ if (fuse->txpwr_ht20diff[jj][i] > 0x0f) /*-8~7 */
+ bw20_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i] -
+ (~(fuse->txpwr_ht20diff[jj][i]) + 1);
+ else
+ bw20_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i] +
+ fuse->txpwr_ht20diff[jj][i];
+ if (fuse->txpwr_legacyhtdiff[jj][i] > 0xf)
+ ofdm[jj] = fuse->txpwrlevel_ht40_1s[jj][i] -
+ (~(fuse->txpwr_legacyhtdiff[jj][i])+1);
+ else
+ ofdm[jj] = fuse->txpwrlevel_ht40_1s[jj][i] +
+ fuse->txpwr_legacyhtdiff[jj][i];
+ bw40_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i];
+
+ } else if (rf_path == kk) {
+ cckpower[kk] = fuse->txpwrlevel_cck[kk][i];
+ bw20_pwr[kk] = fuse->txpwrlevel_ht40_1s[kk][i] +
+ fuse->txpwr_ht20diff[kk][i];
+ ofdm[kk] = fuse->txpwrlevel_ht40_1s[kk][i] +
+ fuse->txpwr_legacyhtdiff[kk][i];
+ bw40_pwr[kk] = fuse->txpwrlevel_ht40_1s[kk][i];
+ }
+ }
+}
+
+static void _rtl88e_ccxpower_index_check(struct ieee80211_hw *hw,
+ u8 channel, u8 *cckpower,
+ u8 *ofdm, u8 *bw20_pwr,
+ u8 *bw40_pwr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->cur_cck_txpwridx = cckpower[0];
+ rtlphy->cur_ofdm24g_txpwridx = ofdm[0];
+ rtlphy->cur_bw20_txpwridx = bw20_pwr[0];
+ rtlphy->cur_bw40_txpwridx = bw40_pwr[0];
+}
+
+void rtl88e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+{
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ u8 cckpower[MAX_TX_COUNT] = {0}, ofdm[MAX_TX_COUNT] = {0};
+ u8 bw20_pwr[MAX_TX_COUNT] = {0}, bw40_pwr[MAX_TX_COUNT] = {0};
+
+ if (fuse->txpwr_fromeprom == false)
+ return;
+ _rtl88e_get_txpower_index(hw, channel, &cckpower[0], &ofdm[0],
+ &bw20_pwr[0], &bw40_pwr[0]);
+ _rtl88e_ccxpower_index_check(hw, channel, &cckpower[0], &ofdm[0],
+ &bw20_pwr[0], &bw40_pwr[0]);
+ rtl88e_phy_rf6052_set_cck_txpower(hw, &cckpower[0]);
+ rtl88e_phy_rf6052_set_ofdm_txpower(hw, &ofdm[0], &bw20_pwr[0],
+ &bw40_pwr[0], channel);
+}
+
+void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ enum io_type iotype;
+
+ if (!is_hal_stop(rtlhal)) {
+ switch (operation) {
+ case SCAN_OPT_BACKUP:
+ iotype = IO_CMD_PAUSE_DM_BY_SCAN;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_IO_CMD,
+ (u8 *)&iotype);
+ break;
+ case SCAN_OPT_RESTORE:
+ iotype = IO_CMD_RESUME_DM_BY_SCAN;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_IO_CMD,
+ (u8 *)&iotype);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Unknown Scan Backup operation.\n");
+ break;
+ }
+ }
+}
+
+void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 reg_bw_opmode;
+ u8 reg_prsr_rsc;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ "Switch to %s bandwidth\n",
+ rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+ "20MHz" : "40MHz");
+
+ if (is_hal_stop(rtlhal)) {
+ rtlphy->set_bwmode_inprogress = false;
+ return;
+ }
+
+ reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+ reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ reg_bw_opmode |= BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+ reg_prsr_rsc =
+ (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
+ rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+ break;
+ }
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+ /* rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);*/
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
+ rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+ (mac->cur_40_prime_sc >> 1));
+ rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+ /*rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);*/
+
+ rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+ (mac->cur_40_prime_sc ==
+ HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+ break;
+ }
+ rtl88e_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+ rtlphy->set_bwmode_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "\n");
+}
+
+void rtl88e_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp_bw = rtlphy->current_chan_bw;
+
+ if (rtlphy->set_bwmode_inprogress)
+ return;
+ rtlphy->set_bwmode_inprogress = true;
+ if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+ rtl88e_phy_set_bw_mode_callback(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "FALSE driver sleep or unload\n");
+ rtlphy->set_bwmode_inprogress = false;
+ rtlphy->current_chan_bw = tmp_bw;
+ }
+}
+
+void rtl88e_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 delay;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ "switch to channel%d\n", rtlphy->current_channel);
+ if (is_hal_stop(rtlhal))
+ return;
+ do {
+ if (!rtlphy->sw_chnl_inprogress)
+ break;
+ if (!chnl_step_by_step(hw, rtlphy->current_channel,
+ &rtlphy->sw_chnl_stage,
+ &rtlphy->sw_chnl_step, &delay)) {
+ if (delay > 0)
+ mdelay(delay);
+ else
+ continue;
+ } else {
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ break;
+ } while (true);
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
+}
+
+u8 rtl88e_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (rtlphy->sw_chnl_inprogress)
+ return 0;
+ if (rtlphy->set_bwmode_inprogress)
+ return 0;
+ RT_ASSERT((rtlphy->current_channel <= 14),
+ "WIRELESS_MODE_G but channel>14");
+ rtlphy->sw_chnl_inprogress = true;
+ rtlphy->sw_chnl_stage = 0;
+ rtlphy->sw_chnl_step = 0;
+ if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+ rtl88e_phy_sw_chnl_callback(hw);
+ RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+ "sw_chnl_inprogress false schdule workitem current channel %d\n",
+ rtlphy->current_channel);
+ rtlphy->sw_chnl_inprogress = false;
+ } else {
+ RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+ "sw_chnl_inprogress false driver sleep or unload\n");
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ return 1;
+}
+
+static u8 _rtl88e_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+ u32 reg_eac, reg_e94, reg_e9c;
+ u8 result = 0x00;
+
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1c);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x30008c1c);
+ rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x8214032a);
+ rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160000);
+
+ rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
+
+ mdelay(IQK_DELAY_TIME);
+
+ reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+ reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
+ reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
+
+ if (!(reg_eac & BIT(28)) &&
+ (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ return result;
+}
+
+static u8 _rtl88e_phy_path_b_iqk(struct ieee80211_hw *hw)
+{
+ u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+ u8 result = 0x00;
+
+ rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002);
+ rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000);
+ mdelay(IQK_DELAY_TIME);
+ reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+ reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
+ reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
+ reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
+ reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
+
+ if (!(reg_eac & BIT(31)) &&
+ (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_ebc & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ else
+ return result;
+ if (!(reg_eac & BIT(30)) &&
+ (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) &&
+ (((reg_ecc & 0x03FF0000) >> 16) != 0x36))
+ result |= 0x02;
+ return result;
+}
+
+static u8 _rtl88e_phy_path_a_rx_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+ u32 reg_eac, reg_e94, reg_e9c, reg_ea4, u32temp;
+ u8 result = 0x00;
+ int jj = RF90_PATH_A;
+
+ /*Get TXIMR Setting*/
+ /*Modify RX IQK mode table*/
+ rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+ rtl_set_rfreg(hw, jj, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+ rtl_set_rfreg(hw, jj, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+ rtl_set_rfreg(hw, jj, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+ rtl_set_rfreg(hw, jj, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b);
+ rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+ /*IQK Setting*/
+ rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+ rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x81004800);
+
+ /*path a IQK setting*/
+ rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x10008c1c);
+ rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x30008c1c);
+ rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82160804);
+ rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28160000);
+
+ /*LO calibration Setting*/
+ rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
+ /*one shot, path A LOK & iqk*/
+ rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+ mdelay(IQK_DELAY_TIME);
+
+ reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+ reg_e94 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_A, MASKDWORD);
+ reg_e9c = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A, MASKDWORD);
+
+
+ if (!(reg_eac & BIT(28)) &&
+ (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ else
+ return result;
+
+ u32temp = 0x80007C00 | (reg_e94&0x3FF0000) |
+ ((reg_e9c&0x3FF0000) >> 16);
+ rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, u32temp);
+ /*RX IQK*/
+ /*Modify RX IQK mode table*/
+ rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+ rtl_set_rfreg(hw, jj, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+ rtl_set_rfreg(hw, jj, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+ rtl_set_rfreg(hw, jj, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+ rtl_set_rfreg(hw, jj, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa);
+ rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+ /*IQK Setting*/
+ rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+ /*path a IQK setting*/
+ rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x30008c1c);
+ rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x10008c1c);
+ rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82160c05);
+ rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28160c05);
+
+ /*LO calibration Setting*/
+ rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
+ /*one shot, path A LOK & iqk*/
+ rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+ mdelay(IQK_DELAY_TIME);
+
+ reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+ reg_e94 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_A, MASKDWORD);
+ reg_e9c = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A, MASKDWORD);
+ reg_ea4 = rtl_get_bbreg(hw, RRX_POWER_BEFORE_IQK_A_2, MASKDWORD);
+
+ if (!(reg_eac & BIT(27)) &&
+ (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
+ (((reg_eac & 0x03FF0000) >> 16) != 0x36))
+ result |= 0x02;
+ return result;
+}
+
+static void fill_iqk(struct ieee80211_hw *hw, bool iqk_ok, long result[][8],
+ u8 final, bool btxonly)
+{
+ u32 oldval_0, x, tx0_a, reg;
+ long y, tx0_c;
+
+ if (final == 0xFF) {
+ return;
+ } else if (iqk_ok) {
+ oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBAL,
+ MASKDWORD) >> 22) & 0x3FF;
+ x = result[final][0];
+ if ((x & 0x00000200) != 0)
+ x = x | 0xFFFFFC00;
+ tx0_a = (x * oldval_0) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, 0x3FF, tx0_a);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(31),
+ ((x * oldval_0 >> 7) & 0x1));
+ y = result[final][1];
+ if ((y & 0x00000200) != 0)
+ y |= 0xFFFFFC00;
+ tx0_c = (y * oldval_0) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
+ ((tx0_c & 0x3C0) >> 6));
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, 0x003F0000,
+ (tx0_c & 0x3F));
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(29),
+ ((y * oldval_0 >> 7) & 0x1));
+ if (btxonly)
+ return;
+ reg = result[final][2];
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBAL, 0x3FF, reg);
+ reg = result[final][3] & 0x3F;
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBAL, 0xFC00, reg);
+ reg = (result[final][3] >> 6) & 0xF;
+ rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
+ }
+}
+
+static void save_adda_reg(struct ieee80211_hw *hw,
+ const u32 *addareg, u32 *backup,
+ u32 registernum)
+{
+ u32 i;
+
+ for (i = 0; i < registernum; i++)
+ backup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
+}
+
+static void save_mac_reg(struct ieee80211_hw *hw, const u32 *macreg,
+ u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+ macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
+ macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
+}
+
+static void reload_adda(struct ieee80211_hw *hw, const u32 *addareg,
+ u32 *backup, u32 reg_num)
+{
+ u32 i;
+
+ for (i = 0; i < reg_num; i++)
+ rtl_set_bbreg(hw, addareg[i], MASKDWORD, backup[i]);
+}
+
+static void reload_mac(struct ieee80211_hw *hw, const u32 *macreg,
+ u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+ rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
+ rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
+}
+
+static void _rtl88e_phy_path_adda_on(struct ieee80211_hw *hw,
+ const u32 *addareg, bool is_patha_on,
+ bool is2t)
+{
+ u32 pathon;
+ u32 i;
+
+ pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
+ if (false == is2t) {
+ pathon = 0x0bdb25a0;
+ rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
+ } else {
+ rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon);
+ }
+
+ for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+ rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathon);
+}
+
+static void _rtl88e_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+ const u32 *macreg,
+ u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i = 0;
+
+ rtl_write_byte(rtlpriv, macreg[i], 0x3F);
+
+ for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
+ rtl_write_byte(rtlpriv, macreg[i],
+ (u8) (macbackup[i] & (~BIT(3))));
+ rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
+}
+
+static void _rtl88e_phy_path_a_standby(struct ieee80211_hw *hw)
+{
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+}
+
+static void _rtl88e_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode)
+{
+ u32 mode;
+
+ mode = pi_mode ? 0x01000100 : 0x01000000;
+ rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
+ rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
+}
+
+static bool sim_comp(struct ieee80211_hw *hw, long result[][8], u8 c1, u8 c2)
+{
+ u32 i, j, diff, bitmap, bound;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ u8 final[2] = {0xFF, 0xFF};
+ bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version);
+
+ if (is2t)
+ bound = 8;
+ else
+ bound = 4;
+
+ bitmap = 0;
+
+ for (i = 0; i < bound; i++) {
+ diff = (result[c1][i] > result[c2][i]) ?
+ (result[c1][i] - result[c2][i]) :
+ (result[c2][i] - result[c1][i]);
+
+ if (diff > MAX_TOLERANCE) {
+ if ((i == 2 || i == 6) && !bitmap) {
+ if (result[c1][i] + result[c1][i + 1] == 0)
+ final[(i / 4)] = c2;
+ else if (result[c2][i] + result[c2][i + 1] == 0)
+ final[(i / 4)] = c1;
+ else
+ bitmap = bitmap | (1 << i);
+ } else {
+ bitmap = bitmap | (1 << i);
+ }
+ }
+ }
+
+ if (bitmap == 0) {
+ for (i = 0; i < (bound / 4); i++) {
+ if (final[i] != 0xFF) {
+ for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+ result[3][j] = result[final[i]][j];
+ bresult = false;
+ }
+ }
+ return bresult;
+ } else if (!(bitmap & 0x0F)) {
+ for (i = 0; i < 4; i++)
+ result[3][i] = result[c1][i];
+ return false;
+ } else if (!(bitmap & 0xF0) && is2t) {
+ for (i = 4; i < 8; i++)
+ result[3][i] = result[c1][i];
+ return false;
+ } else {
+ return false;
+ }
+}
+
+static void _rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw,
+ long result[][8], u8 t, bool is2t)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 i;
+ u8 patha_ok, pathb_ok;
+ const u32 adda_reg[IQK_ADDA_REG_NUM] = {
+ 0x85c, 0xe6c, 0xe70, 0xe74,
+ 0xe78, 0xe7c, 0xe80, 0xe84,
+ 0xe88, 0xe8c, 0xed0, 0xed4,
+ 0xed8, 0xedc, 0xee0, 0xeec
+ };
+ const u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
+ 0x522, 0x550, 0x551, 0x040
+ };
+ const u32 iqk_bb_reg[IQK_BB_REG_NUM] = {
+ ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR, RFPGA0_XCD_RFINTERFACESW,
+ 0xb68, 0xb6c, 0x870, 0x860, 0x864, 0x800
+ };
+ const u32 retrycount = 2;
+
+ if (t == 0) {
+ save_adda_reg(hw, adda_reg, rtlphy->adda_backup, 16);
+ save_mac_reg(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+ save_adda_reg(hw, iqk_bb_reg, rtlphy->iqk_bb_backup,
+ IQK_BB_REG_NUM);
+ }
+ _rtl88e_phy_path_adda_on(hw, adda_reg, true, is2t);
+ if (t == 0) {
+ rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER1, BIT(8));
+ }
+
+ if (!rtlphy->rfpi_enable)
+ _rtl88e_phy_pi_mode_switch(hw, true);
+ /*BB Setting*/
+ rtl_set_bbreg(hw, 0x800, BIT(24), 0x00);
+ rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
+ rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
+ rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
+
+ rtl_set_bbreg(hw, 0x870, BIT(10), 0x01);
+ rtl_set_bbreg(hw, 0x870, BIT(26), 0x01);
+ rtl_set_bbreg(hw, 0x860, BIT(10), 0x00);
+ rtl_set_bbreg(hw, 0x864, BIT(10), 0x00);
+
+ if (is2t) {
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+ rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
+ }
+ _rtl88e_phy_mac_setting_calibration(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
+ rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
+ if (is2t)
+ rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000);
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+ rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
+ rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x81004800);
+ for (i = 0; i < retrycount; i++) {
+ patha_ok = _rtl88e_phy_path_a_iqk(hw, is2t);
+ if (patha_ok == 0x01) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path A Tx IQK Success!!\n");
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ }
+ }
+
+ for (i = 0; i < retrycount; i++) {
+ patha_ok = _rtl88e_phy_path_a_rx_iqk(hw, is2t);
+ if (patha_ok == 0x03) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path A Rx IQK Success!!\n");
+ result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path a RX iqk fail!!!\n");
+ }
+ }
+
+ if (0 == patha_ok) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path A IQK Success!!\n");
+ }
+ if (is2t) {
+ _rtl88e_phy_path_a_standby(hw);
+ _rtl88e_phy_path_adda_on(hw, adda_reg, false, is2t);
+ for (i = 0; i < retrycount; i++) {
+ pathb_ok = _rtl88e_phy_path_b_iqk(hw);
+ if (pathb_ok == 0x03) {
+ result[t][4] = (rtl_get_bbreg(hw,
+ 0xeb4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][5] =
+ (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][6] =
+ (rtl_get_bbreg(hw, 0xec4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][7] =
+ (rtl_get_bbreg(hw, 0xecc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ } else if (i == (retrycount - 1) && pathb_ok == 0x01) {
+ result[t][4] = (rtl_get_bbreg(hw,
+ 0xeb4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ }
+ result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ }
+ }
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
+
+ if (t != 0) {
+ if (!rtlphy->rfpi_enable)
+ _rtl88e_phy_pi_mode_switch(hw, false);
+ reload_adda(hw, adda_reg, rtlphy->adda_backup, 16);
+ reload_mac(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+ reload_adda(hw, iqk_bb_reg, rtlphy->iqk_bb_backup,
+ IQK_BB_REG_NUM);
+
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
+ if (is2t)
+ rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "88ee IQK Finish!!\n");
+}
+
+static void _rtl88e_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
+{
+ u8 tmpreg;
+ u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int jj = RF90_PATH_A;
+ int kk = RF90_PATH_B;
+
+ tmpreg = rtl_read_byte(rtlpriv, 0xd03);
+
+ if ((tmpreg & 0x70) != 0)
+ rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F);
+ else
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+
+ if ((tmpreg & 0x70) != 0) {
+ rf_a_mode = rtl_get_rfreg(hw, jj, 0x00, MASK12BITS);
+
+ if (is2t)
+ rf_b_mode = rtl_get_rfreg(hw, kk, 0x00,
+ MASK12BITS);
+
+ rtl_set_rfreg(hw, jj, 0x00, MASK12BITS,
+ (rf_a_mode & 0x8FFFF) | 0x10000);
+
+ if (is2t)
+ rtl_set_rfreg(hw, kk, 0x00, MASK12BITS,
+ (rf_b_mode & 0x8FFFF) | 0x10000);
+ }
+ lc_cal = rtl_get_rfreg(hw, jj, 0x18, MASK12BITS);
+
+ rtl_set_rfreg(hw, jj, 0x18, MASK12BITS, lc_cal | 0x08000);
+
+ mdelay(100);
+
+ if ((tmpreg & 0x70) != 0) {
+ rtl_write_byte(rtlpriv, 0xd03, tmpreg);
+ rtl_set_rfreg(hw, jj, 0x00, MASK12BITS, rf_a_mode);
+
+ if (is2t)
+ rtl_set_rfreg(hw, kk, 0x00, MASK12BITS,
+ rf_b_mode);
+ } else {
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+}
+
+static void rfpath_switch(struct ieee80211_hw *hw,
+ bool bmain, bool is2t)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+
+ if (is_hal_stop(rtlhal)) {
+ u8 u1btmp;
+ u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0);
+ rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7));
+ rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+ }
+ if (is2t) {
+ if (bmain)
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(6), 0x1);
+ else
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(6), 0x2);
+ } else {
+ rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0);
+ rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201);
+
+ /* We use the RF definition of MAIN and AUX, left antenna and
+ * right antenna repectively.
+ * Default output at AUX.
+ */
+ if (bmain) {
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(14) |
+ BIT(13) | BIT(12), 0);
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(5) |
+ BIT(4) | BIT(3), 0);
+ if (fuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtl_set_bbreg(hw, RCONFIG_RAM64X16, BIT(31), 0);
+ } else {
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(14) |
+ BIT(13) | BIT(12), 1);
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(5) |
+ BIT(4) | BIT(3), 1);
+ if (fuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtl_set_bbreg(hw, RCONFIG_RAM64X16, BIT(31), 1);
+ }
+ }
+}
+
+#undef IQK_ADDA_REG_NUM
+#undef IQK_DELAY_TIME
+
+void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ long result[4][8];
+ u8 i, final;
+ bool patha_ok;
+ long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0;
+ bool is12simular, is13simular, is23simular;
+ u32 iqk_bb_reg[9] = {
+ ROFDM0_XARXIQIMBAL,
+ ROFDM0_XBRXIQIMBAL,
+ ROFDM0_ECCATHRES,
+ ROFDM0_AGCRSSITABLE,
+ ROFDM0_XATXIQIMBAL,
+ ROFDM0_XBTXIQIMBAL,
+ ROFDM0_XCTXAFE,
+ ROFDM0_XDTXAFE,
+ ROFDM0_RXIQEXTANTA
+ };
+
+ if (recovery) {
+ reload_adda(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+ return;
+ }
+
+ memset(result, 0, 32 * sizeof(long));
+ final = 0xff;
+ patha_ok = false;
+ is12simular = false;
+ is23simular = false;
+ is13simular = false;
+ for (i = 0; i < 3; i++) {
+ if (get_rf_type(rtlphy) == RF_2T2R)
+ _rtl88e_phy_iq_calibrate(hw, result, i, true);
+ else
+ _rtl88e_phy_iq_calibrate(hw, result, i, false);
+ if (i == 1) {
+ is12simular = sim_comp(hw, result, 0, 1);
+ if (is12simular) {
+ final = 0;
+ break;
+ }
+ }
+ if (i == 2) {
+ is13simular = sim_comp(hw, result, 0, 2);
+ if (is13simular) {
+ final = 0;
+ break;
+ }
+ is23simular = sim_comp(hw, result, 1, 2);
+ if (is23simular) {
+ final = 1;
+ } else {
+ for (i = 0; i < 8; i++)
+ reg_tmp += result[3][i];
+
+ if (reg_tmp != 0)
+ final = 3;
+ else
+ final = 0xFF;
+ }
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ reg_e94 = result[i][0];
+ reg_e9c = result[i][1];
+ reg_ea4 = result[i][2];
+ reg_eb4 = result[i][4];
+ reg_ebc = result[i][5];
+ }
+ if (final != 0xff) {
+ reg_e94 = result[final][0];
+ rtlphy->reg_e94 = reg_e94;
+ reg_e9c = result[final][1];
+ rtlphy->reg_e9c = reg_e9c;
+ reg_ea4 = result[final][2];
+ reg_eb4 = result[final][4];
+ rtlphy->reg_eb4 = reg_eb4;
+ reg_ebc = result[final][5];
+ rtlphy->reg_ebc = reg_ebc;
+ patha_ok = true;
+ } else {
+ rtlphy->reg_e94 = 0x100;
+ rtlphy->reg_eb4 = 0x100;
+ rtlphy->reg_ebc = 0x0;
+ rtlphy->reg_e9c = 0x0;
+ }
+ if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
+ fill_iqk(hw, patha_ok, result, final, (reg_ea4 == 0));
+ if (final != 0xFF) {
+ for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
+ rtlphy->iqk_matrix[0].value[0][i] = result[final][i];
+ rtlphy->iqk_matrix[0].iqk_done = true;
+ }
+ save_adda_reg(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+}
+
+void rtl88e_phy_lc_calibrate(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
+ bool start_conttx = false, singletone = false;
+ u32 timeout = 2000, timecount = 0;
+
+ if (start_conttx || singletone)
+ return;
+
+ while (rtlpriv->mac80211.act_scanning && timecount < timeout) {
+ udelay(50);
+ timecount += 50;
+ }
+
+ rtlphy->lck_inprogress = true;
+ RTPRINT(rtlpriv, FINIT, INIT_IQK,
+ "LCK:Start!!! currentband %x delay %d ms\n",
+ rtlhal->current_bandtype, timecount);
+
+ _rtl88e_phy_lc_calibrate(hw, false);
+
+ rtlphy->lck_inprogress = false;
+}
+
+void rtl88e_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+{
+ rfpath_switch(hw, bmain, false);
+}
+
+bool rtl88e_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ bool postprocessing = false;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
+ iotype, rtlphy->set_io_inprogress);
+ do {
+ switch (iotype) {
+ case IO_CMD_RESUME_DM_BY_SCAN:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "[IO CMD] Resume DM after scan.\n");
+ postprocessing = true;
+ break;
+ case IO_CMD_PAUSE_DM_BY_SCAN:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "[IO CMD] Pause DM before scan.\n");
+ postprocessing = true;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ } while (false);
+ if (postprocessing && !rtlphy->set_io_inprogress) {
+ rtlphy->set_io_inprogress = true;
+ rtlphy->current_io_type = iotype;
+ } else {
+ return false;
+ }
+ rtl88e_phy_set_io(hw);
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype);
+ return true;
+}
+
+static void rtl88ee_phy_set_rf_on(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ /*rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);*/
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+}
+
+static void _rtl88ee_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int jj = RF90_PATH_A;
+
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+ rtl_set_rfreg(hw, jj, 0x00, RFREG_OFFSET_MASK, 0x00);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
+static bool _rtl88ee_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl8192_tx_ring *ring = NULL;
+ bool bresult = true;
+ u8 i, queue_id;
+
+ switch (rfpwr_state) {
+ case ERFON:{
+ if ((ppsc->rfpwr_state == ERFOFF) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+ bool rtstatus;
+ u32 init = 0;
+ do {
+ init++;
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "IPS Set eRf nic enable\n");
+ rtstatus = rtl_ps_enable_nic(hw);
+ } while ((rtstatus != true) && (init < 10));
+ RT_CLEAR_PS_LEVEL(ppsc,
+ RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "Set ERFON sleeped:%d ms\n",
+ jiffies_to_msecs(jiffies - ppsc->
+ last_sleep_jiffies));
+ ppsc->last_awake_jiffies = jiffies;
+ rtl88ee_phy_set_rf_on(hw);
+ }
+ if (mac->link_state == MAC80211_LINKED)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK);
+ else
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK);
+ break; }
+ case ERFOFF:{
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+ (i + 1), queue_id,
+ skb_queue_len(&ring->queue));
+
+ udelay(10);
+ i++;
+ }
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue));
+ break;
+ }
+ }
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "IPS Set eRf nic disable\n");
+ rtl_ps_disable_nic(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ } else {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_POWER_OFF);
+ }
+ }
+ break; }
+ case ERFSLEEP:{
+ if (ppsc->rfpwr_state == ERFOFF)
+ break;
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+ (i + 1), queue_id,
+ skb_queue_len(&ring->queue));
+
+ udelay(10);
+ i++;
+ }
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue));
+ break;
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "Set ERFSLEEP awaked:%d ms\n",
+ jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies));
+ ppsc->last_sleep_jiffies = jiffies;
+ _rtl88ee_phy_set_rf_sleep(hw);
+ break; }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ bresult = false;
+ break;
+ }
+ if (bresult)
+ ppsc->rfpwr_state = rfpwr_state;
+ return bresult;
+}
+
+bool rtl88e_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool bresult;
+
+ if (rfpwr_state == ppsc->rfpwr_state)
+ return false;
+ bresult = _rtl88ee_phy_set_rf_power_state(hw, rfpwr_state);
+ return bresult;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h
new file mode 100644
index 000000000000..f1acd6d27e44
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h
@@ -0,0 +1,236 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_PHY_H__
+#define __RTL92C_PHY_H__
+
+/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
+#define MAX_TX_COUNT 4
+
+#define MAX_PRECMD_CNT 16
+#define MAX_RFDEPENDCMD_CNT 16
+#define MAX_POSTCMD_CNT 16
+
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+#define RT_CANNOT_IO(hw) false
+#define HIGHPOWER_RADIOA_ARRAYLEN 22
+
+#define IQK_ADDA_REG_NUM 16
+#define IQK_BB_REG_NUM 9
+#define MAX_TOLERANCE 5
+#define IQK_DELAY_TIME 10
+#define IDX_MAP 15
+
+#define APK_BB_REG_NUM 5
+#define APK_AFE_REG_NUM 16
+#define APK_CURVE_REG_NUM 4
+#define PATH_NUM 2
+
+#define LOOP_LIMIT 5
+#define MAX_STALL_TIME 50
+#define ANTENNADIVERSITYVALUE 0x80
+#define MAX_TXPWR_IDX_NMODE_92S 63
+#define RESET_CNT_LIMIT 3
+
+#define IQK_ADDA_REG_NUM 16
+#define IQK_MAC_REG_NUM 4
+
+#define RF6052_MAX_PATH 2
+
+#define CT_OFFSET_MAC_ADDR 0X16
+
+#define CT_OFFSET_CCK_TX_PWR_IDX 0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX 0x60
+#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF 0x66
+#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF 0x69
+#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF 0x6C
+
+#define CT_OFFSET_HT40_MAX_PWR_OFFSET 0x6F
+#define CT_OFFSET_HT20_MAX_PWR_OFFSET 0x72
+
+#define CT_OFFSET_CHANNEL_PLAH 0x75
+#define CT_OFFSET_THERMAL_METER 0x78
+#define CT_OFFSET_RF_OPTION 0x79
+#define CT_OFFSET_VERSION 0x7E
+#define CT_OFFSET_CUSTOMER_ID 0x7F
+
+#define RTL92C_MAX_PATH_NUM 2
+
+enum swchnlcmd_id {
+ CMDID_END,
+ CMDID_SET_TXPOWEROWER_LEVEL,
+ CMDID_BBREGWRITE10,
+ CMDID_WRITEPORT_ULONG,
+ CMDID_WRITEPORT_USHORT,
+ CMDID_WRITEPORT_UCHAR,
+ CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+ enum swchnlcmd_id cmdid;
+ u32 para1;
+ u32 para2;
+ u32 msdelay;
+};
+
+enum hw90_block_e {
+ HW90_BLOCK_MAC = 0,
+ HW90_BLOCK_PHY0 = 1,
+ HW90_BLOCK_PHY1 = 2,
+ HW90_BLOCK_RF = 3,
+ HW90_BLOCK_MAXIMUM = 4,
+};
+
+enum baseband_config_type {
+ BASEBAND_CONFIG_PHY_REG = 0,
+ BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+enum ra_offset_area {
+ RA_OFFSET_LEGACY_OFDM1,
+ RA_OFFSET_LEGACY_OFDM2,
+ RA_OFFSET_HT_OFDM1,
+ RA_OFFSET_HT_OFDM2,
+ RA_OFFSET_HT_OFDM3,
+ RA_OFFSET_HT_OFDM4,
+ RA_OFFSET_HT_CCK,
+};
+
+enum antenna_path {
+ ANTENNA_NONE,
+ ANTENNA_D,
+ ANTENNA_C,
+ ANTENNA_CD,
+ ANTENNA_B,
+ ANTENNA_BD,
+ ANTENNA_BC,
+ ANTENNA_BCD,
+ ANTENNA_A,
+ ANTENNA_AD,
+ ANTENNA_AC,
+ ANTENNA_ACD,
+ ANTENNA_AB,
+ ANTENNA_ABD,
+ ANTENNA_ABC,
+ ANTENNA_ABCD
+};
+
+struct r_antenna_select_ofdm {
+ u32 r_tx_antenna:4;
+ u32 r_ant_l:4;
+ u32 r_ant_non_ht:4;
+ u32 r_ant_ht1:4;
+ u32 r_ant_ht2:4;
+ u32 r_ant_ht_s1:4;
+ u32 r_ant_non_ht_s1:4;
+ u32 ofdm_txsc:2;
+ u32 reserved:2;
+};
+
+struct r_antenna_select_cck {
+ u8 r_cckrx_enable_2:2;
+ u8 r_cckrx_enable:2;
+ u8 r_ccktx_enable:4;
+};
+
+
+struct efuse_contents {
+ u8 mac_addr[ETH_ALEN];
+ u8 cck_tx_power_idx[6];
+ u8 ht40_1s_tx_power_idx[6];
+ u8 ht40_2s_tx_power_idx_diff[3];
+ u8 ht20_tx_power_idx_diff[3];
+ u8 ofdm_tx_power_idx_diff[3];
+ u8 ht40_max_power_offset[3];
+ u8 ht20_max_power_offset[3];
+ u8 channel_plan;
+ u8 thermal_meter;
+ u8 rf_option[5];
+ u8 version;
+ u8 oem_id;
+ u8 regulatory;
+};
+
+struct tx_power_struct {
+ u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 legacy_ht_txpowerdiff;
+ u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 pwrgroup_cnt;
+ u32 mcs_original_offset[4][16];
+};
+
+enum _ANT_DIV_TYPE {
+ NO_ANTDIV = 0xFF,
+ CG_TRX_HW_ANTDIV = 0x01,
+ CGCS_RX_HW_ANTDIV = 0x02,
+ FIXED_HW_ANTDIV = 0x03,
+ CG_TRX_SMART_ANTDIV = 0x04,
+ CGCS_RX_SW_ANTDIV = 0x05,
+};
+
+extern u32 rtl88e_phy_query_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask);
+extern void rtl88e_phy_set_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask, u32 data);
+extern u32 rtl88e_phy_query_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask);
+extern void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask, u32 data);
+extern bool rtl88e_phy_mac_config(struct ieee80211_hw *hw);
+extern bool rtl88e_phy_bb_config(struct ieee80211_hw *hw);
+extern bool rtl88e_phy_rf_config(struct ieee80211_hw *hw);
+extern void rtl88e_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+extern void rtl88e_phy_get_txpower_level(struct ieee80211_hw *hw,
+ long *powerlevel);
+extern void rtl88e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+extern void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw,
+ u8 operation);
+extern void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+extern void rtl88e_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type);
+extern void rtl88e_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+extern u8 rtl88e_phy_sw_chnl(struct ieee80211_hw *hw);
+extern void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+void rtl88e_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl88e_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath);
+bool rtl88e_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+extern bool rtl88e_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
new file mode 100644
index 000000000000..6dc4e3a954f6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseqcmd.h"
+#include "pwrseq.h"
+
+/* drivers should parse below arrays and do the corresponding actions */
+/*3 Power on Array*/
+struct wlan_pwr_cfg rtl8188e_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS +
+ RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/*3Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8188e_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_END
+};
+
+/*3Card Disable Array*/
+struct wlan_pwr_cfg rtl8188e_card_disable_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_CARDDIS
+ RTL8188E_TRANS_END
+};
+
+/*3 Card Enable Array*/
+struct wlan_pwr_cfg rtl8188e_card_enable_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_CARDDIS_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/*3Suspend Array*/
+struct wlan_pwr_cfg rtl8188e_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_SUS
+ RTL8188E_TRANS_END
+};
+
+/*3 Resume Array*/
+struct wlan_pwr_cfg rtl8188e_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_SUS_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/*3HWPDN Array*/
+struct wlan_pwr_cfg rtl8188e_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_PDN
+ RTL8188E_TRANS_END
+};
+
+/*3 Enter LPS */
+struct wlan_pwr_cfg rtl8188e_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ /*FW behavior*/
+ RTL8188E_TRANS_ACT_TO_LPS
+ RTL8188E_TRANS_END
+};
+
+/*3 Leave LPS */
+struct wlan_pwr_cfg rtl8188e_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ /*FW behavior*/
+ RTL8188E_TRANS_LPS_TO_ACT
+ RTL8188E_TRANS_END
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
new file mode 100644
index 000000000000..028ec6dd52b4
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
@@ -0,0 +1,327 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_PWRSEQ_H__
+#define __RTL8723E_PWRSEQ_H__
+
+#include "pwrseqcmd.h"
+/*
+ Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd
+ There are 6 HW Power States:
+ 0: POFF--Power Off
+ 1: PDN--Power Down
+ 2: CARDEMU--Card Emulation
+ 3: ACT--Active Mode
+ 4: LPS--Low Power State
+ 5: SUS--Suspend
+
+ The transision from different states are defined below
+ TRANS_CARDEMU_TO_ACT
+ TRANS_ACT_TO_CARDEMU
+ TRANS_CARDEMU_TO_SUS
+ TRANS_SUS_TO_CARDEMU
+ TRANS_CARDEMU_TO_PDN
+ TRANS_ACT_TO_LPS
+ TRANS_LPS_TO_ACT
+
+ TRANS_END
+ PWR SEQ Version: rtl8188e_PwrSeq_V09.h
+*/
+
+#define RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS 10
+#define RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS 10
+#define RTL8188E_TRANS_SUS_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS 10
+#define RTL8188E_TRANS_PDN_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_ACT_TO_LPS_STEPS 15
+#define RTL8188E_TRANS_LPS_TO_ACT_STEPS 15
+#define RTL8188E_TRANS_END_STEPS 1
+
+
+#define RTL8188E_TRANS_CARDEMU_TO_ACT \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /* wait till 0x04[17] = 1 power ready*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /* 0x02[1:0] = 0 reset BB*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0)|BIT(1), 0}, \
+ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x24[23] = 2b'01 schmit trigger */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /* 0x04[15] = 0 disable HWPDN (control by DRV)*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x04[12:11] = 2b'00 disable WL suspend*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x04[8] = 1 polling until return 0*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*wait till 0x04[8] = 0*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0}, \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*LDO normal mode*/\
+ {0x0074, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*SDIO Driving*/\
+
+#define RTL8188E_TRANS_ACT_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/\
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*LDO Sleep mode*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x04[9] = 1 turn off MAC by HW state machine*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0}, \
+
+
+#define RTL8188E_TRANS_CARDEMU_TO_SUS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ /*0x04[12:11] = 2b'11enable WL suspend for PCIe*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)},\
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, BIT(7)}, \
+ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*Clear SIC_EN register 0x40[12] = 1'b0 */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*Set USB suspend enable local register 0xfe10[4]= 1 */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*Set SDIO suspend local register*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*wait power state to suspend*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8188E_TRANS_SUS_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*Set SDIO suspend local register*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*wait power state to suspend*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
+
+#define RTL8188E_TRANS_CARDEMU_TO_CARDDIS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x24[23] = 2b'01 schmit trigger */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*0x04[12:11] = 2b'01 enable WL suspend*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, \
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, \
+ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*Clear SIC_EN register 0x40[12] = 1'b0 */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \
+ /*Set USB suspend enable local register 0xfe10[4]= 1 */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*Set SDIO suspend local register*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/
+
+#define RTL8188E_TRANS_CARDDIS_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO,\
+ PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO,\
+ PWR_CMD_POLLING, BIT(1), BIT(1)}, /*wait power state to suspend*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, \
+ PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, \
+ /*0x04[12:11] = 2b'01enable WL suspend*/
+
+
+#define RTL8188E_TRANS_CARDEMU_TO_PDN \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},/* 0x04[16] = 0*/ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},/* 0x04[15] = 1*/
+
+
+#define RTL8188E_TRANS_PDN_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},/* 0x04[15] = 0*/
+
+
+#define RTL8188E_TRANS_ACT_TO_LPS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \
+ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*zero if no pkt is tx*/\
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Should be zero if no packet is transmitting*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Should be zero if no packet is transmitting*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Should be zero if no packet is transmitting*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*CCK and OFDM are disabled, and clock are gated*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/\
+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/ \
+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*check if removed later*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \
+ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Respond TxOK to scheduler*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}, \
+
+
+#define RTL8188E_TRANS_LPS_TO_ACT \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/ \
+ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/ \
+ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/ \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/ \
+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x08[4] = 0 switch TSF to 40M*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Polling 0x109[7]= 0 TSF in 40M*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0}, \
+ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x29[7:6] = 2b'00 enable BB clock*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0}, \
+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x101[1] = 1*/\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x02[1:0] = 2b'11 enable BB macro*/\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1)|BIT(0), BIT(1)|BIT(0)}, \
+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/
+
+
+#define RTL8188E_TRANS_END \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+ 0, PWR_CMD_END, 0, 0}
+
+extern struct wlan_pwr_cfg rtl8188e_power_on_flow
+ [RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_radio_off_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_card_disable_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_card_enable_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_suspend_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_resume_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_hwpdn_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_enter_lps_flow
+ [RTL8188E_TRANS_ACT_TO_LPS_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_leave_lps_flow
+ [RTL8188E_TRANS_LPS_TO_ACT_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+
+/* RTL8723 Power Configuration CMDs for PCIe interface */
+#define Rtl8188E_NIC_PWR_ON_FLOW rtl8188e_power_on_flow
+#define Rtl8188E_NIC_RF_OFF_FLOW rtl8188e_radio_off_flow
+#define Rtl8188E_NIC_DISABLE_FLOW rtl8188e_card_disable_flow
+#define Rtl8188E_NIC_ENABLE_FLOW rtl8188e_card_enable_flow
+#define Rtl8188E_NIC_SUSPEND_FLOW rtl8188e_suspend_flow
+#define Rtl8188E_NIC_RESUME_FLOW rtl8188e_resume_flow
+#define Rtl8188E_NIC_PDN_FLOW rtl8188e_hwpdn_flow
+#define Rtl8188E_NIC_LPS_ENTER_FLOW rtl8188e_enter_lps_flow
+#define Rtl8188E_NIC_LPS_LEAVE_FLOW rtl8188e_leave_lps_flow
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c
new file mode 100644
index 000000000000..a9cfa13be3a8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseq.h"
+
+
+/* Description:
+ * This routine deal with the Power Configuration CMDs
+ * parsing for RTL8723/RTL8188E Series IC.
+ * Assumption:
+ * We should follow specific format which was released from HW SD.
+ *
+ * 2011.07.07, added by Roger.
+ */
+
+bool rtl88_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+ u8 fab_version, u8 interface_type,
+ struct wlan_pwr_cfg pwrcfgcmd[])
+{
+ struct wlan_pwr_cfg cmd = {0};
+ bool polling_bit = false;
+ u32 ary_idx = 0;
+ u8 val = 0;
+ u32 offset = 0;
+ u32 polling_count = 0;
+ u32 max_polling_cnt = 5000;
+
+ do {
+ cmd = pwrcfgcmd[ary_idx];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): offset(%#x), cut_msk(%#x), fab_msk(%#x),"
+ "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), val(%#x)\n",
+ GET_PWR_CFG_OFFSET(cmd),
+ GET_PWR_CFG_CUT_MASK(cmd),
+ GET_PWR_CFG_FAB_MASK(cmd),
+ GET_PWR_CFG_INTF_MASK(cmd),
+ GET_PWR_CFG_BASE(cmd),
+ GET_PWR_CFG_CMD(cmd),
+ GET_PWR_CFG_MASK(cmd),
+ GET_PWR_CFG_VALUE(cmd));
+
+ if ((GET_PWR_CFG_FAB_MASK(cmd) & fab_version) &&
+ (GET_PWR_CFG_CUT_MASK(cmd) & cut_version) &&
+ (GET_PWR_CFG_INTF_MASK(cmd) & interface_type)) {
+ switch (GET_PWR_CFG_CMD(cmd)) {
+ case PWR_CMD_READ:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
+ break;
+ case PWR_CMD_WRITE: {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
+ offset = GET_PWR_CFG_OFFSET(cmd);
+
+ /*Read the val from system register*/
+ val = rtl_read_byte(rtlpriv, offset);
+ val &= (~(GET_PWR_CFG_MASK(cmd)));
+ val |= (GET_PWR_CFG_VALUE(cmd) &
+ GET_PWR_CFG_MASK(cmd));
+
+ /*Write the val back to sytem register*/
+ rtl_write_byte(rtlpriv, offset, val);
+ }
+ break;
+ case PWR_CMD_POLLING:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
+ polling_bit = false;
+ offset = GET_PWR_CFG_OFFSET(cmd);
+
+ do {
+ val = rtl_read_byte(rtlpriv, offset);
+
+ val = val & GET_PWR_CFG_MASK(cmd);
+ if (val == (GET_PWR_CFG_VALUE(cmd) &
+ GET_PWR_CFG_MASK(cmd)))
+ polling_bit = true;
+ else
+ udelay(10);
+
+ if (polling_count++ > max_polling_cnt) {
+ RT_TRACE(rtlpriv, COMP_INIT,
+ DBG_LOUD,
+ "polling fail in pwrseqcmd\n");
+ return false;
+ }
+ } while (!polling_bit);
+
+ break;
+ case PWR_CMD_DELAY:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
+ if (GET_PWR_CFG_VALUE(cmd) == PWRSEQ_DELAY_US)
+ udelay(GET_PWR_CFG_OFFSET(cmd));
+ else
+ mdelay(GET_PWR_CFG_OFFSET(cmd));
+ break;
+ case PWR_CMD_END:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
+ return true;
+ break;
+ default:
+ RT_ASSERT(false,
+ "rtl88_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
+ break;
+ }
+ }
+
+ ary_idx++;
+ } while (1);
+
+ return true;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h
new file mode 100644
index 000000000000..d9ae280bb1a2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_PWRSEQCMD_H__
+#define __RTL8723E_PWRSEQCMD_H__
+
+#include "../wifi.h"
+/*---------------------------------------------*/
+/* The value of cmd: 4 bits */
+/*---------------------------------------------*/
+#define PWR_CMD_READ 0x00
+#define PWR_CMD_WRITE 0x01
+#define PWR_CMD_POLLING 0x02
+#define PWR_CMD_DELAY 0x03
+#define PWR_CMD_END 0x04
+
+/* define the base address of each block */
+#define PWR_BASEADDR_MAC 0x00
+#define PWR_BASEADDR_USB 0x01
+#define PWR_BASEADDR_PCIE 0x02
+#define PWR_BASEADDR_SDIO 0x03
+
+#define PWR_INTF_SDIO_MSK BIT(0)
+#define PWR_INTF_USB_MSK BIT(1)
+#define PWR_INTF_PCI_MSK BIT(2)
+#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+#define PWR_FAB_TSMC_MSK BIT(0)
+#define PWR_FAB_UMC_MSK BIT(1)
+#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+#define PWR_CUT_TESTCHIP_MSK BIT(0)
+#define PWR_CUT_A_MSK BIT(1)
+#define PWR_CUT_B_MSK BIT(2)
+#define PWR_CUT_C_MSK BIT(3)
+#define PWR_CUT_D_MSK BIT(4)
+#define PWR_CUT_E_MSK BIT(5)
+#define PWR_CUT_F_MSK BIT(6)
+#define PWR_CUT_G_MSK BIT(7)
+#define PWR_CUT_ALL_MSK 0xFF
+
+enum pwrseq_delay_unit {
+ PWRSEQ_DELAY_US,
+ PWRSEQ_DELAY_MS,
+};
+
+struct wlan_pwr_cfg {
+ u16 offset;
+ u8 cut_msk;
+ u8 fab_msk:4;
+ u8 interface_msk:4;
+ u8 base:4;
+ u8 cmd:4;
+ u8 msk;
+ u8 value;
+};
+
+#define GET_PWR_CFG_OFFSET(__PWR) (__PWR.offset)
+#define GET_PWR_CFG_CUT_MASK(__PWR) (__PWR.cut_msk)
+#define GET_PWR_CFG_FAB_MASK(__PWR) (__PWR.fab_msk)
+#define GET_PWR_CFG_INTF_MASK(__PWR) (__PWR.interface_msk)
+#define GET_PWR_CFG_BASE(__PWR) (__PWR.base)
+#define GET_PWR_CFG_CMD(__PWR) (__PWR.cmd)
+#define GET_PWR_CFG_MASK(__PWR) (__PWR.msk)
+#define GET_PWR_CFG_VALUE(__PWR) (__PWR.value)
+
+bool rtl88_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+ u8 fab_version, u8 interface_type,
+ struct wlan_pwr_cfg pwrcfgcmd[]);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
new file mode 100644
index 000000000000..d849abf7d94a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
@@ -0,0 +1,2258 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_REG_H__
+#define __RTL92C_REG_H__
+
+#define TXPKT_BUF_SELECT 0x69
+#define RXPKT_BUF_SELECT 0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS 0x0
+
+#define REG_SYS_ISO_CTRL 0x0000
+#define REG_SYS_FUNC_EN 0x0002
+#define REG_APS_FSMCO 0x0004
+#define REG_SYS_CLKR 0x0008
+#define REG_9346CR 0x000A
+#define REG_EE_VPD 0x000C
+#define REG_AFE_MISC 0x0010
+#define REG_SPS0_CTRL 0x0011
+#define REG_SPS_OCP_CFG 0x0018
+#define REG_RSV_CTRL 0x001C
+#define REG_RF_CTRL 0x001F
+#define REG_LDOA15_CTRL 0x0020
+#define REG_LDOV12D_CTRL 0x0021
+#define REG_LDOHCI12_CTRL 0x0022
+#define REG_LPLDO_CTRL 0x0023
+#define REG_AFE_XTAL_CTRL 0x0024
+#define REG_AFE_LDO_CTRL 0x0027 /* 1.5v for 8188EE test
+ * chip, 1.4v for MP chip
+ */
+#define REG_AFE_PLL_CTRL 0x0028
+#define REG_EFUSE_CTRL 0x0030
+#define REG_EFUSE_TEST 0x0034
+#define REG_PWR_DATA 0x0038
+#define REG_CAL_TIMER 0x003C
+#define REG_ACLK_MON 0x003E
+#define REG_GPIO_MUXCFG 0x0040
+#define REG_GPIO_IO_SEL 0x0042
+#define REG_MAC_PINMUX_CFG 0x0043
+#define REG_GPIO_PIN_CTRL 0x0044
+#define REG_GPIO_INTM 0x0048
+#define REG_LEDCFG0 0x004C
+#define REG_LEDCFG1 0x004D
+#define REG_LEDCFG2 0x004E
+#define REG_LEDCFG3 0x004F
+#define REG_FSIMR 0x0050
+#define REG_FSISR 0x0054
+#define REG_HSIMR 0x0058
+#define REG_HSISR 0x005c
+#define REG_GPIO_PIN_CTRL_2 0x0060
+#define REG_GPIO_IO_SEL_2 0x0062
+#define REG_GPIO_OUTPUT 0x006c
+#define REG_AFE_XTAL_CTRL_EXT 0x0078
+#define REG_XCK_OUT_CTRL 0x007c
+#define REG_MCUFWDL 0x0080
+#define REG_WOL_EVENT 0x0081
+#define REG_MCUTSTCFG 0x0084
+
+
+#define REG_HIMR 0x00B0
+#define REG_HISR 0x00B4
+#define REG_HIMRE 0x00B8
+#define REG_HISRE 0x00BC
+
+#define REG_EFUSE_ACCESS 0x00CF
+
+#define REG_BIST_SCAN 0x00D0
+#define REG_BIST_RPT 0x00D4
+#define REG_BIST_ROM_RPT 0x00D8
+#define REG_USB_SIE_INTF 0x00E0
+#define REG_PCIE_MIO_INTF 0x00E4
+#define REG_PCIE_MIO_INTD 0x00E8
+#define REG_HPON_FSM 0x00EC
+#define REG_SYS_CFG 0x00F0
+
+#define REG_CR 0x0100
+#define REG_PBP 0x0104
+#define REG_PKT_BUFF_ACCESS_CTRL 0x0106
+#define REG_TRXDMA_CTRL 0x010C
+#define REG_TRXFF_BNDY 0x0114
+#define REG_TRXFF_STATUS 0x0118
+#define REG_RXFF_PTR 0x011C
+
+#define REG_CPWM 0x012F
+#define REG_FWIMR 0x0130
+#define REG_FWISR 0x0134
+#define REG_PKTBUF_DBG_CTRL 0x0140
+#define REG_PKTBUF_DBG_DATA_L 0x0144
+#define REG_PKTBUF_DBG_DATA_H 0x0148
+#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL+2)
+
+#define REG_TC0_CTRL 0x0150
+#define REG_TC1_CTRL 0x0154
+#define REG_TC2_CTRL 0x0158
+#define REG_TC3_CTRL 0x015C
+#define REG_TC4_CTRL 0x0160
+#define REG_TCUNIT_BASE 0x0164
+#define REG_MBIST_START 0x0174
+#define REG_MBIST_DONE 0x0178
+#define REG_MBIST_FAIL 0x017C
+#define REG_32K_CTRL 0x0194
+#define REG_C2HEVT_MSG_NORMAL 0x01A0
+#define REG_C2HEVT_CLEAR 0x01AF
+#define REG_C2HEVT_MSG_TEST 0x01B8
+#define REG_MCUTST_1 0x01c0
+#define REG_FMETHR 0x01C8
+#define REG_HMETFR 0x01CC
+#define REG_HMEBOX_0 0x01D0
+#define REG_HMEBOX_1 0x01D4
+#define REG_HMEBOX_2 0x01D8
+#define REG_HMEBOX_3 0x01DC
+
+#define REG_LLT_INIT 0x01E0
+#define REG_BB_ACCEESS_CTRL 0x01E8
+#define REG_BB_ACCESS_DATA 0x01EC
+
+#define REG_HMEBOX_EXT_0 0x01F0
+#define REG_HMEBOX_EXT_1 0x01F4
+#define REG_HMEBOX_EXT_2 0x01F8
+#define REG_HMEBOX_EXT_3 0x01FC
+
+#define REG_RQPN 0x0200
+#define REG_FIFOPAGE 0x0204
+#define REG_TDECTRL 0x0208
+#define REG_TXDMA_OFFSET_CHK 0x020C
+#define REG_TXDMA_STATUS 0x0210
+#define REG_RQPN_NPQ 0x0214
+
+#define REG_RXDMA_AGG_PG_TH 0x0280
+#define REG_FW_UPD_RDPTR 0x0284 /* FW shall update this
+ * register before FW * write
+ * RXPKT_RELEASE_POLL to 1
+ */
+#define REG_RXDMA_CONTROL 0x0286 /* Control the RX DMA.*/
+#define REG_RXPKT_NUM 0x0287 /* The number of packets
+ * in RXPKTBUF.
+ */
+#define REG_PCIE_CTRL_REG 0x0300
+#define REG_INT_MIG 0x0304
+#define REG_BCNQ_DESA 0x0308
+#define REG_HQ_DESA 0x0310
+#define REG_MGQ_DESA 0x0318
+#define REG_VOQ_DESA 0x0320
+#define REG_VIQ_DESA 0x0328
+#define REG_BEQ_DESA 0x0330
+#define REG_BKQ_DESA 0x0338
+#define REG_RX_DESA 0x0340
+
+#define REG_DBI 0x0348
+#define REG_MDIO 0x0354
+#define REG_DBG_SEL 0x0360
+#define REG_PCIE_HRPWM 0x0361
+#define REG_PCIE_HCPWM 0x0363
+#define REG_UART_CTRL 0x0364
+#define REG_WATCH_DOG 0x0368
+#define REG_UART_TX_DESA 0x0370
+#define REG_UART_RX_DESA 0x0378
+
+
+#define REG_HDAQ_DESA_NODEF 0x0000
+#define REG_CMDQ_DESA_NODEF 0x0000
+
+#define REG_VOQ_INFORMATION 0x0400
+#define REG_VIQ_INFORMATION 0x0404
+#define REG_BEQ_INFORMATION 0x0408
+#define REG_BKQ_INFORMATION 0x040C
+#define REG_MGQ_INFORMATION 0x0410
+#define REG_HGQ_INFORMATION 0x0414
+#define REG_BCNQ_INFORMATION 0x0418
+#define REG_TXPKT_EMPTY 0x041A
+
+
+#define REG_CPU_MGQ_INFORMATION 0x041C
+#define REG_FWHW_TXQ_CTRL 0x0420
+#define REG_HWSEQ_CTRL 0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY 0x0424
+#define REG_TXPKTBUF_MGQ_BDNY 0x0425
+#define REG_MULTI_BCNQ_EN 0x0426
+#define REG_MULTI_BCNQ_OFFSET 0x0427
+#define REG_SPEC_SIFS 0x0428
+#define REG_RL 0x042A
+#define REG_DARFRC 0x0430
+#define REG_RARFRC 0x0438
+#define REG_RRSR 0x0440
+#define REG_ARFR0 0x0444
+#define REG_ARFR1 0x0448
+#define REG_ARFR2 0x044C
+#define REG_ARFR3 0x0450
+#define REG_AGGLEN_LMT 0x0458
+#define REG_AMPDU_MIN_SPACE 0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D
+#define REG_FAST_EDCA_CTRL 0x0460
+#define REG_RD_RESP_PKT_TH 0x0463
+#define REG_INIRTS_RATE_SEL 0x0480
+#define REG_INIDATA_RATE_SEL 0x0484
+#define REG_POWER_STATUS 0x04A4
+#define REG_POWER_STAGE1 0x04B4
+#define REG_POWER_STAGE2 0x04B8
+#define REG_PKT_LIFE_TIME 0x04C0
+#define REG_STBC_SETTING 0x04C4
+#define REG_PROT_MODE_CTRL 0x04C8
+#define REG_BAR_MODE_CTRL 0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT 0x04CF
+#define REG_EARLY_MODE_CONTROL 0x04D0
+#define REG_NQOS_SEQ 0x04DC
+#define REG_QOS_SEQ 0x04DE
+#define REG_NEED_CPU_HANDLE 0x04E0
+#define REG_PKT_LOSE_RPT 0x04E1
+#define REG_PTCL_ERR_STATUS 0x04E2
+#define REG_TX_RPT_CTRL 0x04EC
+#define REG_TX_RPT_TIME 0x04F0
+#define REG_DUMMY 0x04FC
+
+#define REG_EDCA_VO_PARAM 0x0500
+#define REG_EDCA_VI_PARAM 0x0504
+#define REG_EDCA_BE_PARAM 0x0508
+#define REG_EDCA_BK_PARAM 0x050C
+#define REG_BCNTCFG 0x0510
+#define REG_PIFS 0x0512
+#define REG_RDG_PIFS 0x0513
+#define REG_SIFS_CTX 0x0514
+#define REG_SIFS_TRX 0x0516
+#define REG_AGGR_BREAK_TIME 0x051A
+#define REG_SLOT 0x051B
+#define REG_TX_PTCL_CTRL 0x0520
+#define REG_TXPAUSE 0x0522
+#define REG_DIS_TXREQ_CLR 0x0523
+#define REG_RD_CTRL 0x0524
+#define REG_TBTT_PROHIBIT 0x0540
+#define REG_RD_NAV_NXT 0x0544
+#define REG_NAV_PROT_LEN 0x0546
+#define REG_BCN_CTRL 0x0550
+#define REG_USTIME_TSF 0x0551
+#define REG_MBID_NUM 0x0552
+#define REG_DUAL_TSF_RST 0x0553
+#define REG_BCN_INTERVAL 0x0554
+#define REG_MBSSID_BCN_SPACE 0x0554
+#define REG_DRVERLYINT 0x0558
+#define REG_BCNDMATIM 0x0559
+#define REG_ATIMWND 0x055A
+#define REG_BCN_MAX_ERR 0x055D
+#define REG_RXTSF_OFFSET_CCK 0x055E
+#define REG_RXTSF_OFFSET_OFDM 0x055F
+#define REG_TSFTR 0x0560
+#define REG_INIT_TSFTR 0x0564
+#define REG_PSTIMER 0x0580
+#define REG_TIMER0 0x0584
+#define REG_TIMER1 0x0588
+#define REG_ACMHWCTRL 0x05C0
+#define REG_ACMRSTCTRL 0x05C1
+#define REG_ACMAVG 0x05C2
+#define REG_VO_ADMTIME 0x05C4
+#define REG_VI_ADMTIME 0x05C6
+#define REG_BE_ADMTIME 0x05C8
+#define REG_EDCA_RANDOM_GEN 0x05CC
+#define REG_SCH_TXCMD 0x05D0
+
+#define REG_APSD_CTRL 0x0600
+#define REG_BWOPMODE 0x0603
+#define REG_TCR 0x0604
+#define REG_RCR 0x0608
+#define REG_RX_PKT_LIMIT 0x060C
+#define REG_RX_DLK_TIME 0x060D
+#define REG_RX_DRVINFO_SZ 0x060F
+
+#define REG_MACID 0x0610
+#define REG_BSSID 0x0618
+#define REG_MAR 0x0620
+#define REG_MBIDCAMCFG 0x0628
+
+#define REG_USTIME_EDCA 0x0638
+#define REG_MAC_SPEC_SIFS 0x063A
+#define REG_RESP_SIFS_CCK 0x063C
+#define REG_RESP_SIFS_OFDM 0x063E
+#define REG_ACKTO 0x0640
+#define REG_CTS2TO 0x0641
+#define REG_EIFS 0x0642
+
+#define REG_NAV_CTRL 0x0650
+#define REG_BACAMCMD 0x0654
+#define REG_BACAMCONTENT 0x0658
+#define REG_LBDLY 0x0660
+#define REG_FWDLY 0x0661
+#define REG_RXERR_RPT 0x0664
+#define REG_TRXPTCL_CTL 0x0668
+
+#define REG_CAMCMD 0x0670
+#define REG_CAMWRITE 0x0674
+#define REG_CAMREAD 0x0678
+#define REG_CAMDBG 0x067C
+#define REG_SECCFG 0x0680
+
+#define REG_WOW_CTRL 0x0690
+#define REG_PSSTATUS 0x0691
+#define REG_PS_RX_INFO 0x0692
+#define REG_UAPSD_TID 0x0693
+#define REG_LPNAV_CTRL 0x0694
+#define REG_WKFMCAM_NUM 0x0698
+#define REG_WKFMCAM_RWD 0x069C
+#define REG_RXFLTMAP0 0x06A0
+#define REG_RXFLTMAP1 0x06A2
+#define REG_RXFLTMAP2 0x06A4
+#define REG_BCN_PSR_RPT 0x06A8
+#define REG_CALB32K_CTRL 0x06AC
+#define REG_PKT_MON_CTRL 0x06B4
+#define REG_BT_COEX_TABLE 0x06C0
+#define REG_WMAC_RESP_TXINFO 0x06D8
+
+#define REG_USB_INFO 0xFE17
+#define REG_USB_SPECIAL_OPTION 0xFE55
+#define REG_USB_DMA_AGG_TO 0xFE5B
+#define REG_USB_AGG_TO 0xFE5C
+#define REG_USB_AGG_TH 0xFE5D
+
+#define REG_TEST_USB_TXQS 0xFE48
+#define REG_TEST_SIE_VID 0xFE60
+#define REG_TEST_SIE_PID 0xFE62
+#define REG_TEST_SIE_OPTIONAL 0xFE64
+#define REG_TEST_SIE_CHIRP_K 0xFE65
+#define REG_TEST_SIE_PHY 0xFE66
+#define REG_TEST_SIE_MAC_ADDR 0xFE70
+#define REG_TEST_SIE_STRING 0xFE80
+
+#define REG_NORMAL_SIE_VID 0xFE60
+#define REG_NORMAL_SIE_PID 0xFE62
+#define REG_NORMAL_SIE_OPTIONAL 0xFE64
+#define REG_NORMAL_SIE_EP 0xFE65
+#define REG_NORMAL_SIE_PHY 0xFE68
+#define REG_NORMAL_SIE_MAC_ADDR 0xFE70
+#define REG_NORMAL_SIE_STRING 0xFE80
+
+#define CR9346 REG_9346CR
+#define MSR (REG_CR + 2)
+#define ISR REG_HISR
+#define TSFR REG_TSFTR
+
+#define MACIDR0 REG_MACID
+#define MACIDR4 (REG_MACID + 4)
+
+#define PBP REG_PBP
+
+#define IDR0 MACIDR0
+#define IDR4 MACIDR4
+
+#define UNUSED_REGISTER 0x1BF
+#define DCAM UNUSED_REGISTER
+#define PSR UNUSED_REGISTER
+#define BBADDR UNUSED_REGISTER
+#define PHYDATAR UNUSED_REGISTER
+
+#define INVALID_BBRF_VALUE 0x12345678
+
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+#define CMDEEPROM_EN BIT(5)
+#define CMDEEPROM_SEL BIT(4)
+#define CMD9346CR_9356SEL BIT(4)
+#define AUTOLOAD_EEPROM (CMDEEPROM_EN|CMDEEPROM_SEL)
+#define AUTOLOAD_EFUSE CMDEEPROM_EN
+
+#define GPIOSEL_GPIO 0
+#define GPIOSEL_ENBT BIT(5)
+
+#define GPIO_IN REG_GPIO_PIN_CTRL
+#define GPIO_OUT (REG_GPIO_PIN_CTRL+1)
+#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2)
+#define GPIO_MOD (REG_GPIO_PIN_CTRL+3)
+
+/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
+#define HSIMR_GPIO12_0_INT_EN BIT(0)
+#define HSIMR_SPS_OCP_INT_EN BIT(5)
+#define HSIMR_RON_INT_EN BIT(6)
+#define HSIMR_PDN_INT_EN BIT(7)
+#define HSIMR_GPIO9_INT_EN BIT(25)
+
+
+/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+#define HSISR_GPIO12_0_INT BIT(0)
+#define HSISR_SPS_OCP_INT BIT(5)
+#define HSISR_RON_INT_EN BIT(6)
+#define HSISR_PDNINT BIT(7)
+#define HSISR_GPIO9_INT BIT(25)
+
+#define MSR_NOLINK 0x00
+#define MSR_ADHOC 0x01
+#define MSR_INFRA 0x02
+#define MSR_AP 0x03
+
+#define RRSR_RSC_OFFSET 21
+#define RRSR_SHORT_OFFSET 23
+#define RRSR_RSC_BW_40M 0x600000
+#define RRSR_RSC_UPSUBCHNL 0x400000
+#define RRSR_RSC_LOWSUBCHNL 0x200000
+#define RRSR_SHORT 0x800000
+#define RRSR_1M BIT(0)
+#define RRSR_2M BIT(1)
+#define RRSR_5_5M BIT(2)
+#define RRSR_11M BIT(3)
+#define RRSR_6M BIT(4)
+#define RRSR_9M BIT(5)
+#define RRSR_12M BIT(6)
+#define RRSR_18M BIT(7)
+#define RRSR_24M BIT(8)
+#define RRSR_36M BIT(9)
+#define RRSR_48M BIT(10)
+#define RRSR_54M BIT(11)
+#define RRSR_MCS0 BIT(12)
+#define RRSR_MCS1 BIT(13)
+#define RRSR_MCS2 BIT(14)
+#define RRSR_MCS3 BIT(15)
+#define RRSR_MCS4 BIT(16)
+#define RRSR_MCS5 BIT(17)
+#define RRSR_MCS6 BIT(18)
+#define RRSR_MCS7 BIT(19)
+#define BRSR_ACKSHORTPMB BIT(23)
+
+#define RATR_1M 0x00000001
+#define RATR_2M 0x00000002
+#define RATR_55M 0x00000004
+#define RATR_11M 0x00000008
+#define RATR_6M 0x00000010
+#define RATR_9M 0x00000020
+#define RATR_12M 0x00000040
+#define RATR_18M 0x00000080
+#define RATR_24M 0x00000100
+#define RATR_36M 0x00000200
+#define RATR_48M 0x00000400
+#define RATR_54M 0x00000800
+#define RATR_MCS0 0x00001000
+#define RATR_MCS1 0x00002000
+#define RATR_MCS2 0x00004000
+#define RATR_MCS3 0x00008000
+#define RATR_MCS4 0x00010000
+#define RATR_MCS5 0x00020000
+#define RATR_MCS6 0x00040000
+#define RATR_MCS7 0x00080000
+#define RATR_MCS8 0x00100000
+#define RATR_MCS9 0x00200000
+#define RATR_MCS10 0x00400000
+#define RATR_MCS11 0x00800000
+#define RATR_MCS12 0x01000000
+#define RATR_MCS13 0x02000000
+#define RATR_MCS14 0x04000000
+#define RATR_MCS15 0x08000000
+
+#define RATE_1M BIT(0)
+#define RATE_2M BIT(1)
+#define RATE_5_5M BIT(2)
+#define RATE_11M BIT(3)
+#define RATE_6M BIT(4)
+#define RATE_9M BIT(5)
+#define RATE_12M BIT(6)
+#define RATE_18M BIT(7)
+#define RATE_24M BIT(8)
+#define RATE_36M BIT(9)
+#define RATE_48M BIT(10)
+#define RATE_54M BIT(11)
+#define RATE_MCS0 BIT(12)
+#define RATE_MCS1 BIT(13)
+#define RATE_MCS2 BIT(14)
+#define RATE_MCS3 BIT(15)
+#define RATE_MCS4 BIT(16)
+#define RATE_MCS5 BIT(17)
+#define RATE_MCS6 BIT(18)
+#define RATE_MCS7 BIT(19)
+#define RATE_MCS8 BIT(20)
+#define RATE_MCS9 BIT(21)
+#define RATE_MCS10 BIT(22)
+#define RATE_MCS11 BIT(23)
+#define RATE_MCS12 BIT(24)
+#define RATE_MCS13 BIT(25)
+#define RATE_MCS14 BIT(26)
+#define RATE_MCS15 BIT(27)
+
+#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M | \
+ RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \
+ RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \
+ RATR_MCS6 | RATR_MCS7)
+#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \
+ RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \
+ RATR_MCS14 | RATR_MCS15)
+
+#define BW_OPMODE_20MHZ BIT(2)
+#define BW_OPMODE_5G BIT(1)
+#define BW_OPMODE_11J BIT(0)
+
+#define CAM_VALID BIT(15)
+#define CAM_NOTVALID 0x0000
+#define CAM_USEDK BIT(5)
+
+#define CAM_NONE 0x0
+#define CAM_WEP40 0x01
+#define CAM_TKIP 0x02
+#define CAM_AES 0x04
+#define CAM_WEP104 0x05
+
+#define TOTAL_CAM_ENTRY 32
+#define HALF_CAM_ENTRY 16
+
+#define CAM_WRITE BIT(16)
+#define CAM_READ 0x00000000
+#define CAM_POLLINIG BIT(31)
+
+#define SCR_USEDK 0x01
+#define SCR_TXSEC_ENABLE 0x02
+#define SCR_RXSEC_ENABLE 0x04
+
+#define WOW_PMEN BIT(0)
+#define WOW_WOMEN BIT(1)
+#define WOW_MAGIC BIT(2)
+#define WOW_UWF BIT(3)
+
+/*********************************************
+* 8188 IMR/ISR bits
+**********************************************/
+#define IMR_DISABLED 0x0
+/* IMR DW0(0x0060-0063) Bit 0-31 */
+#define IMR_TXCCK BIT(30) /* TXRPT interrupt when CCX bit of
+ * the packet is set
+ */
+#define IMR_PSTIMEOUT BIT(29) /* Power Save Time Out Interrupt */
+#define IMR_GTINT4 BIT(28) /* When GTIMER4 expires,
+ * this bit is set to 1
+ */
+#define IMR_GTINT3 BIT(27) /* When GTIMER3 expires,
+ * this bit is set to 1
+ */
+#define IMR_TBDER BIT(26) /* Transmit Beacon0 Error */
+#define IMR_TBDOK BIT(25) /* Transmit Beacon0 OK */
+#define IMR_TSF_BIT32_TOGGLE BIT(24) /* TSF Timer BIT32 toggle ind int */
+#define IMR_BCNDMAINT0 BIT(20) /* Beacon DMA Interrupt 0 */
+#define IMR_BCNDOK0 BIT(16) /* Beacon Queue DMA OK0 */
+#define IMR_HSISR_IND_ON_INT BIT(15) /* HSISR Indicator (HSIMR & HSISR is
+ * true, this bit is set to 1)
+ */
+#define IMR_BCNDMAINT_E BIT(14) /* Beacon DMA Int Extension for Win7 */
+#define IMR_ATIMEND BIT(12) /* CTWidnow End or ATIM Window End */
+#define IMR_HISR1_IND_INT BIT(11) /* HISR1 Indicator (HISR1 & HIMR1 is
+ * true, this bit is set to 1)
+ */
+#define IMR_C2HCMD BIT(10) /* CPU to Host Command INT Status,
+ * Write 1 clear
+ */
+#define IMR_CPWM2 BIT(9) /* CPU power Mode exchange INT Status,
+ * Write 1 clear
+ */
+#define IMR_CPWM BIT(8) /* CPU power Mode exchange INT Status,
+ * Write 1 clear
+ */
+#define IMR_HIGHDOK BIT(7) /* High Queue DMA OK */
+#define IMR_MGNTDOK BIT(6) /* Management Queue DMA OK */
+#define IMR_BKDOK BIT(5) /* AC_BK DMA OK */
+#define IMR_BEDOK BIT(4) /* AC_BE DMA OK */
+#define IMR_VIDOK BIT(3) /* AC_VI DMA OK */
+#define IMR_VODOK BIT(2) /* AC_VO DMA OK */
+#define IMR_RDU BIT(1) /* Rx Descriptor Unavailable */
+#define IMR_ROK BIT(0) /* Receive DMA OK */
+
+/* IMR DW1(0x00B4-00B7) Bit 0-31 */
+#define IMR_BCNDMAINT7 BIT(27) /* Beacon DMA Interrupt 7 */
+#define IMR_BCNDMAINT6 BIT(26) /* Beacon DMA Interrupt 6 */
+#define IMR_BCNDMAINT5 BIT(25) /* Beacon DMA Interrupt 5 */
+#define IMR_BCNDMAINT4 BIT(24) /* Beacon DMA Interrupt 4 */
+#define IMR_BCNDMAINT3 BIT(23) /* Beacon DMA Interrupt 3 */
+#define IMR_BCNDMAINT2 BIT(22) /* Beacon DMA Interrupt 2 */
+#define IMR_BCNDMAINT1 BIT(21) /* Beacon DMA Interrupt 1 */
+#define IMR_BCNDOK7 BIT(20) /* Beacon Queue DMA OK Interrup 7 */
+#define IMR_BCNDOK6 BIT(19) /* Beacon Queue DMA OK Interrup 6 */
+#define IMR_BCNDOK5 BIT(18) /* Beacon Queue DMA OK Interrup 5 */
+#define IMR_BCNDOK4 BIT(17) /* Beacon Queue DMA OK Interrup 4 */
+#define IMR_BCNDOK3 BIT(16) /* Beacon Queue DMA OK Interrup 3 */
+#define IMR_BCNDOK2 BIT(15) /* Beacon Queue DMA OK Interrup 2 */
+#define IMR_BCNDOK1 BIT(14) /* Beacon Queue DMA OK Interrup 1 */
+#define IMR_ATIMEND_E BIT(13) /* ATIM Window End Extension for Win7 */
+#define IMR_TXERR BIT(11) /* Tx Err Flag Int Status,
+ * write 1 clear.
+ */
+#define IMR_RXERR BIT(10) /* Rx Err Flag INT Status,
+ * Write 1 clear
+ */
+#define IMR_TXFOVW BIT(9) /* Transmit FIFO Overflow */
+#define IMR_RXFOVW BIT(8) /* Receive FIFO Overflow */
+
+
+#define HWSET_MAX_SIZE 512
+#define EFUSE_MAX_SECTION 64
+#define EFUSE_REAL_CONTENT_LEN 256
+#define EFUSE_OOB_PROTECT_BYTES 18 /* PG data exclude header,
+ * dummy 7 bytes frome CP
+ * test and reserved 1byte.
+ */
+
+#define EEPROM_DEFAULT_TSSI 0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF 0x0
+#define EEPROM_DEFAULT_CRYSTALCAP 0x5
+#define EEPROM_DEFAULT_BOARDTYPE 0x02
+#define EEPROM_DEFAULT_TXPOWER 0x1010
+#define EEPROM_DEFAULT_HT2T_TXPWR 0x10
+
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+#define EEPROM_DEFAULT_THERMALMETER 0x18
+#define EEPROM_DEFAULT_ANTTXPOWERDIFF 0x0
+#define EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP 0x5
+#define EEPROM_DEFAULT_TXPOWERLEVEL 0x22
+#define EEPROM_DEFAULT_HT40_2SDIFF 0x0
+#define EEPROM_DEFAULT_HT20_DIFF 2
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET 0
+#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET 0
+
+#define RF_OPTION1 0x79
+#define RF_OPTION2 0x7A
+#define RF_OPTION3 0x7B
+#define RF_OPTION4 0x7C
+
+#define EEPROM_DEFAULT_PID 0x1234
+#define EEPROM_DEFAULT_VID 0x5678
+#define EEPROM_DEFAULT_CUSTOMERID 0xAB
+#define EEPROM_DEFAULT_SUBCUSTOMERID 0xCD
+#define EEPROM_DEFAULT_VERSION 0
+
+#define EEPROM_CHANNEL_PLAN_FCC 0x0
+#define EEPROM_CHANNEL_PLAN_IC 0x1
+#define EEPROM_CHANNEL_PLAN_ETSI 0x2
+#define EEPROM_CHANNEL_PLAN_SPAIN 0x3
+#define EEPROM_CHANNEL_PLAN_FRANCE 0x4
+#define EEPROM_CHANNEL_PLAN_MKK 0x5
+#define EEPROM_CHANNEL_PLAN_MKK1 0x6
+#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7
+#define EEPROM_CHANNEL_PLAN_TELEC 0x8
+#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA
+#define EEPROM_CHANNEL_PLAN_NCC 0xB
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80
+
+#define EEPROM_CID_DEFAULT 0x0
+#define EEPROM_CID_TOSHIBA 0x4
+#define EEPROM_CID_CCX 0x10
+#define EEPROM_CID_QMI 0x0D
+#define EEPROM_CID_WHQL 0xFE
+
+#define RTL8188E_EEPROM_ID 0x8129
+
+#define EEPROM_HPON 0x02
+#define EEPROM_CLK 0x06
+#define EEPROM_TESTR 0x08
+
+#define EEPROM_TXPOWERCCK 0x10
+#define EEPROM_TXPOWERHT40_1S 0x16
+#define EEPROM_TXPOWERHT20DIFF 0x1B
+#define EEPROM_TXPOWER_OFDMDIFF 0x1B
+
+#define EEPROM_TX_PWR_INX 0x10
+
+#define EEPROM_CHANNELPLAN 0xB8
+#define EEPROM_XTAL_88E 0xB9
+#define EEPROM_THERMAL_METER_88E 0xBA
+#define EEPROM_IQK_LCK_88E 0xBB
+
+#define EEPROM_RF_BOARD_OPTION_88E 0xC1
+#define EEPROM_RF_FEATURE_OPTION_88E 0xC2
+#define EEPROM_RF_BT_SETTING_88E 0xC3
+#define EEPROM_VERSION 0xC4
+#define EEPROM_CUSTOMER_ID 0xC5
+#define EEPROM_RF_ANTENNA_OPT_88E 0xC9
+
+#define EEPROM_MAC_ADDR 0xD0
+#define EEPROM_VID 0xD6
+#define EEPROM_DID 0xD8
+#define EEPROM_SVID 0xDA
+#define EEPROM_SMID 0xDC
+
+#define STOPBECON BIT(6)
+#define STOPHIGHT BIT(5)
+#define STOPMGT BIT(4)
+#define STOPVO BIT(3)
+#define STOPVI BIT(2)
+#define STOPBE BIT(1)
+#define STOPBK BIT(0)
+
+#define RCR_APPFCS BIT(31)
+#define RCR_APP_MIC BIT(30)
+#define RCR_APP_ICV BIT(29)
+#define RCR_APP_PHYST_RXFF BIT(28)
+#define RCR_APP_BA_SSN BIT(27)
+#define RCR_ENMBID BIT(24)
+#define RCR_LSIGEN BIT(23)
+#define RCR_MFBEN BIT(22)
+#define RCR_HTC_LOC_CTRL BIT(14)
+#define RCR_AMF BIT(13)
+#define RCR_ACF BIT(12)
+#define RCR_ADF BIT(11)
+#define RCR_AICV BIT(9)
+#define RCR_ACRC32 BIT(8)
+#define RCR_CBSSID_BCN BIT(7)
+#define RCR_CBSSID_DATA BIT(6)
+#define RCR_CBSSID RCR_CBSSID_DATA
+#define RCR_APWRMGT BIT(5)
+#define RCR_ADD3 BIT(4)
+#define RCR_AB BIT(3)
+#define RCR_AM BIT(2)
+#define RCR_APM BIT(1)
+#define RCR_AAP BIT(0)
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+
+#define RSV_CTRL 0x001C
+#define RD_CTRL 0x0524
+
+#define REG_USB_INFO 0xFE17
+#define REG_USB_SPECIAL_OPTION 0xFE55
+#define REG_USB_DMA_AGG_TO 0xFE5B
+#define REG_USB_AGG_TO 0xFE5C
+#define REG_USB_AGG_TH 0xFE5D
+
+#define REG_USB_VID 0xFE60
+#define REG_USB_PID 0xFE62
+#define REG_USB_OPTIONAL 0xFE64
+#define REG_USB_CHIRP_K 0xFE65
+#define REG_USB_PHY 0xFE66
+#define REG_USB_MAC_ADDR 0xFE70
+#define REG_USB_HRPWM 0xFE58
+#define REG_USB_HCPWM 0xFE57
+
+#define SW18_FPWM BIT(3)
+
+#define ISO_MD2PP BIT(0)
+#define ISO_UA2USB BIT(1)
+#define ISO_UD2CORE BIT(2)
+#define ISO_PA2PCIE BIT(3)
+#define ISO_PD2CORE BIT(4)
+#define ISO_IP2MAC BIT(5)
+#define ISO_DIOP BIT(6)
+#define ISO_DIOE BIT(7)
+#define ISO_EB2CORE BIT(8)
+#define ISO_DIOR BIT(9)
+
+#define PWC_EV25V BIT(14)
+#define PWC_EV12V BIT(15)
+
+#define FEN_BBRSTB BIT(0)
+#define FEN_BB_GLB_RSTN BIT(1)
+#define FEN_USBA BIT(2)
+#define FEN_UPLL BIT(3)
+#define FEN_USBD BIT(4)
+#define FEN_DIO_PCIE BIT(5)
+#define FEN_PCIEA BIT(6)
+#define FEN_PPLL BIT(7)
+#define FEN_PCIED BIT(8)
+#define FEN_DIOE BIT(9)
+#define FEN_CPUEN BIT(10)
+#define FEN_DCORE BIT(11)
+#define FEN_ELDR BIT(12)
+#define FEN_DIO_RF BIT(13)
+#define FEN_HWPDN BIT(14)
+#define FEN_MREGEN BIT(15)
+
+#define PFM_LDALL BIT(0)
+#define PFM_ALDN BIT(1)
+#define PFM_LDKP BIT(2)
+#define PFM_WOWL BIT(3)
+#define ENPDN BIT(4)
+#define PDN_PL BIT(5)
+#define APFM_ONMAC BIT(8)
+#define APFM_OFF BIT(9)
+#define APFM_RSM BIT(10)
+#define AFSM_HSUS BIT(11)
+#define AFSM_PCIE BIT(12)
+#define APDM_MAC BIT(13)
+#define APDM_HOST BIT(14)
+#define APDM_HPDN BIT(15)
+#define RDY_MACON BIT(16)
+#define SUS_HOST BIT(17)
+#define ROP_ALD BIT(20)
+#define ROP_PWR BIT(21)
+#define ROP_SPS BIT(22)
+#define SOP_MRST BIT(25)
+#define SOP_FUSE BIT(26)
+#define SOP_ABG BIT(27)
+#define SOP_AMB BIT(28)
+#define SOP_RCK BIT(29)
+#define SOP_A8M BIT(30)
+#define XOP_BTCK BIT(31)
+
+#define ANAD16V_EN BIT(0)
+#define ANA8M BIT(1)
+#define MACSLP BIT(4)
+#define LOADER_CLK_EN BIT(5)
+#define _80M_SSC_DIS BIT(7)
+#define _80M_SSC_EN_HO BIT(8)
+#define PHY_SSC_RSTB BIT(9)
+#define SEC_CLK_EN BIT(10)
+#define MAC_CLK_EN BIT(11)
+#define SYS_CLK_EN BIT(12)
+#define RING_CLK_EN BIT(13)
+
+#define BOOT_FROM_EEPROM BIT(4)
+#define EEPROM_EN BIT(5)
+
+#define AFE_BGEN BIT(0)
+#define AFE_MBEN BIT(1)
+#define MAC_ID_EN BIT(7)
+
+#define WLOCK_ALL BIT(0)
+#define WLOCK_00 BIT(1)
+#define WLOCK_04 BIT(2)
+#define WLOCK_08 BIT(3)
+#define WLOCK_40 BIT(4)
+#define R_DIS_PRST_0 BIT(5)
+#define R_DIS_PRST_1 BIT(6)
+#define LOCK_ALL_EN BIT(7)
+
+#define RF_EN BIT(0)
+#define RF_RSTB BIT(1)
+#define RF_SDMRSTB BIT(2)
+
+#define LDA15_EN BIT(0)
+#define LDA15_STBY BIT(1)
+#define LDA15_OBUF BIT(2)
+#define LDA15_REG_VOS BIT(3)
+#define _LDA15_VOADJ(x) (((x) & 0x7) << 4)
+
+#define LDV12_EN BIT(0)
+#define LDV12_SDBY BIT(1)
+#define LPLDO_HSM BIT(2)
+#define LPLDO_LSM_DIS BIT(3)
+#define _LDV12_VADJ(x) (((x) & 0xF) << 4)
+
+#define XTAL_EN BIT(0)
+#define XTAL_BSEL BIT(1)
+#define _XTAL_BOSC(x) (((x) & 0x3) << 2)
+#define _XTAL_CADJ(x) (((x) & 0xF) << 4)
+#define XTAL_GATE_USB BIT(8)
+#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9)
+#define XTAL_GATE_AFE BIT(11)
+#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12)
+#define XTAL_RF_GATE BIT(14)
+#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15)
+#define XTAL_GATE_DIG BIT(17)
+#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18)
+#define XTAL_BT_GATE BIT(20)
+#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21)
+#define _XTAL_GPIO(x) (((x) & 0x7) << 23)
+
+#define CKDLY_AFE BIT(26)
+#define CKDLY_USB BIT(27)
+#define CKDLY_DIG BIT(28)
+#define CKDLY_BT BIT(29)
+
+#define APLL_EN BIT(0)
+#define APLL_320_EN BIT(1)
+#define APLL_FREF_SEL BIT(2)
+#define APLL_EDGE_SEL BIT(3)
+#define APLL_WDOGB BIT(4)
+#define APLL_LPFEN BIT(5)
+
+#define APLL_REF_CLK_13MHZ 0x1
+#define APLL_REF_CLK_19_2MHZ 0x2
+#define APLL_REF_CLK_20MHZ 0x3
+#define APLL_REF_CLK_25MHZ 0x4
+#define APLL_REF_CLK_26MHZ 0x5
+#define APLL_REF_CLK_38_4MHZ 0x6
+#define APLL_REF_CLK_40MHZ 0x7
+
+#define APLL_320EN BIT(14)
+#define APLL_80EN BIT(15)
+#define APLL_1MEN BIT(24)
+
+#define ALD_EN BIT(18)
+#define EF_PD BIT(19)
+#define EF_FLAG BIT(31)
+
+#define EF_TRPT BIT(7)
+#define LDOE25_EN BIT(31)
+
+#define RSM_EN BIT(0)
+#define TIMER_EN BIT(4)
+
+#define TRSW0EN BIT(2)
+#define TRSW1EN BIT(3)
+#define EROM_EN BIT(4)
+#define ENBT BIT(5)
+#define ENUART BIT(8)
+#define UART_910 BIT(9)
+#define ENPMAC BIT(10)
+#define SIC_SWRST BIT(11)
+#define ENSIC BIT(12)
+#define SIC_23 BIT(13)
+#define ENHDP BIT(14)
+#define SIC_LBK BIT(15)
+
+#define LED0PL BIT(4)
+#define LED1PL BIT(12)
+#define LED0DIS BIT(7)
+
+#define MCUFWDL_EN BIT(0)
+#define MCUFWDL_RDY BIT(1)
+#define FWDL_CHKSUM_RPT BIT(2)
+#define MACINI_RDY BIT(3)
+#define BBINI_RDY BIT(4)
+#define RFINI_RDY BIT(5)
+#define WINTINI_RDY BIT(6)
+#define CPRST BIT(23)
+
+#define XCLK_VLD BIT(0)
+#define ACLK_VLD BIT(1)
+#define UCLK_VLD BIT(2)
+#define PCLK_VLD BIT(3)
+#define PCIRSTB BIT(4)
+#define V15_VLD BIT(5)
+#define TRP_B15V_EN BIT(7)
+#define SIC_IDLE BIT(8)
+#define BD_MAC2 BIT(9)
+#define BD_MAC1 BIT(10)
+#define IC_MACPHY_MODE BIT(11)
+#define VENDOR_ID BIT(19)
+#define PAD_HWPD_IDN BIT(22)
+#define TRP_VAUX_EN BIT(23)
+#define TRP_BT_EN BIT(24)
+#define BD_PKG_SEL BIT(25)
+#define BD_HCI_SEL BIT(26)
+#define TYPE_ID BIT(27)
+
+#define CHIP_VER_RTL_MASK 0xF000
+#define CHIP_VER_RTL_SHIFT 12
+
+#define REG_LBMODE (REG_CR + 3)
+
+#define HCI_TXDMA_EN BIT(0)
+#define HCI_RXDMA_EN BIT(1)
+#define TXDMA_EN BIT(2)
+#define RXDMA_EN BIT(3)
+#define PROTOCOL_EN BIT(4)
+#define SCHEDULE_EN BIT(5)
+#define MACTXEN BIT(6)
+#define MACRXEN BIT(7)
+#define ENSWBCN BIT(8)
+#define ENSEC BIT(9)
+
+#define _NETTYPE(x) (((x) & 0x3) << 16)
+#define MASK_NETTYPE 0x30000
+#define NT_NO_LINK 0x0
+#define NT_LINK_AD_HOC 0x1
+#define NT_LINK_AP 0x2
+#define NT_AS_AP 0x3
+
+#define _LBMODE(x) (((x) & 0xF) << 24)
+#define MASK_LBMODE 0xF000000
+#define LOOPBACK_NORMAL 0x0
+#define LOOPBACK_IMMEDIATELY 0xB
+#define LOOPBACK_MAC_DELAY 0x3
+#define LOOPBACK_PHY 0x1
+#define LOOPBACK_DMA 0x7
+
+#define GET_RX_PAGE_SIZE(value) ((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4)
+#define _PSRX_MASK 0xF
+#define _PSTX_MASK 0xF0
+#define _PSRX(x) (x)
+#define _PSTX(x) ((x) << 4)
+
+#define PBP_64 0x0
+#define PBP_128 0x1
+#define PBP_256 0x2
+#define PBP_512 0x3
+#define PBP_1024 0x4
+
+#define RXDMA_ARBBW_EN BIT(0)
+#define RXSHFT_EN BIT(1)
+#define RXDMA_AGG_EN BIT(2)
+#define QS_VO_QUEUE BIT(8)
+#define QS_VI_QUEUE BIT(9)
+#define QS_BE_QUEUE BIT(10)
+#define QS_BK_QUEUE BIT(11)
+#define QS_MANAGER_QUEUE BIT(12)
+#define QS_HIGH_QUEUE BIT(13)
+
+#define HQSEL_VOQ BIT(0)
+#define HQSEL_VIQ BIT(1)
+#define HQSEL_BEQ BIT(2)
+#define HQSEL_BKQ BIT(3)
+#define HQSEL_MGTQ BIT(4)
+#define HQSEL_HIQ BIT(5)
+
+#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8)
+#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6)
+#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4)
+
+#define QUEUE_LOW 1
+#define QUEUE_NORMAL 2
+#define QUEUE_HIGH 3
+
+#define _LLT_NO_ACTIVE 0x0
+#define _LLT_WRITE_ACCESS 0x1
+#define _LLT_READ_ACCESS 0x2
+
+#define _LLT_INIT_DATA(x) ((x) & 0xFF)
+#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8)
+#define _LLT_OP(x) (((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3)
+
+#define BB_WRITE_READ_MASK (BIT(31) | BIT(30))
+#define BB_WRITE_EN BIT(30)
+#define BB_READ_EN BIT(31)
+
+#define _HPQ(x) ((x) & 0xFF)
+#define _LPQ(x) (((x) & 0xFF) << 8)
+#define _PUBQ(x) (((x) & 0xFF) << 16)
+#define _NPQ(x) ((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS BIT(24)
+#define LPQ_PUBLIC_DIS BIT(25)
+#define LD_RQPN BIT(31)
+
+#define BCN_VALID BIT(16)
+#define BCN_HEAD(x) (((x) & 0xFF) << 8)
+#define BCN_HEAD_MASK 0xFF00
+
+#define BLK_DESC_NUM_SHIFT 4
+#define BLK_DESC_NUM_MASK 0xF
+
+#define DROP_DATA_EN BIT(9)
+
+#define EN_AMPDU_RTY_NEW BIT(7)
+
+#define _INIRTSMCS_SEL(x) ((x) & 0x3F)
+
+#define _SPEC_SIFS_CCK(x) ((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8)
+
+#define RATE_REG_BITMAP_ALL 0xFFFFF
+
+#define _RRSC_BITMAP(x) ((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x) (((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED 0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL 0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL 0x2
+#define RRSR_RSC_DUPLICATE_MODE 0x3
+
+#define USE_SHORT_G1 BIT(20)
+
+#define _AGGLMT_MCS0(x) ((x) & 0xF)
+#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28)
+
+#define RETRY_LIMIT_SHORT_SHIFT 8
+#define RETRY_LIMIT_LONG_SHIFT 0
+
+#define _DARF_RC1(x) ((x) & 0x1F)
+#define _DARF_RC2(x) (((x) & 0x1F) << 8)
+#define _DARF_RC3(x) (((x) & 0x1F) << 16)
+#define _DARF_RC4(x) (((x) & 0x1F) << 24)
+#define _DARF_RC5(x) ((x) & 0x1F)
+#define _DARF_RC6(x) (((x) & 0x1F) << 8)
+#define _DARF_RC7(x) (((x) & 0x1F) << 16)
+#define _DARF_RC8(x) (((x) & 0x1F) << 24)
+
+#define _RARF_RC1(x) ((x) & 0x1F)
+#define _RARF_RC2(x) (((x) & 0x1F) << 8)
+#define _RARF_RC3(x) (((x) & 0x1F) << 16)
+#define _RARF_RC4(x) (((x) & 0x1F) << 24)
+#define _RARF_RC5(x) ((x) & 0x1F)
+#define _RARF_RC6(x) (((x) & 0x1F) << 8)
+#define _RARF_RC7(x) (((x) & 0x1F) << 16)
+#define _RARF_RC8(x) (((x) & 0x1F) << 24)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET 16
+#define AC_PARAM_ECW_MAX_OFFSET 12
+#define AC_PARAM_ECW_MIN_OFFSET 8
+#define AC_PARAM_AIFS_OFFSET 0
+
+#define _AIFS(x) (x)
+#define _ECW_MAX_MIN(x) ((x) << 8)
+#define _TXOP_LIMIT(x) ((x) << 16)
+
+#define _BCNIFS(x) ((x) & 0xFF)
+#define _BCNECW(x) ((((x) & 0xF)) << 8)
+
+#define _LRL(x) ((x) & 0x3F)
+#define _SRL(x) (((x) & 0x3F) << 8)
+
+#define _SIFS_CCK_CTX(x) ((x) & 0xFF)
+#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8);
+
+#define _SIFS_OFDM_CTX(x) ((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8);
+
+#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8)
+
+#define DIS_EDCA_CNT_DWN BIT(11)
+
+#define EN_MBSSID BIT(1)
+#define EN_TXBCN_RPT BIT(2)
+#define EN_BCN_FUNCTION BIT(3)
+
+#define TSFTR_RST BIT(0)
+#define TSFTR1_RST BIT(1)
+
+#define STOP_BCNQ BIT(6)
+
+#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4)
+#define DIS_TSF_UDT0_TEST_CHIP BIT(5)
+
+#define ACMHW_HWEN BIT(0)
+#define ACMHW_BEQEN BIT(1)
+#define ACMHW_VIQEN BIT(2)
+#define ACMHW_VOQEN BIT(3)
+#define ACMHW_BEQSTATUS BIT(4)
+#define ACMHW_VIQSTATUS BIT(5)
+#define ACMHW_VOQSTATUS BIT(6)
+
+#define APSDOFF BIT(6)
+#define APSDOFF_STATUS BIT(7)
+
+#define BW_20MHZ BIT(2)
+
+#define RATE_BITMAP_ALL 0xFFFFF
+
+#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1
+
+#define TSFRST BIT(0)
+#define DIS_GCLK BIT(1)
+#define PAD_SEL BIT(2)
+#define PWR_ST BIT(6)
+#define PWRBIT_OW_EN BIT(7)
+#define ACRC BIT(8)
+#define CFENDFORM BIT(9)
+#define ICV BIT(10)
+
+#define AAP BIT(0)
+#define APM BIT(1)
+#define AM BIT(2)
+#define AB BIT(3)
+#define ADD3 BIT(4)
+#define APWRMGT BIT(5)
+#define CBSSID BIT(6)
+#define CBSSID_DATA BIT(6)
+#define CBSSID_BCN BIT(7)
+#define ACRC32 BIT(8)
+#define AICV BIT(9)
+#define ADF BIT(11)
+#define ACF BIT(12)
+#define AMF BIT(13)
+#define HTC_LOC_CTRL BIT(14)
+#define UC_DATA_EN BIT(16)
+#define BM_DATA_EN BIT(17)
+#define MFBEN BIT(22)
+#define LSIGEN BIT(23)
+#define ENMBID BIT(24)
+#define APP_BASSN BIT(27)
+#define APP_PHYSTS BIT(28)
+#define APP_ICV BIT(29)
+#define APP_MIC BIT(30)
+#define APP_FCS BIT(31)
+
+#define _MIN_SPACE(x) ((x) & 0x7)
+#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3)
+
+#define RXERR_TYPE_OFDM_PPDU 0
+#define RXERR_TYPE_OFDM_FALSE_ALARM 1
+#define RXERR_TYPE_OFDM_MPDU_OK 2
+#define RXERR_TYPE_OFDM_MPDU_FAIL 3
+#define RXERR_TYPE_CCK_PPDU 4
+#define RXERR_TYPE_CCK_FALSE_ALARM 5
+#define RXERR_TYPE_CCK_MPDU_OK 6
+#define RXERR_TYPE_CCK_MPDU_FAIL 7
+#define RXERR_TYPE_HT_PPDU 8
+#define RXERR_TYPE_HT_FALSE_ALARM 9
+#define RXERR_TYPE_HT_MPDU_TOTAL 10
+#define RXERR_TYPE_HT_MPDU_OK 11
+#define RXERR_TYPE_HT_MPDU_FAIL 12
+#define RXERR_TYPE_RX_FULL_DROP 15
+
+#define RXERR_COUNTER_MASK 0xFFFFF
+#define RXERR_RPT_RST BIT(27)
+#define _RXERR_RPT_SEL(type) ((type) << 28)
+
+#define SCR_TXUSEDK BIT(0)
+#define SCR_RXUSEDK BIT(1)
+#define SCR_TXENCENABLE BIT(2)
+#define SCR_RXDECENABLE BIT(3)
+#define SCR_SKBYA2 BIT(4)
+#define SCR_NOSKMC BIT(5)
+#define SCR_TXBCUSEDK BIT(6)
+#define SCR_RXBCUSEDK BIT(7)
+
+#define USB_IS_HIGH_SPEED 0
+#define USB_IS_FULL_SPEED 1
+#define USB_SPEED_MASK BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK 0xF
+#define USB_NORMAL_SIE_EP_SHIFT 4
+
+#define USB_TEST_EP_MASK 0x30
+#define USB_TEST_EP_SHIFT 4
+
+#define USB_AGG_EN BIT(3)
+
+#define MAC_ADDR_LEN 6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER 175/*255 88e*/
+
+#define POLLING_LLT_THRESHOLD 20
+#define POLLING_READY_TIMEOUT_COUNT 3000
+
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6))
+#define EPROM_CMD_CONFIG 0x3
+#define EPROM_CMD_LOAD 1
+
+#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE
+
+#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2)
+
+#define RPMAC_RESET 0x100
+#define RPMAC_TXSTART 0x104
+#define RPMAC_TXLEGACYSIG 0x108
+#define RPMAC_TXHTSIG1 0x10c
+#define RPMAC_TXHTSIG2 0x110
+#define RPMAC_PHYDEBUG 0x114
+#define RPMAC_TXPACKETNUM 0x118
+#define RPMAC_TXIDLE 0x11c
+#define RPMAC_TXMACHEADER0 0x120
+#define RPMAC_TXMACHEADER1 0x124
+#define RPMAC_TXMACHEADER2 0x128
+#define RPMAC_TXMACHEADER3 0x12c
+#define RPMAC_TXMACHEADER4 0x130
+#define RPMAC_TXMACHEADER5 0x134
+#define RPMAC_TXDADATYPE 0x138
+#define RPMAC_TXRANDOMSEED 0x13c
+#define RPMAC_CCKPLCPPREAMBLE 0x140
+#define RPMAC_CCKPLCPHEADER 0x144
+#define RPMAC_CCKCRC16 0x148
+#define RPMAC_OFDMRXCRC32OK 0x170
+#define RPMAC_OFDMRXCRC32Er 0x174
+#define RPMAC_OFDMRXPARITYER 0x178
+#define RPMAC_OFDMRXCRC8ER 0x17c
+#define RPMAC_CCKCRXRC16ER 0x180
+#define RPMAC_CCKCRXRC32ER 0x184
+#define RPMAC_CCKCRXRC32OK 0x188
+#define RPMAC_TXSTATUS 0x18c
+
+#define RFPGA0_RFMOD 0x800
+
+#define RFPGA0_TXINFO 0x804
+#define RFPGA0_PSDFUNCTION 0x808
+
+#define RFPGA0_TXGAINSTAGE 0x80c
+
+#define RFPGA0_RFTIMING1 0x810
+#define RFPGA0_RFTIMING2 0x814
+
+#define RFPGA0_XA_HSSIPARAMETER1 0x820
+#define RFPGA0_XA_HSSIPARAMETER2 0x824
+#define RFPGA0_XB_HSSIPARAMETER1 0x828
+#define RFPGA0_XB_HSSIPARAMETER2 0x82c
+
+#define RFPGA0_XA_LSSIPARAMETER 0x840
+#define RFPGA0_XB_LSSIPARAMETER 0x844
+
+#define RFPGA0_RFWAKEUPPARAMETER 0x850
+#define RFPGA0_RFSLEEPUPPARAMETER 0x854
+
+#define RFPGA0_XAB_SWITCHCONTROL 0x858
+#define RFPGA0_XCD_SWITCHCONTROL 0x85c
+
+#define RFPGA0_XA_RFINTERFACEOE 0x860
+#define RFPGA0_XB_RFINTERFACEOE 0x864
+
+#define RFPGA0_XAB_RFINTERFACESW 0x870
+#define RFPGA0_XCD_RFINTERFACESW 0x874
+
+#define rFPGA0_XAB_RFPARAMETER 0x878
+#define rFPGA0_XCD_RFPARAMETER 0x87c
+
+#define RFPGA0_ANALOGPARAMETER1 0x880
+#define RFPGA0_ANALOGPARAMETER2 0x884
+#define RFPGA0_ANALOGPARAMETER3 0x888
+#define RFPGA0_ANALOGPARAMETER4 0x88c
+
+#define RFPGA0_XA_LSSIREADBACK 0x8a0
+#define RFPGA0_XB_LSSIREADBACK 0x8a4
+#define RFPGA0_XC_LSSIREADBACK 0x8a8
+#define RFPGA0_XD_LSSIREADBACK 0x8ac
+
+#define RFPGA0_PSDREPORT 0x8b4
+#define TRANSCEIVEA_HSPI_READBACK 0x8b8
+#define TRANSCEIVEB_HSPI_READBACK 0x8bc
+#define REG_SC_CNT 0x8c4
+#define RFPGA0_XAB_RFINTERFACERB 0x8e0
+#define RFPGA0_XCD_RFINTERFACERB 0x8e4
+
+#define RFPGA1_RFMOD 0x900
+
+#define RFPGA1_TXBLOCK 0x904
+#define RFPGA1_DEBUGSELECT 0x908
+#define RFPGA1_TXINFO 0x90c
+
+#define RCCK0_SYSTEM 0xa00
+
+#define RCCK0_AFESETTING 0xa04
+#define RCCK0_CCA 0xa08
+
+#define RCCK0_RXAGC1 0xa0c
+#define RCCK0_RXAGC2 0xa10
+
+#define RCCK0_RXHP 0xa14
+
+#define RCCK0_DSPPARAMETER1 0xa18
+#define RCCK0_DSPPARAMETER2 0xa1c
+
+#define RCCK0_TXFILTER1 0xa20
+#define RCCK0_TXFILTER2 0xa24
+#define RCCK0_DEBUGPORT 0xa28
+#define RCCK0_FALSEALARMREPORT 0xa2c
+#define RCCK0_TRSSIREPORT 0xa50
+#define RCCK0_RXREPORT 0xa54
+#define RCCK0_FACOUNTERLOWER 0xa5c
+#define RCCK0_FACOUNTERUPPER 0xa58
+#define RCCK0_CCA_CNT 0xa60
+
+
+/* PageB(0xB00) */
+#define RPDP_ANTA 0xb00
+#define RPDP_ANTA_4 0xb04
+#define RPDP_ANTA_8 0xb08
+#define RPDP_ANTA_C 0xb0c
+#define RPDP_ANTA_10 0xb10
+#define RPDP_ANTA_14 0xb14
+#define RPDP_ANTA_18 0xb18
+#define RPDP_ANTA_1C 0xb1c
+#define RPDP_ANTA_20 0xb20
+#define RPDP_ANTA_24 0xb24
+
+#define RCONFIG_PMPD_ANTA 0xb28
+#define RCONFIG_RAM64X16 0xb2c
+
+#define RBNDA 0xb30
+#define RHSSIPAR 0xb34
+
+#define RCONFIG_ANTA 0xb68
+#define RCONFIG_ANTB 0xb6c
+
+#define RPDP_ANTB 0xb70
+#define RPDP_ANTB_4 0xb74
+#define RPDP_ANTB_8 0xb78
+#define RPDP_ANTB_C 0xb7c
+#define RPDP_ANTB_10 0xb80
+#define RPDP_ANTB_14 0xb84
+#define RPDP_ANTB_18 0xb88
+#define RPDP_ANTB_1C 0xb8c
+#define RPDP_ANTB_20 0xb90
+#define RPDP_ANTB_24 0xb94
+
+#define RCONFIG_PMPD_ANTB 0xb98
+
+#define RBNDB 0xba0
+
+#define RAPK 0xbd8
+#define rPm_Rx0_AntA 0xbdc
+#define rPm_Rx1_AntA 0xbe0
+#define rPm_Rx2_AntA 0xbe4
+#define rPm_Rx3_AntA 0xbe8
+#define rPm_Rx0_AntB 0xbec
+#define rPm_Rx1_AntB 0xbf0
+#define rPm_Rx2_AntB 0xbf4
+#define rPm_Rx3_AntB 0xbf8
+
+/*Page C*/
+#define ROFDM0_LSTF 0xc00
+
+#define ROFDM0_TRXPATHENABLE 0xc04
+#define ROFDM0_TRMUXPAR 0xc08
+#define ROFDM0_TRSWISOLATION 0xc0c
+
+#define ROFDM0_XARXAFE 0xc10
+#define ROFDM0_XARXIQIMBAL 0xc14
+#define ROFDM0_XBRXAFE 0xc18
+#define ROFDM0_XBRXIQIMBAL 0xc1c
+#define ROFDM0_XCRXAFE 0xc20
+#define ROFDM0_XCRXIQIMBAL 0xc24
+#define ROFDM0_XDRXAFE 0xc28
+#define ROFDM0_XDRXIQIMBAL 0xc2c
+
+#define ROFDM0_RXDETECTOR1 0xc30
+#define ROFDM0_RXDETECTOR2 0xc34
+#define ROFDM0_RXDETECTOR3 0xc38
+#define ROFDM0_RXDETECTOR4 0xc3c
+
+#define ROFDM0_RXDSP 0xc40
+#define ROFDM0_CFOANDDAGC 0xc44
+#define ROFDM0_CCADROPTHRES 0xc48
+#define ROFDM0_ECCATHRES 0xc4c
+
+#define ROFDM0_XAAGCCORE1 0xc50
+#define ROFDM0_XAAGCCORE2 0xc54
+#define ROFDM0_XBAGCCORE1 0xc58
+#define ROFDM0_XBAGCCORE2 0xc5c
+#define ROFDM0_XCAGCCORE1 0xc60
+#define ROFDM0_XCAGCCORE2 0xc64
+#define ROFDM0_XDAGCCORE1 0xc68
+#define ROFDM0_XDAGCCORE2 0xc6c
+
+#define ROFDM0_AGCPARAMETER1 0xc70
+#define ROFDM0_AGCPARAMETER2 0xc74
+#define ROFDM0_AGCRSSITABLE 0xc78
+#define ROFDM0_HTSTFAGC 0xc7c
+
+#define ROFDM0_XATXIQIMBAL 0xc80
+#define ROFDM0_XATXAFE 0xc84
+#define ROFDM0_XBTXIQIMBAL 0xc88
+#define ROFDM0_XBTXAFE 0xc8c
+#define ROFDM0_XCTXIQIMBAL 0xc90
+#define ROFDM0_XCTXAFE 0xc94
+#define ROFDM0_XDTXIQIMBAL 0xc98
+#define ROFDM0_XDTXAFE 0xc9c
+
+#define ROFDM0_RXIQEXTANTA 0xca0
+#define ROFDM0_TXCOEFF1 0xca4
+#define ROFDM0_TXCOEFF2 0xca8
+#define ROFDM0_TXCOEFF3 0xcac
+#define ROFDM0_TXCOEFF4 0xcb0
+#define ROFDM0_TXCOEFF5 0xcb4
+#define ROFDM0_TXCOEFF6 0xcb8
+
+#define ROFDM0_RXHPPARAMETER 0xce0
+#define ROFDM0_TXPSEUDONOISEWGT 0xce4
+#define ROFDM0_FRAMESYNC 0xcf0
+#define ROFDM0_DFSREPORT 0xcf4
+
+
+#define ROFDM1_LSTF 0xd00
+#define ROFDM1_TRXPATHENABLE 0xd04
+
+#define ROFDM1_CF0 0xd08
+#define ROFDM1_CSI1 0xd10
+#define ROFDM1_SBD 0xd14
+#define ROFDM1_CSI2 0xd18
+#define ROFDM1_CFOTRACKING 0xd2c
+#define ROFDM1_TRXMESAURE1 0xd34
+#define ROFDM1_INTFDET 0xd3c
+#define ROFDM1_PSEUDONOISESTATEAB 0xd50
+#define ROFDM1_PSEUDONOISESTATECD 0xd54
+#define ROFDM1_RXPSEUDONOISEWGT 0xd58
+
+#define ROFDM_PHYCOUNTER1 0xda0
+#define ROFDM_PHYCOUNTER2 0xda4
+#define ROFDM_PHYCOUNTER3 0xda8
+
+#define ROFDM_SHORTCFOAB 0xdac
+#define ROFDM_SHORTCFOCD 0xdb0
+#define ROFDM_LONGCFOAB 0xdb4
+#define ROFDM_LONGCFOCD 0xdb8
+#define ROFDM_TAILCF0AB 0xdbc
+#define ROFDM_TAILCF0CD 0xdc0
+#define ROFDM_PWMEASURE1 0xdc4
+#define ROFDM_PWMEASURE2 0xdc8
+#define ROFDM_BWREPORT 0xdcc
+#define ROFDM_AGCREPORT 0xdd0
+#define ROFDM_RXSNR 0xdd4
+#define ROFDM_RXEVMCSI 0xdd8
+#define ROFDM_SIGREPORT 0xddc
+
+#define RTXAGC_A_RATE18_06 0xe00
+#define RTXAGC_A_RATE54_24 0xe04
+#define RTXAGC_A_CCK1_MCS32 0xe08
+#define RTXAGC_A_MCS03_MCS00 0xe10
+#define RTXAGC_A_MCS07_MCS04 0xe14
+#define RTXAGC_A_MCS11_MCS08 0xe18
+#define RTXAGC_A_MCS15_MCS12 0xe1c
+
+#define RTXAGC_B_RATE18_06 0x830
+#define RTXAGC_B_RATE54_24 0x834
+#define RTXAGC_B_CCK1_55_MCS32 0x838
+#define RTXAGC_B_MCS03_MCS00 0x83c
+#define RTXAGC_B_MCS07_MCS04 0x848
+#define RTXAGC_B_MCS11_MCS08 0x84c
+#define RTXAGC_B_MCS15_MCS12 0x868
+#define RTXAGC_B_CCK11_A_CCK2_11 0x86c
+
+#define RFPGA0_IQK 0xe28
+#define RTX_IQK_TONE_A 0xe30
+#define RRX_IQK_TONE_A 0xe34
+#define RTX_IQK_PI_A 0xe38
+#define RRX_IQK_PI_A 0xe3c
+
+#define RTX_IQK 0xe40
+#define RRX_IQK 0xe44
+#define RIQK_AGC_PTS 0xe48
+#define RIQK_AGC_RSP 0xe4c
+#define RTX_IQK_TONE_B 0xe50
+#define RRX_IQK_TONE_B 0xe54
+#define RTX_IQK_PI_B 0xe58
+#define RRX_IQK_PI_B 0xe5c
+#define RIQK_AGC_CONT 0xe60
+
+#define RBLUE_TOOTH 0xe6c
+#define RRX_WAIT_CCA 0xe70
+#define RTX_CCK_RFON 0xe74
+#define RTX_CCK_BBON 0xe78
+#define RTX_OFDM_RFON 0xe7c
+#define RTX_OFDM_BBON 0xe80
+#define RTX_TO_RX 0xe84
+#define RTX_TO_TX 0xe88
+#define RRX_CCK 0xe8c
+
+#define RTX_POWER_BEFORE_IQK_A 0xe94
+#define RTX_POWER_AFTER_IQK_A 0xe9c
+
+#define RRX_POWER_BEFORE_IQK_A 0xea0
+#define RRX_POWER_BEFORE_IQK_A_2 0xea4
+#define RRX_POWER_AFTER_IQK_A 0xea8
+#define RRX_POWER_AFTER_IQK_A_2 0xeac
+
+#define RTX_POWER_BEFORE_IQK_B 0xeb4
+#define RTX_POWER_AFTER_IQK_B 0xebc
+
+#define RRX_POWER_BEFORE_IQK_B 0xec0
+#define RRX_POWER_BEFORE_IQK_B_2 0xec4
+#define RRX_POWER_AFTER_IQK_B 0xec8
+#define RRX_POWER_AFTER_IQK_B_2 0xecc
+
+#define RRX_OFDM 0xed0
+#define RRX_WAIT_RIFS 0xed4
+#define RRX_TO_RX 0xed8
+#define RSTANDBY 0xedc
+#define RSLEEP 0xee0
+#define RPMPD_ANAEN 0xeec
+
+#define RZEBRA1_HSSIENABLE 0x0
+#define RZEBRA1_TRXENABLE1 0x1
+#define RZEBRA1_TRXENABLE2 0x2
+#define RZEBRA1_AGC 0x4
+#define RZEBRA1_CHARGEPUMP 0x5
+#define RZEBRA1_CHANNEL 0x7
+
+#define RZEBRA1_TXGAIN 0x8
+#define RZEBRA1_TXLPF 0x9
+#define RZEBRA1_RXLPF 0xb
+#define RZEBRA1_RXHPFCORNER 0xc
+
+#define RGLOBALCTRL 0
+#define RRTL8256_TXLPF 19
+#define RRTL8256_RXLPF 11
+#define RRTL8258_TXLPF 0x11
+#define RRTL8258_RXLPF 0x13
+#define RRTL8258_RSSILPF 0xa
+
+#define RF_AC 0x00
+
+#define RF_IQADJ_G1 0x01
+#define RF_IQADJ_G2 0x02
+#define RF_POW_TRSW 0x05
+
+#define RF_GAIN_RX 0x06
+#define RF_GAIN_TX 0x07
+
+#define RF_TXM_IDAC 0x08
+#define RF_BS_IQGEN 0x0F
+
+#define RF_MODE1 0x10
+#define RF_MODE2 0x11
+
+#define RF_RX_AGC_HP 0x12
+#define RF_TX_AGC 0x13
+#define RF_BIAS 0x14
+#define RF_IPA 0x15
+#define RF_POW_ABILITY 0x17
+#define RF_MODE_AG 0x18
+#define RRFCHANNEL 0x18
+#define RF_CHNLBW 0x18
+#define RF_TOP 0x19
+
+#define RF_RX_G1 0x1A
+#define RF_RX_G2 0x1B
+
+#define RF_RX_BB2 0x1C
+#define RF_RX_BB1 0x1D
+
+#define RF_RCK1 0x1E
+#define RF_RCK2 0x1F
+
+#define RF_TX_G1 0x20
+#define RF_TX_G2 0x21
+#define RF_TX_G3 0x22
+
+#define RF_TX_BB1 0x23
+#define RF_T_METER 0x42
+
+#define RF_SYN_G1 0x25
+#define RF_SYN_G2 0x26
+#define RF_SYN_G3 0x27
+#define RF_SYN_G4 0x28
+#define RF_SYN_G5 0x29
+#define RF_SYN_G6 0x2A
+#define RF_SYN_G7 0x2B
+#define RF_SYN_G8 0x2C
+
+#define RF_RCK_OS 0x30
+#define RF_TXPA_G1 0x31
+#define RF_TXPA_G2 0x32
+#define RF_TXPA_G3 0x33
+
+#define RF_TX_BIAS_A 0x35
+#define RF_TX_BIAS_D 0x36
+#define RF_LOBF_9 0x38
+#define RF_RXRF_A3 0x3C
+#define RF_TRSW 0x3F
+
+#define RF_TXRF_A2 0x41
+#define RF_TXPA_G4 0x46
+#define RF_TXPA_A4 0x4B
+
+#define RF_WE_LUT 0xEF
+
+#define BBBRESETB 0x100
+#define BGLOBALRESETB 0x200
+#define BOFDMTXSTART 0x4
+#define BCCKTXSTART 0x8
+#define BCRC32DEBUG 0x100
+#define BPMACLOOPBACK 0x10
+#define BTXLSIG 0xffffff
+#define BOFDMTXRATE 0xf
+#define BOFDMTXRESERVED 0x10
+#define BOFDMTXLENGTH 0x1ffe0
+#define BOFDMTXPARITY 0x20000
+#define BTXHTSIG1 0xffffff
+#define BTXHTMCSRATE 0x7f
+#define BTXHTBW 0x80
+#define BTXHTLENGTH 0xffff00
+#define BTXHTSIG2 0xffffff
+#define BTXHTSMOOTHING 0x1
+#define BTXHTSOUNDING 0x2
+#define BTXHTRESERVED 0x4
+#define BTXHTAGGREATION 0x8
+#define BTXHTSTBC 0x30
+#define BTXHTADVANCECODING 0x40
+#define BTXHTSHORTGI 0x80
+#define BTXHTNUMBERHT_LTF 0x300
+#define BTXHTCRC8 0x3fc00
+#define BCOUNTERRESET 0x10000
+#define BNUMOFOFDMTX 0xffff
+#define BNUMOFCCKTX 0xffff0000
+#define BTXIDLEINTERVAL 0xffff
+#define BOFDMSERVICE 0xffff0000
+#define BTXMACHEADER 0xffffffff
+#define BTXDATAINIT 0xff
+#define BTXHTMODE 0x100
+#define BTXDATATYPE 0x30000
+#define BTXRANDOMSEED 0xffffffff
+#define BCCKTXPREAMBLE 0x1
+#define BCCKTXSFD 0xffff0000
+#define BCCKTXSIG 0xff
+#define BCCKTXSERVICE 0xff00
+#define BCCKLENGTHEXT 0x8000
+#define BCCKTXLENGHT 0xffff0000
+#define BCCKTXCRC16 0xffff
+#define BCCKTXSTATUS 0x1
+#define BOFDMTXSTATUS 0x2
+#define IS_BB_REG_OFFSET_92S(_offset) \
+ ((_offset >= 0x800) && (_offset <= 0xfff))
+
+#define BRFMOD 0x1
+#define BJAPANMODE 0x2
+#define BCCKTXSC 0x30
+#define BCCKEN 0x1000000
+#define BOFDMEN 0x2000000
+
+#define BOFDMRXADCPHASE 0x10000
+#define BOFDMTXDACPHASE 0x40000
+#define BXATXAGC 0x3f
+
+#define BXBTXAGC 0xf00
+#define BXCTXAGC 0xf000
+#define BXDTXAGC 0xf0000
+
+#define BPASTART 0xf0000000
+#define BTRSTART 0x00f00000
+#define BRFSTART 0x0000f000
+#define BBBSTART 0x000000f0
+#define BBBCCKSTART 0x0000000f
+#define BPAEND 0xf
+#define BTREND 0x0f000000
+#define BRFEND 0x000f0000
+#define BCCAMASK 0x000000f0
+#define BR2RCCAMASK 0x00000f00
+#define BHSSI_R2TDELAY 0xf8000000
+#define BHSSI_T2RDELAY 0xf80000
+#define BCONTXHSSI 0x400
+#define BIGFROMCCK 0x200
+#define BAGCADDRESS 0x3f
+#define BRXHPTX 0x7000
+#define BRXHP2RX 0x38000
+#define BRXHPCCKINI 0xc0000
+#define BAGCTXCODE 0xc00000
+#define BAGCRXCODE 0x300000
+
+#define B3WIREDATALENGTH 0x800
+#define B3WIREADDREAALENGTH 0x400
+
+#define B3WIRERFPOWERDOWN 0x1
+#define B5GPAPEPOLARITY 0x40000000
+#define B2GPAPEPOLARITY 0x80000000
+#define BRFSW_TXDEFAULTANT 0x3
+#define BRFSW_TXOPTIONANT 0x30
+#define BRFSW_RXDEFAULTANT 0x300
+#define BRFSW_RXOPTIONANT 0x3000
+#define BRFSI_3WIREDATA 0x1
+#define BRFSI_3WIRECLOCK 0x2
+#define BRFSI_3WIRELOAD 0x4
+#define BRFSI_3WIRERW 0x8
+#define BRFSI_3WIRE 0xf
+
+#define BRFSI_RFENV 0x10
+
+#define BRFSI_TRSW 0x20
+#define BRFSI_TRSWB 0x40
+#define BRFSI_ANTSW 0x100
+#define BRFSI_ANTSWB 0x200
+#define BRFSI_PAPE 0x400
+#define BRFSI_PAPE5G 0x800
+#define BBANDSELECT 0x1
+#define BHTSIG2_GI 0x80
+#define BHTSIG2_SMOOTHING 0x01
+#define BHTSIG2_SOUNDING 0x02
+#define BHTSIG2_AGGREATON 0x08
+#define BHTSIG2_STBC 0x30
+#define BHTSIG2_ADVCODING 0x40
+#define BHTSIG2_NUMOFHTLTF 0x300
+#define BHTSIG2_CRC8 0x3fc
+#define BHTSIG1_MCS 0x7f
+#define BHTSIG1_BANDWIDTH 0x80
+#define BHTSIG1_HTLENGTH 0xffff
+#define BLSIG_RATE 0xf
+#define BLSIG_RESERVED 0x10
+#define BLSIG_LENGTH 0x1fffe
+#define BLSIG_PARITY 0x20
+#define BCCKRXPHASE 0x4
+
+#define BLSSIREADADDRESS 0x7f800000
+#define BLSSIREADEDGE 0x80000000
+
+#define BLSSIREADBACKDATA 0xfffff
+
+#define BLSSIREADOKFLAG 0x1000
+#define BCCKSAMPLERATE 0x8
+#define BREGULATOR0STANDBY 0x1
+#define BREGULATORPLLSTANDBY 0x2
+#define BREGULATOR1STANDBY 0x4
+#define BPLLPOWERUP 0x8
+#define BDPLLPOWERUP 0x10
+#define BDA10POWERUP 0x20
+#define BAD7POWERUP 0x200
+#define BDA6POWERUP 0x2000
+#define BXTALPOWERUP 0x4000
+#define B40MDCLKPOWERUP 0x8000
+#define BDA6DEBUGMODE 0x20000
+#define BDA6SWING 0x380000
+
+#define BADCLKPHASE 0x4000000
+#define B80MCLKDELAY 0x18000000
+#define BAFEWATCHDOGENABLE 0x20000000
+
+#define BXTALCAP01 0xc0000000
+#define BXTALCAP23 0x3
+#define BXTALCAP92X 0x0f000000
+#define BXTALCAP 0x0f000000
+
+#define BINTDIFCLKENABLE 0x400
+#define BEXTSIGCLKENABLE 0x800
+#define BBANDGAP_MBIAS_POWERUP 0x10000
+#define BAD11SH_GAIN 0xc0000
+#define BAD11NPUT_RANGE 0x700000
+#define BAD110P_CURRENT 0x3800000
+#define BLPATH_LOOPBACK 0x4000000
+#define BQPATH_LOOPBACK 0x8000000
+#define BAFE_LOOPBACK 0x10000000
+#define BDA10_SWING 0x7e0
+#define BDA10_REVERSE 0x800
+#define BDA_CLK_SOURCE 0x1000
+#define BDA7INPUT_RANGE 0x6000
+#define BDA7_GAIN 0x38000
+#define BDA7OUTPUT_CM_MODE 0x40000
+#define BDA7INPUT_CM_MODE 0x380000
+#define BDA7CURRENT 0xc00000
+#define BREGULATOR_ADJUST 0x7000000
+#define BAD11POWERUP_ATTX 0x1
+#define BDA10PS_ATTX 0x10
+#define BAD11POWERUP_ATRX 0x100
+#define BDA10PS_ATRX 0x1000
+#define BCCKRX_AGC_FORMAT 0x200
+#define BPSDFFT_SAMPLE_POINT 0xc000
+#define BPSD_AVERAGE_NUM 0x3000
+#define BIQPATH_CONTROL 0xc00
+#define BPSD_FREQ 0x3ff
+#define BPSD_ANTENNA_PATH 0x30
+#define BPSD_IQ_SWITCH 0x40
+#define BPSD_RX_TRIGGER 0x400000
+#define BPSD_TX_TRIGGERCW 0x80000000
+#define BPSD_SINE_TONE_SCALE 0x7f000000
+#define BPSD_REPORT 0xffff
+
+#define BOFDM_TXSC 0x30000000
+#define BCCK_TXON 0x1
+#define BOFDM_TXON 0x2
+#define BDEBUG_PAGE 0xfff
+#define BDEBUG_ITEM 0xff
+#define BANTL 0x10
+#define BANT_NONHT 0x100
+#define BANT_HT1 0x1000
+#define BANT_HT2 0x10000
+#define BANT_HT1S1 0x100000
+#define BANT_NONHTS1 0x1000000
+
+#define BCCK_BBMODE 0x3
+#define BCCK_TXPOWERSAVING 0x80
+#define BCCK_RXPOWERSAVING 0x40
+
+#define BCCK_SIDEBAND 0x10
+
+#define BCCK_SCRAMBLE 0x8
+#define BCCK_ANTDIVERSITY 0x8000
+#define BCCK_CARRIER_RECOVERY 0x4000
+#define BCCK_TXRATE 0x3000
+#define BCCK_DCCANCEL 0x0800
+#define BCCK_ISICANCEL 0x0400
+#define BCCK_MATCH_FILTER 0x0200
+#define BCCK_EQUALIZER 0x0100
+#define BCCK_PREAMBLE_DETECT 0x800000
+#define BCCK_FAST_FALSECCA 0x400000
+#define BCCK_CH_ESTSTART 0x300000
+#define BCCK_CCA_COUNT 0x080000
+#define BCCK_CS_LIM 0x070000
+#define BCCK_BIST_MODE 0x80000000
+#define BCCK_CCAMASK 0x40000000
+#define BCCK_TX_DAC_PHASE 0x4
+#define BCCK_RX_ADC_PHASE 0x20000000
+#define BCCKR_CP_MODE 0x0100
+#define BCCK_TXDC_OFFSET 0xf0
+#define BCCK_RXDC_OFFSET 0xf
+#define BCCK_CCA_MODE 0xc000
+#define BCCK_FALSECS_LIM 0x3f00
+#define BCCK_CS_RATIO 0xc00000
+#define BCCK_CORGBIT_SEL 0x300000
+#define BCCK_PD_LIM 0x0f0000
+#define BCCK_NEWCCA 0x80000000
+#define BCCK_RXHP_OF_IG 0x8000
+#define BCCK_RXIG 0x7f00
+#define BCCK_LNA_POLARITY 0x800000
+#define BCCK_RX1ST_BAIN 0x7f0000
+#define BCCK_RF_EXTEND 0x20000000
+#define BCCK_RXAGC_SATLEVEL 0x1f000000
+#define BCCK_RXAGC_SATCOUNT 0xe0
+#define BCCKRXRFSETTLE 0x1f
+#define BCCK_FIXED_RXAGC 0x8000
+#define BCCK_ANTENNA_POLARITY 0x2000
+#define BCCK_TXFILTER_TYPE 0x0c00
+#define BCCK_RXAGC_REPORTTYPE 0x0300
+#define BCCK_RXDAGC_EN 0x80000000
+#define BCCK_RXDAGC_PERIOD 0x20000000
+#define BCCK_RXDAGC_SATLEVEL 0x1f000000
+#define BCCK_TIMING_RECOVERY 0x800000
+#define BCCK_TXC0 0x3f0000
+#define BCCK_TXC1 0x3f000000
+#define BCCK_TXC2 0x3f
+#define BCCK_TXC3 0x3f00
+#define BCCK_TXC4 0x3f0000
+#define BCCK_TXC5 0x3f000000
+#define BCCK_TXC6 0x3f
+#define BCCK_TXC7 0x3f00
+#define BCCK_DEBUGPORT 0xff0000
+#define BCCK_DAC_DEBUG 0x0f000000
+#define BCCK_FALSEALARM_ENABLE 0x8000
+#define BCCK_FALSEALARM_READ 0x4000
+#define BCCK_TRSSI 0x7f
+#define BCCK_RXAGC_REPORT 0xfe
+#define BCCK_RXREPORT_ANTSEL 0x80000000
+#define BCCK_RXREPORT_MFOFF 0x40000000
+#define BCCK_RXREPORT_SQLOSS 0x20000000
+#define BCCK_RXREPORT_PKTLOSS 0x10000000
+#define BCCK_RXREPORT_LOCKEDBIT 0x08000000
+#define BCCK_RXREPORT_RATEERROR 0x04000000
+#define BCCK_RXREPORT_RXRATE 0x03000000
+#define BCCK_RXFA_COUNTER_LOWER 0xff
+#define BCCK_RXFA_COUNTER_UPPER 0xff000000
+#define BCCK_RXHPAGC_START 0xe000
+#define BCCK_RXHPAGC_FINAL 0x1c00
+#define BCCK_RXFALSEALARM_ENABLE 0x8000
+#define BCCK_FACOUNTER_FREEZE 0x4000
+#define BCCK_TXPATH_SEL 0x10000000
+#define BCCK_DEFAULT_RXPATH 0xc000000
+#define BCCK_OPTION_RXPATH 0x3000000
+
+#define BNUM_OFSTF 0x3
+#define BSHIFT_L 0xc0
+#define BGI_TH 0xc
+#define BRXPATH_A 0x1
+#define BRXPATH_B 0x2
+#define BRXPATH_C 0x4
+#define BRXPATH_D 0x8
+#define BTXPATH_A 0x1
+#define BTXPATH_B 0x2
+#define BTXPATH_C 0x4
+#define BTXPATH_D 0x8
+#define BTRSSI_FREQ 0x200
+#define BADC_BACKOFF 0x3000
+#define BDFIR_BACKOFF 0xc000
+#define BTRSSI_LATCH_PHASE 0x10000
+#define BRX_LDC_OFFSET 0xff
+#define BRX_QDC_OFFSET 0xff00
+#define BRX_DFIR_MODE 0x1800000
+#define BRX_DCNF_TYPE 0xe000000
+#define BRXIQIMB_A 0x3ff
+#define BRXIQIMB_B 0xfc00
+#define BRXIQIMB_C 0x3f0000
+#define BRXIQIMB_D 0xffc00000
+#define BDC_DC_NOTCH 0x60000
+#define BRXNB_NOTCH 0x1f000000
+#define BPD_TH 0xf
+#define BPD_TH_OPT2 0xc000
+#define BPWED_TH 0x700
+#define BIFMF_WIN_L 0x800
+#define BPD_OPTION 0x1000
+#define BMF_WIN_L 0xe000
+#define BBW_SEARCH_L 0x30000
+#define BWIN_ENH_L 0xc0000
+#define BBW_TH 0x700000
+#define BED_TH2 0x3800000
+#define BBW_OPTION 0x4000000
+#define BRADIO_TH 0x18000000
+#define BWINDOW_L 0xe0000000
+#define BSBD_OPTION 0x1
+#define BFRAME_TH 0x1c
+#define BFS_OPTION 0x60
+#define BDC_SLOPE_CHECK 0x80
+#define BFGUARD_COUNTER_DC_L 0xe00
+#define BFRAME_WEIGHT_SHORT 0x7000
+#define BSUB_TUNE 0xe00000
+#define BFRAME_DC_LENGTH 0xe000000
+#define BSBD_START_OFFSET 0x30000000
+#define BFRAME_TH_2 0x7
+#define BFRAME_GI2_TH 0x38
+#define BGI2_SYNC_EN 0x40
+#define BSARCH_SHORT_EARLY 0x300
+#define BSARCH_SHORT_LATE 0xc00
+#define BSARCH_GI2_LATE 0x70000
+#define BCFOANTSUM 0x1
+#define BCFOACC 0x2
+#define BCFOSTARTOFFSET 0xc
+#define BCFOLOOPBACK 0x70
+#define BCFOSUMWEIGHT 0x80
+#define BDAGCENABLE 0x10000
+#define BTXIQIMB_A 0x3ff
+#define BTXIQIMB_B 0xfc00
+#define BTXIQIMB_C 0x3f0000
+#define BTXIQIMB_D 0xffc00000
+#define BTXIDCOFFSET 0xff
+#define BTXIQDCOFFSET 0xff00
+#define BTXDFIRMODE 0x10000
+#define BTXPESUDO_NOISEON 0x4000000
+#define BTXPESUDO_NOISE_A 0xff
+#define BTXPESUDO_NOISE_B 0xff00
+#define BTXPESUDO_NOISE_C 0xff0000
+#define BTXPESUDO_NOISE_D 0xff000000
+#define BCCA_DROPOPTION 0x20000
+#define BCCA_DROPTHRES 0xfff00000
+#define BEDCCA_H 0xf
+#define BEDCCA_L 0xf0
+#define BLAMBDA_ED 0x300
+#define BRX_INITIALGAIN 0x7f
+#define BRX_ANTDIV_EN 0x80
+#define BRX_AGC_ADDRESS_FOR_LNA 0x7f00
+#define BRX_HIGHPOWER_FLOW 0x8000
+#define BRX_AGC_FREEZE_THRES 0xc0000
+#define BRX_FREEZESTEP_AGC1 0x300000
+#define BRX_FREEZESTEP_AGC2 0xc00000
+#define BRX_FREEZESTEP_AGC3 0x3000000
+#define BRX_FREEZESTEP_AGC0 0xc000000
+#define BRXRSSI_CMP_EN 0x10000000
+#define BRXQUICK_AGCEN 0x20000000
+#define BRXAGC_FREEZE_THRES_MODE 0x40000000
+#define BRX_OVERFLOW_CHECKTYPE 0x80000000
+#define BRX_AGCSHIFT 0x7f
+#define BTRSW_TRI_ONLY 0x80
+#define BPOWER_THRES 0x300
+#define BRXAGC_EN 0x1
+#define BRXAGC_TOGETHER_EN 0x2
+#define BRXAGC_MIN 0x4
+#define BRXHP_INI 0x7
+#define BRXHP_TRLNA 0x70
+#define BRXHP_RSSI 0x700
+#define BRXHP_BBP1 0x7000
+#define BRXHP_BBP2 0x70000
+#define BRXHP_BBP3 0x700000
+#define BRSSI_H 0x7f0000
+#define BRSSI_GEN 0x7f000000
+#define BRXSETTLE_TRSW 0x7
+#define BRXSETTLE_LNA 0x38
+#define BRXSETTLE_RSSI 0x1c0
+#define BRXSETTLE_BBP 0xe00
+#define BRXSETTLE_RXHP 0x7000
+#define BRXSETTLE_ANTSW_RSSI 0x38000
+#define BRXSETTLE_ANTSW 0xc0000
+#define BRXPROCESS_TIME_DAGC 0x300000
+#define BRXSETTLE_HSSI 0x400000
+#define BRXPROCESS_TIME_BBPPW 0x800000
+#define BRXANTENNA_POWER_SHIFT 0x3000000
+#define BRSSI_TABLE_SELECT 0xc000000
+#define BRXHP_FINAL 0x7000000
+#define BRXHPSETTLE_BBP 0x7
+#define BRXHTSETTLE_HSSI 0x8
+#define BRXHTSETTLE_RXHP 0x70
+#define BRXHTSETTLE_BBPPW 0x80
+#define BRXHTSETTLE_IDLE 0x300
+#define BRXHTSETTLE_RESERVED 0x1c00
+#define BRXHT_RXHP_EN 0x8000
+#define BRXAGC_FREEZE_THRES 0x30000
+#define BRXAGC_TOGETHEREN 0x40000
+#define BRXHTAGC_MIN 0x80000
+#define BRXHTAGC_EN 0x100000
+#define BRXHTDAGC_EN 0x200000
+#define BRXHT_RXHP_BBP 0x1c00000
+#define BRXHT_RXHP_FINAL 0xe0000000
+#define BRXPW_RADIO_TH 0x3
+#define BRXPW_RADIO_EN 0x4
+#define BRXMF_HOLD 0x3800
+#define BRXPD_DELAY_TH1 0x38
+#define BRXPD_DELAY_TH2 0x1c0
+#define BRXPD_DC_COUNT_MAX 0x600
+#define BRXPD_DELAY_TH 0x8000
+#define BRXPROCESS_DELAY 0xf0000
+#define BRXSEARCHRANGE_GI2_EARLY 0x700000
+#define BRXFRAME_FUARD_COUNTER_L 0x3800000
+#define BRXSGI_GUARD_L 0xc000000
+#define BRXSGI_SEARCH_L 0x30000000
+#define BRXSGI_TH 0xc0000000
+#define BDFSCNT0 0xff
+#define BDFSCNT1 0xff00
+#define BDFSFLAG 0xf0000
+#define BMF_WEIGHT_SUM 0x300000
+#define BMINIDX_TH 0x7f000000
+#define BDAFORMAT 0x40000
+#define BTXCH_EMU_ENABLE 0x01000000
+#define BTRSW_ISOLATION_A 0x7f
+#define BTRSW_ISOLATION_B 0x7f00
+#define BTRSW_ISOLATION_C 0x7f0000
+#define BTRSW_ISOLATION_D 0x7f000000
+#define BEXT_LNA_GAIN 0x7c00
+
+#define BSTBC_EN 0x4
+#define BANTENNA_MAPPING 0x10
+#define BNSS 0x20
+#define BCFO_ANTSUM_ID 0x200
+#define BPHY_COUNTER_RESET 0x8000000
+#define BCFO_REPORT_GET 0x4000000
+#define BOFDM_CONTINUE_TX 0x10000000
+#define BOFDM_SINGLE_CARRIER 0x20000000
+#define BOFDM_SINGLE_TONE 0x40000000
+#define BHT_DETECT 0x100
+#define BCFOEN 0x10000
+#define BCFOVALUE 0xfff00000
+#define BSIGTONE_RE 0x3f
+#define BSIGTONE_IM 0x7f00
+#define BCOUNTER_CCA 0xffff
+#define BCOUNTER_PARITYFAIL 0xffff0000
+#define BCOUNTER_RATEILLEGAL 0xffff
+#define BCOUNTER_CRC8FAIL 0xffff0000
+#define BCOUNTER_MCSNOSUPPORT 0xffff
+#define BCOUNTER_FASTSYNC 0xffff
+#define BSHORTCFO 0xfff
+#define BSHORTCFOT_LENGTH 12
+#define BSHORTCFOF_LENGTH 11
+#define BLONGCFO 0x7ff
+#define BLONGCFOT_LENGTH 11
+#define BLONGCFOF_LENGTH 11
+#define BTAILCFO 0x1fff
+#define BTAILCFOT_LENGTH 13
+#define BTAILCFOF_LENGTH 12
+#define BNOISE_EN_PWDB 0xffff
+#define BCC_POWER_DB 0xffff0000
+#define BMOISE_PWDB 0xffff
+#define BPOWERMEAST_LENGTH 10
+#define BPOWERMEASF_LENGTH 3
+#define BRX_HT_BW 0x1
+#define BRXSC 0x6
+#define BRX_HT 0x8
+#define BNB_INTF_DET_ON 0x1
+#define BINTF_WIN_LEN_CFG 0x30
+#define BNB_INTF_TH_CFG 0x1c0
+#define BRFGAIN 0x3f
+#define BTABLESEL 0x40
+#define BTRSW 0x80
+#define BRXSNR_A 0xff
+#define BRXSNR_B 0xff00
+#define BRXSNR_C 0xff0000
+#define BRXSNR_D 0xff000000
+#define BSNR_EVMT_LENGTH 8
+#define BSNR_EVMF_LENGTH 1
+#define BCSI1ST 0xff
+#define BCSI2ND 0xff00
+#define BRXEVM1ST 0xff0000
+#define BRXEVM2ND 0xff000000
+#define BSIGEVM 0xff
+#define BPWDB 0xff00
+#define BSGIEN 0x10000
+
+#define BSFACTOR_QMA1 0xf
+#define BSFACTOR_QMA2 0xf0
+#define BSFACTOR_QMA3 0xf00
+#define BSFACTOR_QMA4 0xf000
+#define BSFACTOR_QMA5 0xf0000
+#define BSFACTOR_QMA6 0xf0000
+#define BSFACTOR_QMA7 0xf00000
+#define BSFACTOR_QMA8 0xf000000
+#define BSFACTOR_QMA9 0xf0000000
+#define BCSI_SCHEME 0x100000
+
+#define BNOISE_LVL_TOP_SET 0x3
+#define BCHSMOOTH 0x4
+#define BCHSMOOTH_CFG1 0x38
+#define BCHSMOOTH_CFG2 0x1c0
+#define BCHSMOOTH_CFG3 0xe00
+#define BCHSMOOTH_CFG4 0x7000
+#define BMRCMODE 0x800000
+#define BTHEVMCFG 0x7000000
+
+#define BLOOP_FIT_TYPE 0x1
+#define BUPD_CFO 0x40
+#define BUPD_CFO_OFFDATA 0x80
+#define BADV_UPD_CFO 0x100
+#define BADV_TIME_CTRL 0x800
+#define BUPD_CLKO 0x1000
+#define BFC 0x6000
+#define BTRACKING_MODE 0x8000
+#define BPHCMP_ENABLE 0x10000
+#define BUPD_CLKO_LTF 0x20000
+#define BCOM_CH_CFO 0x40000
+#define BCSI_ESTI_MODE 0x80000
+#define BADV_UPD_EQZ 0x100000
+#define BUCHCFG 0x7000000
+#define BUPDEQZ 0x8000000
+
+#define BRX_PESUDO_NOISE_ON 0x20000000
+#define BRX_PESUDO_NOISE_A 0xff
+#define BRX_PESUDO_NOISE_B 0xff00
+#define BRX_PESUDO_NOISE_C 0xff0000
+#define BRX_PESUDO_NOISE_D 0xff000000
+#define BRX_PESUDO_NOISESTATE_A 0xffff
+#define BRX_PESUDO_NOISESTATE_B 0xffff0000
+#define BRX_PESUDO_NOISESTATE_C 0xffff
+#define BRX_PESUDO_NOISESTATE_D 0xffff0000
+
+#define BZEBRA1_HSSIENABLE 0x8
+#define BZEBRA1_TRXCONTROL 0xc00
+#define BZEBRA1_TRXGAINSETTING 0x07f
+#define BZEBRA1_RXCOUNTER 0xc00
+#define BZEBRA1_TXCHANGEPUMP 0x38
+#define BZEBRA1_RXCHANGEPUMP 0x7
+#define BZEBRA1_CHANNEL_NUM 0xf80
+#define BZEBRA1_TXLPFBW 0x400
+#define BZEBRA1_RXLPFBW 0x600
+
+#define BRTL8256REG_MODE_CTRL1 0x100
+#define BRTL8256REG_MODE_CTRL0 0x40
+#define BRTL8256REG_TXLPFBW 0x18
+#define BRTL8256REG_RXLPFBW 0x600
+
+#define BRTL8258_TXLPFBW 0xc
+#define BRTL8258_RXLPFBW 0xc00
+#define BRTL8258_RSSILPFBW 0xc0
+
+#define BBYTE0 0x1
+#define BBYTE1 0x2
+#define BBYTE2 0x4
+#define BBYTE3 0x8
+#define BWORD0 0x3
+#define BWORD1 0xc
+#define BWORD 0xf
+
+#define MASKBYTE0 0xff
+#define MASKBYTE1 0xff00
+#define MASKBYTE2 0xff0000
+#define MASKBYTE3 0xff000000
+#define MASKHWORD 0xffff0000
+#define MASKLWORD 0x0000ffff
+#define MASKDWORD 0xffffffff
+#define MASK12BITS 0xfff
+#define MASKH4BITS 0xf0000000
+#define MASKOFDM_D 0xffc00000
+#define MASKCCK 0x3f3f3f3f
+
+#define MASK4BITS 0x0f
+#define MASK20BITS 0xfffff
+#define RFREG_OFFSET_MASK 0xfffff
+
+#define BENABLE 0x1
+#define BDISABLE 0x0
+
+#define LEFT_ANTENNA 0x0
+#define RIGHT_ANTENNA 0x1
+
+#define TCHECK_TXSTATUS 500
+#define TUPDATE_RXCOUNTER 100
+
+#define REG_UN_USED_REGISTER 0x01bf
+
+/* WOL bit information */
+#define HAL92C_WOL_PTK_UPDATE_EVENT BIT(0)
+#define HAL92C_WOL_GTK_UPDATE_EVENT BIT(1)
+#define HAL92C_WOL_DISASSOC_EVENT BIT(2)
+#define HAL92C_WOL_DEAUTH_EVENT BIT(3)
+#define HAL92C_WOL_FW_DISCONNECT_EVENT BIT(4)
+
+#define WOL_REASON_PTK_UPDATE BIT(0)
+#define WOL_REASON_GTK_UPDATE BIT(1)
+#define WOL_REASON_DISASSOC BIT(2)
+#define WOL_REASON_DEAUTH BIT(3)
+#define WOL_REASON_FW_DISCONNECT BIT(4)
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c
new file mode 100644
index 000000000000..4faafdbab9c6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c
@@ -0,0 +1,467 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+void rtl88e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ switch (bandwidth) {
+ case HT_CHANNEL_WIDTH_20:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | BIT(10) | BIT(11));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | BIT(10));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "unknown bandwidth: %#X\n", bandwidth);
+ break;
+ }
+}
+
+void rtl88e_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *plevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 tx_agc[2] = {0, 0}, tmpval;
+ bool turbo_scanoff = false;
+ u8 idx1, idx2;
+ u8 *ptr;
+ u8 direction;
+ u32 pwrtrac_value;
+
+ if (rtlefuse->eeprom_regulatory != 0)
+ turbo_scanoff = true;
+
+ if (mac->act_scanning == true) {
+ tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
+ tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
+
+ if (turbo_scanoff) {
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ tx_agc[idx1] = plevel[idx1] |
+ (plevel[idx1] << 8) |
+ (plevel[idx1] << 16) |
+ (plevel[idx1] << 24);
+ }
+ }
+ } else {
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ tx_agc[idx1] = plevel[idx1] | (plevel[idx1] << 8) |
+ (plevel[idx1] << 16) |
+ (plevel[idx1] << 24);
+ }
+
+ if (rtlefuse->eeprom_regulatory == 0) {
+ tmpval = (rtlphy->mcs_offset[0][6]) +
+ (rtlphy->mcs_offset[0][7] << 8);
+ tx_agc[RF90_PATH_A] += tmpval;
+
+ tmpval = (rtlphy->mcs_offset[0][14]) +
+ (rtlphy->mcs_offset[0][15] << 24);
+ tx_agc[RF90_PATH_B] += tmpval;
+ }
+ }
+
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ ptr = (u8 *)(&(tx_agc[idx1]));
+ for (idx2 = 0; idx2 < 4; idx2++) {
+ if (*ptr > RF6052_MAX_TX_PWR)
+ *ptr = RF6052_MAX_TX_PWR;
+ ptr++;
+ }
+ }
+ rtl88e_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+ if (direction == 1) {
+ tx_agc[0] += pwrtrac_value;
+ tx_agc[1] += pwrtrac_value;
+ } else if (direction == 2) {
+ tx_agc[0] -= pwrtrac_value;
+ tx_agc[1] -= pwrtrac_value;
+ }
+ tmpval = tx_agc[RF90_PATH_A] & 0xff;
+ rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_A_CCK1_MCS32);
+
+ tmpval = tx_agc[RF90_PATH_A] >> 8;
+
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK11_A_CCK2_11);
+
+ tmpval = tx_agc[RF90_PATH_B] >> 24;
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK11_A_CCK2_11);
+
+ tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
+ rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK1_55_MCS32);
+}
+
+static void rtl88e_phy_get_power_base(struct ieee80211_hw *hw,
+ u8 *pwrlvlofdm, u8 *pwrlvlbw20,
+ u8 *pwrlvlbw40, u8 channel,
+ u32 *ofdmbase, u32 *mcsbase)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 base0, base1;
+ u8 i, powerlevel[2];
+
+ for (i = 0; i < 2; i++) {
+ base0 = pwrlvlofdm[i];
+
+ base0 = (base0 << 24) | (base0 << 16) |
+ (base0 << 8) | base0;
+ *(ofdmbase + i) = base0;
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "[OFDM power base index rf(%c) = 0x%x]\n",
+ ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
+ powerlevel[i] = pwrlvlbw20[i];
+ else
+ powerlevel[i] = pwrlvlbw40[i];
+ base1 = powerlevel[i];
+ base1 = (base1 << 24) |
+ (base1 << 16) | (base1 << 8) | base1;
+
+ *(mcsbase + i) = base1;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "[MCS power base index rf(%c) = 0x%x]\n",
+ ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+ }
+}
+
+static void get_txpwr_by_reg(struct ieee80211_hw *hw, u8 chan, u8 index,
+ u32 *base0, u32 *base1, u32 *outval)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 i, chg = 0, pwr_lim[4], pwr_diff = 0, cust_pwr_dif;
+ u32 writeval, cust_lim, rf, tmp;
+ u8 ch = chan - 1;
+ u8 j;
+
+ for (rf = 0; rf < 2; rf++) {
+ j = index + (rf ? 8 : 0);
+ tmp = ((index < 2) ? base0[rf] : base1[rf]);
+ switch (rtlefuse->eeprom_regulatory) {
+ case 0:
+ chg = 0;
+
+ writeval = rtlphy->mcs_offset[chg][j] + tmp;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "RTK better performance, "
+ "writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ case 1:
+ if (rtlphy->pwrgroup_cnt == 1) {
+ chg = 0;
+ } else {
+ chg = chan / 3;
+ if (chan == 14)
+ chg = 5;
+ }
+ writeval = rtlphy->mcs_offset[chg][j] + tmp;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ case 2:
+ writeval = ((index < 2) ? base0[rf] : base1[rf]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Better regulatory, writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ case 3:
+ chg = 0;
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "customer's limit, 40MHz rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'),
+ rtlefuse->pwrgroup_ht40[rf][ch]);
+ } else {
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "customer's limit, 20MHz rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'),
+ rtlefuse->pwrgroup_ht20[rf][ch]);
+ }
+
+ if (index < 2)
+ pwr_diff = rtlefuse->txpwr_legacyhtdiff[rf][ch];
+ else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
+ pwr_diff = rtlefuse->txpwr_ht20diff[rf][ch];
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
+ cust_pwr_dif = rtlefuse->pwrgroup_ht40[rf][ch];
+ else
+ cust_pwr_dif = rtlefuse->pwrgroup_ht20[rf][ch];
+
+ if (pwr_diff > cust_pwr_dif)
+ pwr_diff = 0;
+ else
+ pwr_diff = cust_pwr_dif - pwr_diff;
+
+ for (i = 0; i < 4; i++) {
+ pwr_lim[i] = (u8)((rtlphy->mcs_offset[chg][j] &
+ (0x7f << (i * 8))) >> (i * 8));
+
+ if (pwr_lim[i] > pwr_diff)
+ pwr_lim[i] = pwr_diff;
+ }
+
+ cust_lim = (pwr_lim[3] << 24) | (pwr_lim[2] << 16) |
+ (pwr_lim[1] << 8) | (pwr_lim[0]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Customer's limit rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), cust_lim);
+
+ writeval = cust_lim + tmp;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Customer, writeval rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ default:
+ chg = 0;
+ writeval = rtlphy->mcs_offset[chg][j] + tmp;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "RTK better performance, writeval "
+ "rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ }
+
+ if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
+ writeval = writeval - 0x06060606;
+ else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TXHIGHPWRLEVEL_BT2)
+ writeval -= 0x0c0c0c0c;
+ *(outval + rf) = writeval;
+ }
+}
+
+static void write_ofdm_pwr(struct ieee80211_hw *hw, u8 index, u32 *pvalue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 regoffset_a[6] = {
+ RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,
+ RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
+ RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
+ };
+ u16 regoffset_b[6] = {
+ RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,
+ RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
+ RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
+ };
+ u8 i, rf, pwr_val[4];
+ u32 writeval;
+ u16 regoffset;
+
+ for (rf = 0; rf < 2; rf++) {
+ writeval = pvalue[rf];
+ for (i = 0; i < 4; i++) {
+ pwr_val[i] = (u8) ((writeval & (0x7f <<
+ (i * 8))) >> (i * 8));
+
+ if (pwr_val[i] > RF6052_MAX_TX_PWR)
+ pwr_val[i] = RF6052_MAX_TX_PWR;
+ }
+ writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
+ (pwr_val[1] << 8) | pwr_val[0];
+
+ if (rf == 0)
+ regoffset = regoffset_a[index];
+ else
+ regoffset = regoffset_b[index];
+ rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Set 0x%x = %08x\n", regoffset, writeval);
+ }
+}
+
+void rtl88e_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *pwrlvlofdm,
+ u8 *pwrlvlbw20,
+ u8 *pwrlvlbw40, u8 chan)
+{
+ u32 writeval[2], base0[2], base1[2];
+ u8 index;
+ u8 direction;
+ u32 pwrtrac_value;
+
+ rtl88e_phy_get_power_base(hw, pwrlvlofdm, pwrlvlbw20,
+ pwrlvlbw40, chan, &base0[0],
+ &base1[0]);
+
+ rtl88e_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+
+ for (index = 0; index < 6; index++) {
+ get_txpwr_by_reg(hw, chan, index, &base0[0], &base1[0],
+ &writeval[0]);
+ if (direction == 1) {
+ writeval[0] += pwrtrac_value;
+ writeval[1] += pwrtrac_value;
+ } else if (direction == 2) {
+ writeval[0] -= pwrtrac_value;
+ writeval[1] -= pwrtrac_value;
+ }
+ write_ofdm_pwr(hw, index, &writeval[0]);
+ }
+}
+
+static bool rf6052_conf_para(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 u4val = 0;
+ u8 rfpath;
+ bool rtstatus = true;
+ struct bb_reg_def *pphyreg;
+
+ for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+ pphyreg = &rtlphy->phyreg_def[rfpath];
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ u4val = rtl_get_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ u4val = rtl_get_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV << 16);
+ break;
+ }
+
+ rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
+ B3WIREADDREAALENGTH, 0x0);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
+ udelay(1);
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtstatus = rtl88e_phy_config_rf_with_headerfile(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_B:
+ rtstatus = rtl88e_phy_config_rf_with_headerfile(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_C:
+ break;
+ case RF90_PATH_D:
+ break;
+ }
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV, u4val);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV << 16,
+ u4val);
+ break;
+ }
+
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Radio[%d] Fail!!", rfpath);
+ return false;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
+ return rtstatus;
+}
+
+bool rtl88e_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (rtlphy->rf_type == RF_1T1R)
+ rtlphy->num_total_rfpath = 1;
+ else
+ rtlphy->num_total_rfpath = 2;
+
+ return rf6052_conf_para(hw);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h
new file mode 100644
index 000000000000..a39a2a3dbcc9
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_RF_H__
+#define __RTL92C_RF_H__
+
+#define RF6052_MAX_TX_PWR 0x3F
+#define RF6052_MAX_REG 0x3F
+
+void rtl88e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+ u8 bandwidth);
+void rtl88e_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel);
+void rtl88e_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel_ofdm,
+ u8 *ppowerlevel_bw20,
+ u8 *ppowerlevel_bw40, u8 channel);
+bool rtl88e_phy_rf6052_config(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
new file mode 100644
index 000000000000..c254693a1e6a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
@@ -0,0 +1,400 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "hw.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+#include "table.h"
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static void rtl88e_init_aspm_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ /*close ASPM for AMD defaultly */
+ rtlpci->const_amdpci_aspm = 0;
+
+ /* ASPM PS mode.
+ * 0 - Disable ASPM,
+ * 1 - Enable ASPM without Clock Req,
+ * 2 - Enable ASPM with Clock Req,
+ * 3 - Alwyas Enable ASPM with Clock Req,
+ * 4 - Always Enable ASPM without Clock Req.
+ * set defult to RTL8192CE:3 RTL8192E:2
+ */
+ rtlpci->const_pci_aspm = 3;
+
+ /*Setting for PCI-E device */
+ rtlpci->const_devicepci_aspm_setting = 0x03;
+
+ /*Setting for PCI-E bridge */
+ rtlpci->const_hostpci_aspm_setting = 0x02;
+
+ /* In Hw/Sw Radio Off situation.
+ * 0 - Default,
+ * 1 - From ASPM setting without low Mac Pwr,
+ * 2 - From ASPM setting with low Mac Pwr,
+ * 3 - Bus D3
+ * set default to RTL8192CE:0 RTL8192SE:2
+ */
+ rtlpci->const_hwsw_rfoff_d3 = 0;
+
+ /* This setting works for those device with
+ * backdoor ASPM setting such as EPHY setting.
+ * 0 - Not support ASPM,
+ * 1 - Support ASPM,
+ * 2 - According to chipset.
+ */
+ rtlpci->const_support_pciaspm = 1;
+}
+
+int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
+{
+ int err = 0;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 tid;
+
+ rtl8188ee_bt_reg_init(hw);
+
+ rtlpriv->dm.dm_initialgain_enable = 1;
+ rtlpriv->dm.dm_flag = 0;
+ rtlpriv->dm.disable_framebursting = 0;
+ rtlpriv->dm.thermalvalue = 0;
+ rtlpci->transmit_config = CFENDFORM | BIT(15);
+
+ /* compatible 5G band 88ce just 2.4G band & smsp */
+ rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+ rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+ rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+ rtlpci->receive_config = (RCR_APPFCS |
+ RCR_APP_MIC |
+ RCR_APP_ICV |
+ RCR_APP_PHYST_RXFF |
+ RCR_HTC_LOC_CTRL |
+ RCR_AMF |
+ RCR_ACF |
+ RCR_ADF |
+ RCR_AICV |
+ RCR_ACRC32 |
+ RCR_AB |
+ RCR_AM |
+ RCR_APM |
+ 0);
+
+ rtlpci->irq_mask[0] =
+ (u32) (IMR_PSTIMEOUT |
+ IMR_HSISR_IND_ON_INT |
+ IMR_C2HCMD |
+ IMR_HIGHDOK |
+ IMR_MGNTDOK |
+ IMR_BKDOK |
+ IMR_BEDOK |
+ IMR_VIDOK |
+ IMR_VODOK |
+ IMR_RDU |
+ IMR_ROK |
+ 0);
+ rtlpci->irq_mask[1] = (u32) (IMR_RXFOVW | 0);
+ rtlpci->sys_irq_mask = (u32) (HSIMR_PDN_INT_EN | HSIMR_RON_INT_EN);
+
+ /* for debug level */
+ rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
+ /* for LPS & IPS */
+ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+ rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+ rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ if (!rtlpriv->psc.inactiveps)
+ pr_info("rtl8188ee: Power Save off (module option)\n");
+ if (!rtlpriv->psc.fwctrl_lps)
+ pr_info("rtl8188ee: FW Power Save off (module option)\n");
+ rtlpriv->psc.reg_fwctrl_lps = 3;
+ rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+ /* for ASPM, you can close aspm through
+ * set const_support_pciaspm = 0
+ */
+ rtl88e_init_aspm_vars(hw);
+
+ if (rtlpriv->psc.reg_fwctrl_lps == 1)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+ /* for firmware buf */
+ rtlpriv->rtlhal.pfirmware = vmalloc(0x8000);
+ if (!rtlpriv->rtlhal.pfirmware) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Can't alloc buffer for fw.\n");
+ return 1;
+ }
+
+ rtlpriv->cfg->fw_name = "rtlwifi/rtl8188efw.bin";
+ rtlpriv->max_fw_size = 0x8000;
+ pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
+ err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+ rtlpriv->io.dev, GFP_KERNEL, hw,
+ rtl_fw_cb);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Failed to request firmware!\n");
+ return 1;
+ }
+
+ /* for early mode */
+ rtlpriv->rtlhal.earlymode_enable = false;
+ rtlpriv->rtlhal.max_earlymode_num = 10;
+ for (tid = 0; tid < 8; tid++)
+ skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]);
+
+ /*low power */
+ rtlpriv->psc.low_power_enable = false;
+ if (rtlpriv->psc.low_power_enable) {
+ init_timer(&rtlpriv->works.fw_clockoff_timer);
+ setup_timer(&rtlpriv->works.fw_clockoff_timer,
+ rtl88ee_fw_clk_off_timer_callback,
+ (unsigned long)hw);
+ }
+
+ init_timer(&rtlpriv->works.fast_antenna_training_timer);
+ setup_timer(&rtlpriv->works.fast_antenna_training_timer,
+ rtl88e_dm_fast_antenna_training_callback,
+ (unsigned long)hw);
+ return err;
+}
+
+void rtl88e_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->rtlhal.pfirmware) {
+ vfree(rtlpriv->rtlhal.pfirmware);
+ rtlpriv->rtlhal.pfirmware = NULL;
+ }
+
+ if (rtlpriv->psc.low_power_enable)
+ del_timer_sync(&rtlpriv->works.fw_clockoff_timer);
+
+ del_timer_sync(&rtlpriv->works.fast_antenna_training_timer);
+}
+
+static struct rtl_hal_ops rtl8188ee_hal_ops = {
+ .init_sw_vars = rtl88e_init_sw_vars,
+ .deinit_sw_vars = rtl88e_deinit_sw_vars,
+ .read_eeprom_info = rtl88ee_read_eeprom_info,
+ .interrupt_recognized = rtl88ee_interrupt_recognized,/*need check*/
+ .hw_init = rtl88ee_hw_init,
+ .hw_disable = rtl88ee_card_disable,
+ .hw_suspend = rtl88ee_suspend,
+ .hw_resume = rtl88ee_resume,
+ .enable_interrupt = rtl88ee_enable_interrupt,
+ .disable_interrupt = rtl88ee_disable_interrupt,
+ .set_network_type = rtl88ee_set_network_type,
+ .set_chk_bssid = rtl88ee_set_check_bssid,
+ .set_qos = rtl88ee_set_qos,
+ .set_bcn_reg = rtl88ee_set_beacon_related_registers,
+ .set_bcn_intv = rtl88ee_set_beacon_interval,
+ .update_interrupt_mask = rtl88ee_update_interrupt_mask,
+ .get_hw_reg = rtl88ee_get_hw_reg,
+ .set_hw_reg = rtl88ee_set_hw_reg,
+ .update_rate_tbl = rtl88ee_update_hal_rate_tbl,
+ .fill_tx_desc = rtl88ee_tx_fill_desc,
+ .fill_tx_cmddesc = rtl88ee_tx_fill_cmddesc,
+ .query_rx_desc = rtl88ee_rx_query_desc,
+ .set_channel_access = rtl88ee_update_channel_access_setting,
+ .radio_onoff_checking = rtl88ee_gpio_radio_on_off_checking,
+ .set_bw_mode = rtl88e_phy_set_bw_mode,
+ .switch_channel = rtl88e_phy_sw_chnl,
+ .dm_watchdog = rtl88e_dm_watchdog,
+ .scan_operation_backup = rtl88e_phy_scan_operation_backup,
+ .set_rf_power_state = rtl88e_phy_set_rf_power_state,
+ .led_control = rtl88ee_led_control,
+ .set_desc = rtl88ee_set_desc,
+ .get_desc = rtl88ee_get_desc,
+ .tx_polling = rtl88ee_tx_polling,
+ .enable_hw_sec = rtl88ee_enable_hw_security_config,
+ .set_key = rtl88ee_set_key,
+ .init_sw_leds = rtl88ee_init_sw_leds,
+ .allow_all_destaddr = rtl88ee_allow_all_destaddr,
+ .get_bbreg = rtl88e_phy_query_bb_reg,
+ .set_bbreg = rtl88e_phy_set_bb_reg,
+ .get_rfreg = rtl88e_phy_query_rf_reg,
+ .set_rfreg = rtl88e_phy_set_rf_reg,
+};
+
+static struct rtl_mod_params rtl88ee_mod_params = {
+ .sw_crypto = false,
+ .inactiveps = true,
+ .swctrl_lps = false,
+ .fwctrl_lps = true,
+ .debug = DBG_EMERG,
+};
+
+static struct rtl_hal_cfg rtl88ee_hal_cfg = {
+ .bar_id = 2,
+ .write_readback = true,
+ .name = "rtl88e_pci",
+ .ops = &rtl8188ee_hal_ops,
+ .mod_params = &rtl88ee_mod_params,
+
+ .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+ .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+ .maps[SYS_CLK] = REG_SYS_CLKR,
+ .maps[MAC_RCR_AM] = AM,
+ .maps[MAC_RCR_AB] = AB,
+ .maps[MAC_RCR_ACRC32] = ACRC32,
+ .maps[MAC_RCR_ACF] = ACF,
+ .maps[MAC_RCR_AAP] = AAP,
+
+ .maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS,
+
+ .maps[EFUSE_TEST] = REG_EFUSE_TEST,
+ .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_CLK] = 0,
+ .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_PWC_EV12V] = PWC_EV12V,
+ .maps[EFUSE_FEN_ELDR] = FEN_ELDR,
+ .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
+ .maps[EFUSE_ANA8M] = ANA8M,
+ .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+ .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+ .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+ .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
+
+ .maps[RWCAM] = REG_CAMCMD,
+ .maps[WCAMI] = REG_CAMWRITE,
+ .maps[RCAMO] = REG_CAMREAD,
+ .maps[CAMDBG] = REG_CAMDBG,
+ .maps[SECR] = REG_SECCFG,
+ .maps[SEC_CAM_NONE] = CAM_NONE,
+ .maps[SEC_CAM_WEP40] = CAM_WEP40,
+ .maps[SEC_CAM_TKIP] = CAM_TKIP,
+ .maps[SEC_CAM_AES] = CAM_AES,
+ .maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+ .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+ .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+ .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+ .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+ .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+ .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+/* .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, */ /*need check*/
+ .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+ .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+ .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+ .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+ .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+ .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+ .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+/* .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,*/
+/* .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,*/
+
+ .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+ .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNDMAINT0,
+ .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+ .maps[RTL_IMR_RDU] = IMR_RDU,
+ .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+ .maps[RTL_IMR_BDOK] = IMR_BCNDOK0,
+ .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+ .maps[RTL_IMR_TBDER] = IMR_TBDER,
+ .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+ .maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+ .maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+ .maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+ .maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+ .maps[RTL_IMR_VODOK] = IMR_VODOK,
+ .maps[RTL_IMR_ROK] = IMR_ROK,
+ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER),
+
+ .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(rtl88ee_pci_ids) = {
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8179, rtl88ee_hal_cfg)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl88ee_pci_ids);
+
+MODULE_AUTHOR("zhiyuan_yang <zhiyuan_yang@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8188E 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8188efw.bin");
+
+module_param_named(swenc, rtl88ee_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl88ee_mod_params.debug, int, 0444);
+module_param_named(ips, rtl88ee_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl88ee_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl88ee_mod_params.fwctrl_lps, bool, 0444);
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+
+static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
+
+static struct pci_driver rtl88ee_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rtl88ee_pci_ids,
+ .probe = rtl_pci_probe,
+ .remove = rtl_pci_disconnect,
+ .driver.pm = &rtlwifi_pm_ops,
+};
+
+module_pci_driver(rtl88ee_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h
new file mode 100644
index 000000000000..85e02b3bdff8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_SW_H__
+#define __RTL92CE_SW_H__
+
+int rtl88e_init_sw_vars(struct ieee80211_hw *hw);
+void rtl88e_deinit_sw_vars(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/table.c b/drivers/net/wireless/rtlwifi/rtl8188ee/table.c
new file mode 100644
index 000000000000..fad373f97b2c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/table.c
@@ -0,0 +1,643 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on 2010/ 5/18, 1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "table.h"
+
+u32 RTL8188EEPHY_REG_1TARRAY[] = {
+ 0x800, 0x80040000,
+ 0x804, 0x00000003,
+ 0x808, 0x0000FC00,
+ 0x80C, 0x0000000A,
+ 0x810, 0x10001331,
+ 0x814, 0x020C3D10,
+ 0x818, 0x02200385,
+ 0x81C, 0x00000000,
+ 0x820, 0x01000100,
+ 0x824, 0x00390204,
+ 0x828, 0x00000000,
+ 0x82C, 0x00000000,
+ 0x830, 0x00000000,
+ 0x834, 0x00000000,
+ 0x838, 0x00000000,
+ 0x83C, 0x00000000,
+ 0x840, 0x00010000,
+ 0x844, 0x00000000,
+ 0x848, 0x00000000,
+ 0x84C, 0x00000000,
+ 0x850, 0x00000000,
+ 0x854, 0x00000000,
+ 0x858, 0x569A11A9,
+ 0x85C, 0x01000014,
+ 0x860, 0x66F60110,
+ 0x864, 0x061F0649,
+ 0x868, 0x00000000,
+ 0x86C, 0x27272700,
+ 0x870, 0x07000760,
+ 0x874, 0x25004000,
+ 0x878, 0x00000808,
+ 0x87C, 0x00000000,
+ 0x880, 0xB0000C1C,
+ 0x884, 0x00000001,
+ 0x888, 0x00000000,
+ 0x88C, 0xCCC000C0,
+ 0x890, 0x00000800,
+ 0x894, 0xFFFFFFFE,
+ 0x898, 0x40302010,
+ 0x89C, 0x00706050,
+ 0x900, 0x00000000,
+ 0x904, 0x00000023,
+ 0x908, 0x00000000,
+ 0x90C, 0x81121111,
+ 0x910, 0x00000002,
+ 0x914, 0x00000201,
+ 0xA00, 0x00D047C8,
+ 0xA04, 0x80FF000C,
+ 0xA08, 0x8C838300,
+ 0xA0C, 0x2E7F120F,
+ 0xA10, 0x9500BB78,
+ 0xA14, 0x1114D028,
+ 0xA18, 0x00881117,
+ 0xA1C, 0x89140F00,
+ 0xA20, 0x1A1B0000,
+ 0xA24, 0x090E1317,
+ 0xA28, 0x00000204,
+ 0xA2C, 0x00D30000,
+ 0xA70, 0x101FBF00,
+ 0xA74, 0x00000007,
+ 0xA78, 0x00000900,
+ 0xA7C, 0x225B0606,
+ 0xA80, 0x218075B1,
+ 0xB2C, 0x80000000,
+ 0xC00, 0x48071D40,
+ 0xC04, 0x03A05611,
+ 0xC08, 0x000000E4,
+ 0xC0C, 0x6C6C6C6C,
+ 0xC10, 0x08800000,
+ 0xC14, 0x40000100,
+ 0xC18, 0x08800000,
+ 0xC1C, 0x40000100,
+ 0xC20, 0x00000000,
+ 0xC24, 0x00000000,
+ 0xC28, 0x00000000,
+ 0xC2C, 0x00000000,
+ 0xC30, 0x69E9AC47,
+ 0xC34, 0x469652AF,
+ 0xC38, 0x49795994,
+ 0xC3C, 0x0A97971C,
+ 0xC40, 0x1F7C403F,
+ 0xC44, 0x000100B7,
+ 0xC48, 0xEC020107,
+ 0xC4C, 0x007F037F,
+ 0xC50, 0x69553420,
+ 0xC54, 0x43BC0094,
+ 0xC58, 0x00013169,
+ 0xC5C, 0x00250492,
+ 0xC60, 0x00000000,
+ 0xC64, 0x7112848B,
+ 0xC68, 0x47C00BFF,
+ 0xC6C, 0x00000036,
+ 0xC70, 0x2C7F000D,
+ 0xC74, 0x020610DB,
+ 0xC78, 0x0000001F,
+ 0xC7C, 0x00B91612,
+ 0xC80, 0x390000E4,
+ 0xC84, 0x20F60000,
+ 0xC88, 0x40000100,
+ 0xC8C, 0x20200000,
+ 0xC90, 0x00091521,
+ 0xC94, 0x00000000,
+ 0xC98, 0x00121820,
+ 0xC9C, 0x00007F7F,
+ 0xCA0, 0x00000000,
+ 0xCA4, 0x000300A0,
+ 0xCA8, 0x00000000,
+ 0xCAC, 0x00000000,
+ 0xCB0, 0x00000000,
+ 0xCB4, 0x00000000,
+ 0xCB8, 0x00000000,
+ 0xCBC, 0x28000000,
+ 0xCC0, 0x00000000,
+ 0xCC4, 0x00000000,
+ 0xCC8, 0x00000000,
+ 0xCCC, 0x00000000,
+ 0xCD0, 0x00000000,
+ 0xCD4, 0x00000000,
+ 0xCD8, 0x64B22427,
+ 0xCDC, 0x00766932,
+ 0xCE0, 0x00222222,
+ 0xCE4, 0x00000000,
+ 0xCE8, 0x37644302,
+ 0xCEC, 0x2F97D40C,
+ 0xD00, 0x00000740,
+ 0xD04, 0x00020401,
+ 0xD08, 0x0000907F,
+ 0xD0C, 0x20010201,
+ 0xD10, 0xA0633333,
+ 0xD14, 0x3333BC43,
+ 0xD18, 0x7A8F5B6F,
+ 0xD2C, 0xCC979975,
+ 0xD30, 0x00000000,
+ 0xD34, 0x80608000,
+ 0xD38, 0x00000000,
+ 0xD3C, 0x00127353,
+ 0xD40, 0x00000000,
+ 0xD44, 0x00000000,
+ 0xD48, 0x00000000,
+ 0xD4C, 0x00000000,
+ 0xD50, 0x6437140A,
+ 0xD54, 0x00000000,
+ 0xD58, 0x00000282,
+ 0xD5C, 0x30032064,
+ 0xD60, 0x4653DE68,
+ 0xD64, 0x04518A3C,
+ 0xD68, 0x00002101,
+ 0xD6C, 0x2A201C16,
+ 0xD70, 0x1812362E,
+ 0xD74, 0x322C2220,
+ 0xD78, 0x000E3C24,
+ 0xE00, 0x2D2D2D2D,
+ 0xE04, 0x2D2D2D2D,
+ 0xE08, 0x0390272D,
+ 0xE10, 0x2D2D2D2D,
+ 0xE14, 0x2D2D2D2D,
+ 0xE18, 0x2D2D2D2D,
+ 0xE1C, 0x2D2D2D2D,
+ 0xE28, 0x00000000,
+ 0xE30, 0x1000DC1F,
+ 0xE34, 0x10008C1F,
+ 0xE38, 0x02140102,
+ 0xE3C, 0x681604C2,
+ 0xE40, 0x01007C00,
+ 0xE44, 0x01004800,
+ 0xE48, 0xFB000000,
+ 0xE4C, 0x000028D1,
+ 0xE50, 0x1000DC1F,
+ 0xE54, 0x10008C1F,
+ 0xE58, 0x02140102,
+ 0xE5C, 0x28160D05,
+ 0xE60, 0x00000008,
+ 0xE68, 0x001B25A4,
+ 0xE6C, 0x00C00014,
+ 0xE70, 0x00C00014,
+ 0xE74, 0x01000014,
+ 0xE78, 0x01000014,
+ 0xE7C, 0x01000014,
+ 0xE80, 0x01000014,
+ 0xE84, 0x00C00014,
+ 0xE88, 0x01000014,
+ 0xE8C, 0x00C00014,
+ 0xED0, 0x00C00014,
+ 0xED4, 0x00C00014,
+ 0xED8, 0x00C00014,
+ 0xEDC, 0x00000014,
+ 0xEE0, 0x00000014,
+ 0xEEC, 0x01C00014,
+ 0xF14, 0x00000003,
+ 0xF4C, 0x00000000,
+ 0xF00, 0x00000300,
+
+};
+
+u32 RTL8188EEPHY_REG_ARRAY_PG[] = {
+ 0xE00, 0xFFFFFFFF, 0x06070809,
+ 0xE04, 0xFFFFFFFF, 0x02020405,
+ 0xE08, 0x0000FF00, 0x00000006,
+ 0x86C, 0xFFFFFF00, 0x00020400,
+ 0xE10, 0xFFFFFFFF, 0x08090A0B,
+ 0xE14, 0xFFFFFFFF, 0x01030607,
+ 0xE18, 0xFFFFFFFF, 0x08090A0B,
+ 0xE1C, 0xFFFFFFFF, 0x01030607,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+
+};
+
+u32 RTL8188EE_RADIOA_1TARRAY[] = {
+ 0x000, 0x00030000,
+ 0x008, 0x00084000,
+ 0x018, 0x00000407,
+ 0x019, 0x00000012,
+ 0x01E, 0x00080009,
+ 0x01F, 0x00000880,
+ 0x02F, 0x0001A060,
+ 0x03F, 0x00000000,
+ 0x042, 0x000060C0,
+ 0x057, 0x000D0000,
+ 0x058, 0x000BE180,
+ 0x067, 0x00001552,
+ 0x083, 0x00000000,
+ 0x0B0, 0x000FF8FC,
+ 0x0B1, 0x00054400,
+ 0x0B2, 0x000CCC19,
+ 0x0B4, 0x00043003,
+ 0x0B6, 0x0004953E,
+ 0x0B7, 0x0001C718,
+ 0x0B8, 0x000060FF,
+ 0x0B9, 0x00080001,
+ 0x0BA, 0x00040000,
+ 0x0BB, 0x00000400,
+ 0x0BF, 0x000C0000,
+ 0x0C2, 0x00002400,
+ 0x0C3, 0x00000009,
+ 0x0C4, 0x00040C91,
+ 0x0C5, 0x00099999,
+ 0x0C6, 0x000000A3,
+ 0x0C7, 0x00088820,
+ 0x0C8, 0x00076C06,
+ 0x0C9, 0x00000000,
+ 0x0CA, 0x00080000,
+ 0x0DF, 0x00000180,
+ 0x0EF, 0x000001A0,
+ 0x051, 0x0006B27D,
+ 0x052, 0x0007E49D,
+ 0x053, 0x00000073,
+ 0x056, 0x00051FF3,
+ 0x035, 0x00000086,
+ 0x035, 0x00000186,
+ 0x035, 0x00000286,
+ 0x036, 0x00001C25,
+ 0x036, 0x00009C25,
+ 0x036, 0x00011C25,
+ 0x036, 0x00019C25,
+ 0x0B6, 0x00048538,
+ 0x018, 0x00000C07,
+ 0x05A, 0x0004BD00,
+ 0x019, 0x000739D0,
+ 0x034, 0x0000ADF3,
+ 0x034, 0x00009DF0,
+ 0x034, 0x00008DED,
+ 0x034, 0x00007DEA,
+ 0x034, 0x00006DE7,
+ 0x034, 0x000054EE,
+ 0x034, 0x000044EB,
+ 0x034, 0x000034E8,
+ 0x034, 0x0000246B,
+ 0x034, 0x00001468,
+ 0x034, 0x0000006D,
+ 0x000, 0x00030159,
+ 0x084, 0x00068200,
+ 0x086, 0x000000CE,
+ 0x087, 0x00048A00,
+ 0x08E, 0x00065540,
+ 0x08F, 0x00088000,
+ 0x0EF, 0x000020A0,
+ 0x03B, 0x000F02B0,
+ 0x03B, 0x000EF7B0,
+ 0x03B, 0x000D4FB0,
+ 0x03B, 0x000CF060,
+ 0x03B, 0x000B0090,
+ 0x03B, 0x000A0080,
+ 0x03B, 0x00090080,
+ 0x03B, 0x0008F780,
+ 0x03B, 0x000722B0,
+ 0x03B, 0x0006F7B0,
+ 0x03B, 0x00054FB0,
+ 0x03B, 0x0004F060,
+ 0x03B, 0x00030090,
+ 0x03B, 0x00020080,
+ 0x03B, 0x00010080,
+ 0x03B, 0x0000F780,
+ 0x0EF, 0x000000A0,
+ 0x000, 0x00010159,
+ 0x018, 0x0000F407,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0x01F, 0x00080003,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0x01E, 0x00000001,
+ 0x01F, 0x00080000,
+ 0x000, 0x00033E60,
+
+};
+
+u32 RTL8188EEMAC_1T_ARRAY[] = {
+ 0x026, 0x00000041,
+ 0x027, 0x00000035,
+ 0x428, 0x0000000A,
+ 0x429, 0x00000010,
+ 0x430, 0x00000000,
+ 0x431, 0x00000001,
+ 0x432, 0x00000002,
+ 0x433, 0x00000004,
+ 0x434, 0x00000005,
+ 0x435, 0x00000006,
+ 0x436, 0x00000007,
+ 0x437, 0x00000008,
+ 0x438, 0x00000000,
+ 0x439, 0x00000000,
+ 0x43A, 0x00000001,
+ 0x43B, 0x00000002,
+ 0x43C, 0x00000004,
+ 0x43D, 0x00000005,
+ 0x43E, 0x00000006,
+ 0x43F, 0x00000007,
+ 0x440, 0x0000005D,
+ 0x441, 0x00000001,
+ 0x442, 0x00000000,
+ 0x444, 0x00000015,
+ 0x445, 0x000000F0,
+ 0x446, 0x0000000F,
+ 0x447, 0x00000000,
+ 0x458, 0x00000041,
+ 0x459, 0x000000A8,
+ 0x45A, 0x00000072,
+ 0x45B, 0x000000B9,
+ 0x460, 0x00000066,
+ 0x461, 0x00000066,
+ 0x480, 0x00000008,
+ 0x4C8, 0x000000FF,
+ 0x4C9, 0x00000008,
+ 0x4CC, 0x000000FF,
+ 0x4CD, 0x000000FF,
+ 0x4CE, 0x00000001,
+ 0x4D3, 0x00000001,
+ 0x500, 0x00000026,
+ 0x501, 0x000000A2,
+ 0x502, 0x0000002F,
+ 0x503, 0x00000000,
+ 0x504, 0x00000028,
+ 0x505, 0x000000A3,
+ 0x506, 0x0000005E,
+ 0x507, 0x00000000,
+ 0x508, 0x0000002B,
+ 0x509, 0x000000A4,
+ 0x50A, 0x0000005E,
+ 0x50B, 0x00000000,
+ 0x50C, 0x0000004F,
+ 0x50D, 0x000000A4,
+ 0x50E, 0x00000000,
+ 0x50F, 0x00000000,
+ 0x512, 0x0000001C,
+ 0x514, 0x0000000A,
+ 0x516, 0x0000000A,
+ 0x525, 0x0000004F,
+ 0x550, 0x00000010,
+ 0x551, 0x00000010,
+ 0x559, 0x00000002,
+ 0x55D, 0x000000FF,
+ 0x605, 0x00000030,
+ 0x608, 0x0000000E,
+ 0x609, 0x0000002A,
+ 0x620, 0x000000FF,
+ 0x621, 0x000000FF,
+ 0x622, 0x000000FF,
+ 0x623, 0x000000FF,
+ 0x624, 0x000000FF,
+ 0x625, 0x000000FF,
+ 0x626, 0x000000FF,
+ 0x627, 0x000000FF,
+ 0x652, 0x00000020,
+ 0x63C, 0x0000000A,
+ 0x63D, 0x0000000A,
+ 0x63E, 0x0000000E,
+ 0x63F, 0x0000000E,
+ 0x640, 0x00000040,
+ 0x66E, 0x00000005,
+ 0x700, 0x00000021,
+ 0x701, 0x00000043,
+ 0x702, 0x00000065,
+ 0x703, 0x00000087,
+ 0x708, 0x00000021,
+ 0x709, 0x00000043,
+ 0x70A, 0x00000065,
+ 0x70B, 0x00000087,
+
+};
+
+u32 RTL8188EEAGCTAB_1TARRAY[] = {
+ 0xC78, 0xFB000001,
+ 0xC78, 0xFB010001,
+ 0xC78, 0xFB020001,
+ 0xC78, 0xFB030001,
+ 0xC78, 0xFB040001,
+ 0xC78, 0xFB050001,
+ 0xC78, 0xFA060001,
+ 0xC78, 0xF9070001,
+ 0xC78, 0xF8080001,
+ 0xC78, 0xF7090001,
+ 0xC78, 0xF60A0001,
+ 0xC78, 0xF50B0001,
+ 0xC78, 0xF40C0001,
+ 0xC78, 0xF30D0001,
+ 0xC78, 0xF20E0001,
+ 0xC78, 0xF10F0001,
+ 0xC78, 0xF0100001,
+ 0xC78, 0xEF110001,
+ 0xC78, 0xEE120001,
+ 0xC78, 0xED130001,
+ 0xC78, 0xEC140001,
+ 0xC78, 0xEB150001,
+ 0xC78, 0xEA160001,
+ 0xC78, 0xE9170001,
+ 0xC78, 0xE8180001,
+ 0xC78, 0xE7190001,
+ 0xC78, 0xE61A0001,
+ 0xC78, 0xE51B0001,
+ 0xC78, 0xE41C0001,
+ 0xC78, 0xE31D0001,
+ 0xC78, 0xE21E0001,
+ 0xC78, 0xE11F0001,
+ 0xC78, 0x8A200001,
+ 0xC78, 0x89210001,
+ 0xC78, 0x88220001,
+ 0xC78, 0x87230001,
+ 0xC78, 0x86240001,
+ 0xC78, 0x85250001,
+ 0xC78, 0x84260001,
+ 0xC78, 0x83270001,
+ 0xC78, 0x82280001,
+ 0xC78, 0x6B290001,
+ 0xC78, 0x6A2A0001,
+ 0xC78, 0x692B0001,
+ 0xC78, 0x682C0001,
+ 0xC78, 0x672D0001,
+ 0xC78, 0x662E0001,
+ 0xC78, 0x652F0001,
+ 0xC78, 0x64300001,
+ 0xC78, 0x63310001,
+ 0xC78, 0x62320001,
+ 0xC78, 0x61330001,
+ 0xC78, 0x46340001,
+ 0xC78, 0x45350001,
+ 0xC78, 0x44360001,
+ 0xC78, 0x43370001,
+ 0xC78, 0x42380001,
+ 0xC78, 0x41390001,
+ 0xC78, 0x403A0001,
+ 0xC78, 0x403B0001,
+ 0xC78, 0x403C0001,
+ 0xC78, 0x403D0001,
+ 0xC78, 0x403E0001,
+ 0xC78, 0x403F0001,
+ 0xC78, 0xFB400001,
+ 0xC78, 0xFB410001,
+ 0xC78, 0xFB420001,
+ 0xC78, 0xFB430001,
+ 0xC78, 0xFB440001,
+ 0xC78, 0xFB450001,
+ 0xC78, 0xFB460001,
+ 0xC78, 0xFB470001,
+ 0xC78, 0xFB480001,
+ 0xC78, 0xFA490001,
+ 0xC78, 0xF94A0001,
+ 0xC78, 0xF84B0001,
+ 0xC78, 0xF74C0001,
+ 0xC78, 0xF64D0001,
+ 0xC78, 0xF54E0001,
+ 0xC78, 0xF44F0001,
+ 0xC78, 0xF3500001,
+ 0xC78, 0xF2510001,
+ 0xC78, 0xF1520001,
+ 0xC78, 0xF0530001,
+ 0xC78, 0xEF540001,
+ 0xC78, 0xEE550001,
+ 0xC78, 0xED560001,
+ 0xC78, 0xEC570001,
+ 0xC78, 0xEB580001,
+ 0xC78, 0xEA590001,
+ 0xC78, 0xE95A0001,
+ 0xC78, 0xE85B0001,
+ 0xC78, 0xE75C0001,
+ 0xC78, 0xE65D0001,
+ 0xC78, 0xE55E0001,
+ 0xC78, 0xE45F0001,
+ 0xC78, 0xE3600001,
+ 0xC78, 0xE2610001,
+ 0xC78, 0xC3620001,
+ 0xC78, 0xC2630001,
+ 0xC78, 0xC1640001,
+ 0xC78, 0x8B650001,
+ 0xC78, 0x8A660001,
+ 0xC78, 0x89670001,
+ 0xC78, 0x88680001,
+ 0xC78, 0x87690001,
+ 0xC78, 0x866A0001,
+ 0xC78, 0x856B0001,
+ 0xC78, 0x846C0001,
+ 0xC78, 0x676D0001,
+ 0xC78, 0x666E0001,
+ 0xC78, 0x656F0001,
+ 0xC78, 0x64700001,
+ 0xC78, 0x63710001,
+ 0xC78, 0x62720001,
+ 0xC78, 0x61730001,
+ 0xC78, 0x60740001,
+ 0xC78, 0x46750001,
+ 0xC78, 0x45760001,
+ 0xC78, 0x44770001,
+ 0xC78, 0x43780001,
+ 0xC78, 0x42790001,
+ 0xC78, 0x417A0001,
+ 0xC78, 0x407B0001,
+ 0xC78, 0x407C0001,
+ 0xC78, 0x407D0001,
+ 0xC78, 0x407E0001,
+ 0xC78, 0x407F0001,
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/table.h b/drivers/net/wireless/rtlwifi/rtl8188ee/table.h
new file mode 100644
index 000000000000..c1218e835129
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/table.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on 2010/ 5/18, 1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_TABLE__H_
+#define __RTL92CE_TABLE__H_
+
+#include <linux/types.h>
+#define RTL8188EEPHY_REG_1TARRAYLEN 382
+extern u32 RTL8188EEPHY_REG_1TARRAY[];
+#define RTL8188EEPHY_REG_ARRAY_PGLEN 264
+extern u32 RTL8188EEPHY_REG_ARRAY_PG[];
+#define RTL8188EE_RADIOA_1TARRAYLEN 190
+extern u32 RTL8188EE_RADIOA_1TARRAY[];
+#define RTL8188EEMAC_1T_ARRAYLEN 180
+extern u32 RTL8188EEMAC_1T_ARRAY[];
+#define RTL8188EEAGCTAB_1TARRAYLEN 256
+extern u32 RTL8188EEAGCTAB_1TARRAY[];
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
new file mode 100644
index 000000000000..d075237add51
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
@@ -0,0 +1,817 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../stats.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "trx.h"
+#include "led.h"
+#include "dm.h"
+
+static u8 _rtl88ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+{
+ __le16 fc = rtl_get_fc(skb);
+
+ if (unlikely(ieee80211_is_beacon(fc)))
+ return QSLT_BEACON;
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
+ return QSLT_MGNT;
+
+ return skb->priority;
+}
+
+static void _rtl88ee_query_rxphystatus(struct ieee80211_hw *hw,
+ struct rtl_stats *pstatus, u8 *pdesc,
+ struct rx_fwinfo_88e *p_drvinfo,
+ bool bpacket_match_bssid,
+ bool bpacket_toself, bool packet_beacon)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
+ struct phy_sts_cck_8192s_t *cck_buf;
+ struct phy_status_rpt *phystrpt = (struct phy_status_rpt *)p_drvinfo;
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ char rx_pwr_all = 0, rx_pwr[4];
+ u8 rf_rx_num = 0, evm, pwdb_all;
+ u8 i, max_spatial_stream;
+ u32 rssi, total_rssi = 0;
+ bool is_cck = pstatus->is_cck;
+ u8 lan_idx, vga_idx;
+
+ /* Record it for next packet processing */
+ pstatus->packet_matchbssid = bpacket_match_bssid;
+ pstatus->packet_toself = bpacket_toself;
+ pstatus->packet_beacon = packet_beacon;
+ pstatus->rx_mimo_sig_qual[0] = -1;
+ pstatus->rx_mimo_sig_qual[1] = -1;
+
+ if (is_cck) {
+ u8 cck_hipwr;
+ u8 cck_agc_rpt;
+ /* CCK Driver info Structure is not the same as OFDM packet. */
+ cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
+ cck_agc_rpt = cck_buf->cck_agc_rpt;
+
+ /* (1)Hardware does not provide RSSI for CCK
+ * (2)PWDB, Average PWDB cacluated by
+ * hardware (for rate adaptive)
+ */
+ if (ppsc->rfpwr_state == ERFON)
+ cck_hipwr = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2,
+ BIT(9));
+ else
+ cck_hipwr = false;
+
+ lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
+ vga_idx = (cck_agc_rpt & 0x1f);
+ switch (lan_idx) {
+ case 7:
+ if (vga_idx <= 27)
+ rx_pwr_all = -100 + 2 * (27 - vga_idx);
+ else
+ rx_pwr_all = -100;
+ break;
+ case 6:
+ rx_pwr_all = -48 + 2 * (2 - vga_idx); /*VGA_idx = 2~0*/
+ break;
+ case 5:
+ rx_pwr_all = -42 + 2 * (7 - vga_idx); /*VGA_idx = 7~5*/
+ break;
+ case 4:
+ rx_pwr_all = -36 + 2 * (7 - vga_idx); /*VGA_idx = 7~4*/
+ break;
+ case 3:
+ rx_pwr_all = -24 + 2 * (7 - vga_idx); /*VGA_idx = 7~0*/
+ break;
+ case 2:
+ if (cck_hipwr)
+ rx_pwr_all = -12 + 2 * (5 - vga_idx);
+ else
+ rx_pwr_all = -6 + 2 * (5 - vga_idx);
+ break;
+ case 1:
+ rx_pwr_all = 8 - 2 * vga_idx;
+ break;
+ case 0:
+ rx_pwr_all = 14 - 2 * vga_idx;
+ break;
+ default:
+ break;
+ }
+ rx_pwr_all += 6;
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+ /* CCK gain is smaller than OFDM/MCS gain,
+ * so we add gain diff by experiences,
+ * the val is 6
+ */
+ pwdb_all += 6;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ /* modify the offset to make the same
+ * gain index with OFDM.
+ */
+ if (pwdb_all > 34 && pwdb_all <= 42)
+ pwdb_all -= 2;
+ else if (pwdb_all > 26 && pwdb_all <= 34)
+ pwdb_all -= 6;
+ else if (pwdb_all > 14 && pwdb_all <= 26)
+ pwdb_all -= 8;
+ else if (pwdb_all > 4 && pwdb_all <= 14)
+ pwdb_all -= 4;
+ if (cck_hipwr == false) {
+ if (pwdb_all >= 80)
+ pwdb_all = ((pwdb_all - 80)<<1) +
+ ((pwdb_all - 80)>>1) + 80;
+ else if ((pwdb_all <= 78) && (pwdb_all >= 20))
+ pwdb_all += 3;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ }
+
+ pstatus->rx_pwdb_all = pwdb_all;
+ pstatus->recvsignalpower = rx_pwr_all;
+
+ /* (3) Get Signal Quality (EVM) */
+ if (bpacket_match_bssid) {
+ u8 sq;
+
+ if (pstatus->rx_pwdb_all > 40) {
+ sq = 100;
+ } else {
+ sq = cck_buf->sq_rpt;
+ if (sq > 64)
+ sq = 0;
+ else if (sq < 20)
+ sq = 100;
+ else
+ sq = ((64 - sq) * 100) / 44;
+ }
+
+ pstatus->signalquality = sq;
+ pstatus->rx_mimo_sig_qual[0] = sq;
+ pstatus->rx_mimo_sig_qual[1] = -1;
+ }
+ } else {
+ rtlpriv->dm.rfpath_rxenable[0] =
+ rtlpriv->dm.rfpath_rxenable[1] = true;
+
+ /* (1)Get RSSI for HT rate */
+ for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
+ /* we will judge RF RX path now. */
+ if (rtlpriv->dm.rfpath_rxenable[i])
+ rf_rx_num++;
+
+ rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f) * 2)-110;
+
+ /* Translate DBM to percentage. */
+ rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
+ total_rssi += rssi;
+
+ /* Get Rx snr value in DB */
+ rtlpriv->stats.rx_snr_db[i] = p_drvinfo->rxsnr[i] / 2;
+
+ /* Record Signal Strength for next packet */
+ if (bpacket_match_bssid)
+ pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
+ }
+
+ /* (2)PWDB, Average PWDB cacluated by
+ * hardware (for rate adaptive)
+ */
+ rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+ pstatus->rx_pwdb_all = pwdb_all;
+ pstatus->rxpower = rx_pwr_all;
+ pstatus->recvsignalpower = rx_pwr_all;
+
+ /* (3)EVM of HT rate */
+ if (pstatus->is_ht && pstatus->rate >= DESC92C_RATEMCS8 &&
+ pstatus->rate <= DESC92C_RATEMCS15)
+ max_spatial_stream = 2;
+ else
+ max_spatial_stream = 1;
+
+ for (i = 0; i < max_spatial_stream; i++) {
+ evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+
+ if (bpacket_match_bssid) {
+ /* Fill value in RFD, Get the first
+ * spatial stream only
+ */
+ if (i == 0)
+ pstatus->signalquality = evm & 0xff;
+ pstatus->rx_mimo_sig_qual[i] = evm & 0xff;
+ }
+ }
+ }
+
+ /* UI BSS List signal strength(in percentage),
+ * make it good looking, from 0~100.
+ */
+ if (is_cck)
+ pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+ pwdb_all));
+ else if (rf_rx_num != 0)
+ pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+ total_rssi /= rf_rx_num));
+ /*HW antenna diversity*/
+ rtldm->fat_table.antsel_rx_keep_0 = phystrpt->ant_sel;
+ rtldm->fat_table.antsel_rx_keep_1 = phystrpt->ant_sel_b;
+ rtldm->fat_table.antsel_rx_keep_2 = phystrpt->antsel_rx_keep_2;
+}
+
+static void _rtl88ee_smart_antenna(struct ieee80211_hw *hw,
+ struct rtl_stats *pstatus)
+{
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 ant_mux;
+ struct fast_ant_training *pfat = &(rtldm->fat_table);
+
+ if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV) {
+ if (pfat->fat_state == FAT_TRAINING_STATE) {
+ if (pstatus->packet_toself) {
+ ant_mux = (pfat->antsel_rx_keep_2 << 2) |
+ (pfat->antsel_rx_keep_1 << 1) |
+ pfat->antsel_rx_keep_0;
+ pfat->ant_sum[ant_mux] += pstatus->rx_pwdb_all;
+ pfat->ant_cnt[ant_mux]++;
+ }
+ }
+ } else if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) ||
+ (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)) {
+ if (pstatus->packet_toself || pstatus->packet_matchbssid) {
+ ant_mux = (pfat->antsel_rx_keep_2 << 2) |
+ (pfat->antsel_rx_keep_1 << 1) |
+ pfat->antsel_rx_keep_0;
+ rtl88e_dm_ant_sel_statistics(hw, ant_mux, 0,
+ pstatus->rx_pwdb_all);
+ }
+ }
+}
+
+static void _rtl88ee_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+ struct sk_buff *skb, struct rtl_stats *pstatus,
+ u8 *pdesc, struct rx_fwinfo_88e *p_drvinfo)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct ieee80211_hdr *hdr;
+ u8 *tmp_buf;
+ u8 *praddr;
+ u8 *psaddr;
+ __le16 fc;
+ u16 type, ufc;
+ bool match_bssid, packet_toself, packet_beacon, addr;
+
+ tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
+
+ hdr = (struct ieee80211_hdr *)tmp_buf;
+ fc = hdr->frame_control;
+ ufc = le16_to_cpu(fc);
+ type = WLAN_FC_GET_TYPE(fc);
+ praddr = hdr->addr1;
+ psaddr = ieee80211_get_SA(hdr);
+ memcpy(pstatus->psaddr, psaddr, ETH_ALEN);
+
+ addr = (!compare_ether_addr(mac->bssid, (ufc & IEEE80211_FCTL_TODS) ?
+ hdr->addr1 : (ufc & IEEE80211_FCTL_FROMDS) ?
+ hdr->addr2 : hdr->addr3));
+ match_bssid = ((IEEE80211_FTYPE_CTL != type) && (!pstatus->hwerror) &&
+ (!pstatus->crc) && (!pstatus->icv)) && addr;
+
+ addr = (!compare_ether_addr(praddr, rtlefuse->dev_addr));
+ packet_toself = match_bssid && addr;
+
+ if (ieee80211_is_beacon(fc))
+ packet_beacon = true;
+
+ _rtl88ee_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
+ match_bssid, packet_toself, packet_beacon);
+ _rtl88ee_smart_antenna(hw, pstatus);
+ rtl_process_phyinfo(hw, tmp_buf, pstatus);
+}
+
+static void insert_em(struct rtl_tcb_desc *ptcb_desc, u8 *virtualaddress)
+{
+ u32 dwtmp = 0;
+
+ memset(virtualaddress, 0, 8);
+
+ SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num);
+ if (ptcb_desc->empkt_num == 1) {
+ dwtmp = ptcb_desc->empkt_len[0];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[0];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[1];
+ }
+ SET_EARLYMODE_LEN0(virtualaddress, dwtmp);
+
+ if (ptcb_desc->empkt_num <= 3) {
+ dwtmp = ptcb_desc->empkt_len[2];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[2];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[3];
+ }
+ SET_EARLYMODE_LEN1(virtualaddress, dwtmp);
+ if (ptcb_desc->empkt_num <= 5) {
+ dwtmp = ptcb_desc->empkt_len[4];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[4];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[5];
+ }
+ SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF);
+ SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4);
+ if (ptcb_desc->empkt_num <= 7) {
+ dwtmp = ptcb_desc->empkt_len[6];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[6];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[7];
+ }
+ SET_EARLYMODE_LEN3(virtualaddress, dwtmp);
+ if (ptcb_desc->empkt_num <= 9) {
+ dwtmp = ptcb_desc->empkt_len[8];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[8];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[9];
+ }
+ SET_EARLYMODE_LEN4(virtualaddress, dwtmp);
+}
+
+bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
+ struct rtl_stats *status,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rx_fwinfo_88e *p_drvinfo;
+ struct ieee80211_hdr *hdr;
+
+ u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+ status->packet_report_type = (u8)GET_RX_STATUS_DESC_RPT_SEL(pdesc);
+ if (status->packet_report_type == TX_REPORT2)
+ status->length = (u16) GET_RX_RPT2_DESC_PKT_LEN(pdesc);
+ else
+ status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
+ status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+ RX_DRV_INFO_SIZE_UNIT;
+ status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
+ status->icv = (u16) GET_RX_DESC_ICV(pdesc);
+ status->crc = (u16) GET_RX_DESC_CRC32(pdesc);
+ status->hwerror = (status->crc | status->icv);
+ status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
+ status->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
+ status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
+ status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
+ status->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) &&
+ (GET_RX_DESC_FAGGR(pdesc) == 1));
+ if (status->packet_report_type == NORMAL_RX)
+ status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+ status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+ status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
+
+ status->is_cck = RTL8188_RX_HAL_IS_CCK_RATE(status->rate);
+
+ status->macid = GET_RX_DESC_MACID(pdesc);
+ if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+ status->wake_match = BIT(2);
+ else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+ status->wake_match = BIT(1);
+ else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc))
+ status->wake_match = BIT(0);
+ else
+ status->wake_match = 0;
+ if (status->wake_match)
+ RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
+ "Get Wakeup Packet!! WakeMatch =%d\n",
+ status->wake_match);
+ rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->band = hw->conf.channel->band;
+
+ if (status->crc)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+ if (status->rx_is40Mhzpacket)
+ rx_status->flag |= RX_FLAG_40MHZ;
+
+ if (status->is_ht)
+ rx_status->flag |= RX_FLAG_HT;
+
+ rx_status->flag |= RX_FLAG_MACTIME_START;
+
+ /* hw will set status->decrypted true, if it finds the
+ * frame is open data frame or mgmt frame.
+ * So hw will not decryption robust managment frame
+ * for IEEE80211w but still set status->decrypted
+ * true, so here we should set it back to undecrypted
+ * for IEEE80211w frame, and mac80211 sw will help
+ * to decrypt it
+ */
+ if (status->decrypted) {
+ hdr = (struct ieee80211_hdr *)(skb->data +
+ status->rx_drvinfo_size + status->rx_bufshift);
+
+ if (!hdr) {
+ /* During testing, hdr was NULL */
+ return false;
+ }
+ if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ }
+
+ /* rate_idx: index of data rate into band's
+ * supported rates or MCS index if HT rates
+ * are use (RX_FLAG_HT)
+ * Notice: this is diff with windows define
+ */
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
+ status->rate, false);
+
+ rx_status->mactime = status->timestamp_low;
+ if (phystatus == true) {
+ p_drvinfo = (struct rx_fwinfo_88e *)(skb->data +
+ status->rx_bufshift);
+
+ _rtl88ee_translate_rx_signal_stuff(hw, skb, status, pdesc,
+ p_drvinfo);
+ }
+
+ /*rx_status->qual = status->signal; */
+ rx_status->signal = status->recvsignalpower + 10;
+ /*rx_status->noise = -status->noise; */
+ if (status->packet_report_type == TX_REPORT2) {
+ status->macid_valid_entry[0] =
+ GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
+ status->macid_valid_entry[1] =
+ GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
+ }
+ return true;
+}
+
+void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 *pdesc = (u8 *)pdesc_tx;
+ u16 seq_number;
+ __le16 fc = hdr->frame_control;
+ unsigned int buf_len = 0;
+ unsigned int skb_len = skb->len;
+ u8 fw_qsel = _rtl88ee_map_hwqueue_to_fwqueue(skb, hw_queue);
+ bool firstseg = ((hdr->seq_ctrl &
+ cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+ bool lastseg = ((hdr->frame_control &
+ cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+ dma_addr_t mapping;
+ u8 bw_40 = 0;
+ u8 short_gi = 0;
+
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ bw_40 = mac->bw_40;
+ } else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta)
+ bw_40 = sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+ seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+ rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
+ /* reserve 8 byte for AMPDU early mode */
+ if (rtlhal->earlymode_enable) {
+ skb_push(skb, EM_HDR_LEN);
+ memset(skb->data, 0, EM_HDR_LEN);
+ }
+ buf_len = skb->len;
+ mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "DMA mapping error");
+ return;
+ }
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_88e));
+ if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+ firstseg = true;
+ lastseg = true;
+ }
+ if (firstseg) {
+ if (rtlhal->earlymode_enable) {
+ SET_TX_DESC_PKT_OFFSET(pdesc, 1);
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN +
+ EM_HDR_LEN);
+ if (ptcb_desc->empkt_num) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "Insert 8 byte.pTcb->EMPktNum:%d\n",
+ ptcb_desc->empkt_num);
+ insert_em(ptcb_desc, (u8 *)(skb->data));
+ }
+ } else {
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+ }
+
+ ptcb_desc->use_driver_rate = true;
+ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+ if (ptcb_desc->hw_rate > DESC92C_RATEMCS0)
+ short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
+ else
+ short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
+ SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi);
+
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ SET_TX_DESC_AGG_ENABLE(pdesc, 1);
+ SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
+ }
+ SET_TX_DESC_SEQ(pdesc, seq_number);
+ SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
+ !ptcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0);
+ SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0));
+
+ SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
+ SET_TX_DESC_RTS_BW(pdesc, 0);
+ SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
+ SET_TX_DESC_RTS_SHORT(pdesc,
+ ((ptcb_desc->rts_rate <= DESC92C_RATE54M) ?
+ (ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
+ (ptcb_desc->rts_use_shortgi ? 1 : 0)));
+
+ if (ptcb_desc->btx_enable_sw_calc_duration)
+ SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
+
+ if (bw_40) {
+ if (ptcb_desc->packet_bw) {
+ SET_TX_DESC_DATA_BW(pdesc, 1);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
+ } else {
+ SET_TX_DESC_DATA_BW(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+ mac->cur_40_prime_sc);
+ }
+ } else {
+ SET_TX_DESC_DATA_BW(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+ }
+
+ SET_TX_DESC_LINIP(pdesc, 0);
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len);
+ if (sta) {
+ u8 ampdu_density = sta->ht_cap.ampdu_density;
+ SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+ }
+ if (info->control.hw_key) {
+ struct ieee80211_key_conf *keyconf;
+ keyconf = info->control.hw_key;
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+ break;
+ default:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+ break;
+ }
+ }
+
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+ SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+ SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
+ SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ?
+ 1 : 0);
+ SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
+
+ /* Set TxRate and RTSRate in TxDesc */
+ /* This prevent Tx initial rate of new-coming packets */
+ /* from being overwritten by retried packet rate.*/
+ if (!ptcb_desc->use_driver_rate) {
+ /*SET_TX_DESC_RTS_RATE(pdesc, 0x08); */
+ /* SET_TX_DESC_TX_RATE(pdesc, 0x0b); */
+ }
+ if (ieee80211_is_data_qos(fc)) {
+ if (mac->rdg_en) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "Enable RDG function.\n");
+ SET_TX_DESC_RDG_ENABLE(pdesc, 1);
+ SET_TX_DESC_HTC(pdesc, 1);
+ }
+ }
+ }
+
+ SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+ SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len);
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+ if (rtlpriv->dm.useramask) {
+ SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
+ SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+ } else {
+ SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index);
+ SET_TX_DESC_MACID(pdesc, ptcb_desc->ratr_index);
+ }
+ if (ieee80211_is_data_qos(fc))
+ SET_TX_DESC_QOS(pdesc, 1);
+
+ if (!ieee80211_is_data_qos(fc))
+ SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+ SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
+ if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+ is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+ SET_TX_DESC_BMC(pdesc, 1);
+
+ rtl88e_dm_set_tx_ant_by_tx_info(hw, pdesc, ptcb_desc->mac_id);
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
+}
+
+void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
+ u8 *pdesc, bool firstseg,
+ bool lastseg, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 fw_queue = QSLT_BEACON;
+
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+ skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ __le16 fc = hdr->frame_control;
+
+ if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "DMA mapping error");
+ return;
+ }
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
+
+ if (firstseg)
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+ SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+
+ SET_TX_DESC_SEQ(pdesc, 0);
+
+ SET_TX_DESC_LINIP(pdesc, 0);
+
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+
+ SET_TX_DESC_RATE_ID(pdesc, 7);
+ SET_TX_DESC_MACID(pdesc, 0);
+
+ SET_TX_DESC_OWN(pdesc, 1);
+
+ SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_OFFSET(pdesc, 0x20);
+
+ SET_TX_DESC_USE_RATE(pdesc, 1);
+
+ if (!ieee80211_is_data_qos(fc))
+ SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+ "H2C Tx Cmd Content\n",
+ pdesc, TX_DESC_SIZE);
+}
+
+void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+{
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ SET_TX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_TX_NEXTDESC_ADDR:
+ SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val);
+ break;
+ default:
+ RT_ASSERT(false, "ERR txdesc :%d not processed\n",
+ desc_name);
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_RXOWN:
+ SET_RX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_RXBUFF_ADDR:
+ SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *)val);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ SET_RX_DESC_PKT_LEN(pdesc, *(u32 *)val);
+ break;
+ case HW_DESC_RXERO:
+ SET_RX_DESC_EOR(pdesc, 1);
+ break;
+ default:
+ RT_ASSERT(false, "ERR rxdesc :%d not processed\n",
+ desc_name);
+ break;
+ }
+ }
+}
+
+u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name)
+{
+ u32 ret = 0;
+
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_TX_DESC_OWN(pdesc);
+ break;
+ case HW_DESC_TXBUFF_ADDR:
+ ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc);
+ break;
+ default:
+ RT_ASSERT(false, "ERR txdesc :%d not processed\n",
+ desc_name);
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_RX_DESC_OWN(pdesc);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ ret = GET_RX_DESC_PKT_LEN(pdesc);
+ break;
+ default:
+ RT_ASSERT(false, "ERR rxdesc :%d not processed\n",
+ desc_name);
+ break;
+ }
+ }
+ return ret;
+}
+
+void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ if (hw_queue == BEACON_QUEUE) {
+ rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4));
+ } else {
+ rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG,
+ BIT(0) << (hw_queue));
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
new file mode 100644
index 000000000000..d3a02e73f53a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
@@ -0,0 +1,795 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_TRX_H__
+#define __RTL92CE_TRX_H__
+
+#define TX_DESC_SIZE 64
+#define TX_DESC_AGGR_SUBFRAME_SIZE 32
+
+#define RX_DESC_SIZE 32
+#define RX_DRV_INFO_SIZE_UNIT 8
+
+#define TX_DESC_NEXT_DESC_OFFSET 40
+#define USB_HWDESC_HEADER_LEN 32
+#define CRCLENGTH 4
+
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_BMC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GF(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_PKT_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 0, 16)
+#define GET_TX_DESC_OFFSET(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 16, 8)
+#define GET_TX_DESC_BMC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 24, 1)
+#define GET_TX_DESC_HTC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 25, 1)
+#define GET_TX_DESC_LAST_SEG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_TX_DESC_FIRST_SEG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_TX_DESC_LINIP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_TX_DESC_NO_ACM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_TX_DESC_GF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_TX_DESC_OWN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_TX_DESC_MACID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 6, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
+#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
+#define SET_TX_DESC_RATE_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 4, __val)
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 20, 1, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 26, 5, __val)
+#define SET_TX_DESC_PADDING_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 8, __val)
+
+#define GET_TX_DESC_MACID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
+#define GET_TX_DESC_AGG_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 5, 1)
+#define GET_TX_DESC_AGG_BREAK(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 6, 1)
+#define GET_TX_DESC_RDG_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 7, 1)
+#define GET_TX_DESC_QUEUE_SEL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 8, 5)
+#define GET_TX_DESC_RDG_NAV_EXT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_TX_DESC_PIFS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_TX_DESC_RATE_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_TX_DESC_NAV_USE_HDR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_TX_DESC_EN_DESC_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_TX_DESC_SEC_TYPE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 22, 2)
+#define GET_TX_DESC_PKT_OFFSET(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 24, 8)
+
+#define SET_TX_DESC_RTS_RC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 6, __val)
+#define SET_TX_DESC_DATA_RC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 6, 6, __val)
+#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val)
+#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val)
+#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
+#define SET_TX_DESC_RAW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
+#define SET_TX_DESC_CCX(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
+#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
+#define SET_TX_DESC_BT_INT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val)
+#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 1, __val)
+#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 25, 1, __val)
+#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 26, 2, __val)
+#define SET_TX_DESC_TX_ANTL(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 28, 2, __val)
+#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 30, 2, __val)
+
+#define GET_TX_DESC_RTS_RC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 0, 6)
+#define GET_TX_DESC_DATA_RC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 6, 6)
+#define GET_TX_DESC_BAR_RTY_TH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 14, 2)
+#define GET_TX_DESC_MORE_FRAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 17, 1)
+#define GET_TX_DESC_RAW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 18, 1)
+#define GET_TX_DESC_CCX(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 19, 1)
+#define GET_TX_DESC_AMPDU_DENSITY(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 20, 3)
+#define GET_TX_DESC_ANTSEL_A(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 24, 1)
+#define GET_TX_DESC_ANTSEL_B(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 25, 1)
+#define GET_TX_DESC_TX_ANT_CCK(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 26, 2)
+#define GET_TX_DESC_TX_ANTL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 28, 2)
+#define GET_TX_DESC_TX_ANT_HT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 30, 2)
+
+#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 8, __val)
+#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 8, __val)
+#define SET_TX_DESC_SEQ(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 12, __val)
+#define SET_TX_DESC_CPU_HANDLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 28, 1, __val)
+#define SET_TX_DESC_TAG1(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 29, 1, __val)
+#define SET_TX_DESC_TRIGGER_INT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 30, 1, __val)
+#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 31, 1, __val)
+
+
+#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 0, 8)
+#define GET_TX_DESC_TAIL_PAGE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 8, 8)
+#define GET_TX_DESC_SEQ(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 16, 12)
+
+
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 5, __val)
+#define SET_TX_DESC_AP_DCFE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 5, 1, __val)
+#define SET_TX_DESC_QOS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 6, 1, __val)
+#define SET_TX_DESC_HWSEQ_SSN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val)
+#define SET_TX_DESC_USE_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 1, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 9, 1, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 10, 1, __val)
+#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 12, 1, __val)
+#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 1, __val)
+#define SET_TX_DESC_PORT_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 14, 1, __val)
+#define SET_TX_DESC_PWR_STATUS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 15, 3, __val)
+#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 1, __val)
+#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 19, 1, __val)
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 20, 2, __val)
+#define SET_TX_DESC_TX_STBC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 22, 2, __val)
+#define SET_TX_DESC_DATA_SHORT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 1, __val)
+#define SET_TX_DESC_DATA_BW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 25, 1, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 26, 1, __val)
+#define SET_TX_DESC_RTS_BW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 27, 1, __val)
+#define SET_TX_DESC_RTS_SC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 28, 2, __val)
+#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val)
+
+#define GET_TX_DESC_RTS_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 0, 5)
+#define GET_TX_DESC_AP_DCFE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 5, 1)
+#define GET_TX_DESC_QOS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 6, 1)
+#define GET_TX_DESC_HWSEQ_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 7, 1)
+#define GET_TX_DESC_USE_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 8, 1)
+#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 9, 1)
+#define GET_TX_DESC_DISABLE_FB(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 10, 1)
+#define GET_TX_DESC_CTS2SELF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 11, 1)
+#define GET_TX_DESC_RTS_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 12, 1)
+#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 13, 1)
+#define GET_TX_DESC_PORT_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 14, 1)
+#define GET_TX_DESC_WAIT_DCTS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 18, 1)
+#define GET_TX_DESC_CTS2AP_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 19, 1)
+#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 20, 2)
+#define GET_TX_DESC_TX_STBC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 22, 2)
+#define GET_TX_DESC_DATA_SHORT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 24, 1)
+#define GET_TX_DESC_DATA_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 25, 1)
+#define GET_TX_DESC_RTS_SHORT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 26, 1)
+#define GET_TX_DESC_RTS_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 27, 1)
+#define GET_TX_DESC_RTS_SC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 28, 2)
+#define GET_TX_DESC_RTS_STBC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 30, 2)
+
+#define SET_TX_DESC_TX_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 6, __val)
+#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 6, 1, __val)
+#define SET_TX_DESC_CCX_TAG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 5, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 17, 1, __val)
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 18, 6, __val)
+#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 8, __val)
+
+#define GET_TX_DESC_TX_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 0, 6)
+#define GET_TX_DESC_DATA_SHORTGI(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 6, 1)
+#define GET_TX_DESC_CCX_TAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 7, 1)
+#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 8, 5)
+#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 13, 4)
+#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 17, 1)
+#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 18, 6)
+#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 24, 8)
+
+#define SET_TX_DESC_TXAGC_A(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 5, __val)
+#define SET_TX_DESC_TXAGC_B(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 5, 5, __val)
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 10, 1, __val)
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 11, 5, __val)
+#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 4, __val)
+#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 20, 4, __val)
+#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 24, 4, __val)
+#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 28, 4, __val)
+
+#define GET_TX_DESC_TXAGC_A(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 0, 5)
+#define GET_TX_DESC_TXAGC_B(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 5, 5)
+#define GET_TX_DESC_USE_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 10, 1)
+#define GET_TX_DESC_MAX_AGG_NUM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 11, 5)
+#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 16, 4)
+#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 20, 4)
+#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 24, 4)
+#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 28, 4)
+
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val)
+#define SET_TX_DESC_SW_OFFSET30(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 16, 8, __val)
+#define SET_TX_DESC_SW_OFFSET31(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 24, 4, __val)
+#define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 29, 1, __val)
+#define SET_TX_DESC_NULL_0(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 30, 1, __val)
+#define SET_TX_DESC_NULL_1(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 30, 1, __val)
+
+#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
+
+
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 32, __val)
+#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 32, __val)
+
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+32, 0, 32)
+#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+36, 0, 32)
+
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+44, 0, 32, __val)
+
+#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+40, 0, 32)
+#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+44, 0, 32)
+
+#define GET_RX_DESC_PKT_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 0, 14)
+#define GET_RX_DESC_CRC32(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 14, 1)
+#define GET_RX_DESC_ICV(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 15, 1)
+#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 16, 4)
+#define GET_RX_DESC_SECURITY(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 20, 3)
+#define GET_RX_DESC_QOS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 23, 1)
+#define GET_RX_DESC_SHIFT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 24, 2)
+#define GET_RX_DESC_PHYST(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_RX_DESC_SWDEC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_RX_DESC_LS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_RX_DESC_FS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_RX_DESC_EOR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_RX_DESC_OWN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_RX_DESC_EOR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_RX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_RX_DESC_MACID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 0, 6)
+#define GET_RX_DESC_PAGGR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_RX_DESC_FAGGR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_RX_DESC_A1_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_RX_DESC_A2_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 20, 4)
+#define GET_RX_DESC_PAM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
+#define GET_RX_DESC_PWR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
+#define GET_RX_DESC_MD(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
+#define GET_RX_DESC_MF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
+#define GET_RX_DESC_TYPE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
+#define GET_RX_DESC_MC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
+#define GET_RX_DESC_BC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
+#define GET_RX_DESC_SEQ(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
+#define GET_RX_DESC_FRAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
+
+#define GET_RX_DESC_RXMCS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 0, 6)
+#define GET_RX_DESC_RXHT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 6, 1)
+#define GET_RX_STATUS_DESC_RX_GF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 7, 1)
+#define GET_RX_DESC_SPLCP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 8, 1)
+#define GET_RX_DESC_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 9, 1)
+#define GET_RX_DESC_HTC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
+#define GET_RX_STATUS_DESC_EOSP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 11, 1)
+#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 12, 2)
+#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 14, 2)
+
+#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 29, 1)
+#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 30, 1)
+#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 31, 1)
+
+#define GET_RX_DESC_IV1(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 0, 32)
+#define GET_RX_DESC_TSFL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
+
+#define GET_RX_DESC_BUFF_ADDR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
+#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
+
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+
+/* TX report 2 format in Rx desc*/
+
+#define GET_RX_RPT2_DESC_PKT_LEN(__status) \
+ LE_BITS_TO_4BYTE(__status, 0, 9)
+#define GET_RX_RPT2_DESC_MACID_VALID_1(__status) \
+ LE_BITS_TO_4BYTE(__status+16, 0, 32)
+#define GET_RX_RPT2_DESC_MACID_VALID_2(__status) \
+ LE_BITS_TO_4BYTE(__status+20, 0, 32)
+
+#define SET_EARLYMODE_PKTNUM(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __value)
+#define SET_EARLYMODE_LEN0(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 4, 12, __value)
+#define SET_EARLYMODE_LEN1(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 16, 12, __value)
+#define SET_EARLYMODE_LEN2_1(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 28, 4, __value)
+#define SET_EARLYMODE_LEN2_2(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 8, __value)
+#define SET_EARLYMODE_LEN3(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr+4, 8, 12, __value)
+#define SET_EARLYMODE_LEN4(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr+4, 20, 12, __value)
+
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \
+do { \
+ if (_size > TX_DESC_NEXT_DESC_OFFSET) \
+ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
+ else \
+ memset(__pdesc, 0, _size); \
+} while (0)
+
+#define RTL8188_RX_HAL_IS_CCK_RATE(rxmcs)\
+ (rxmcs == DESC92C_RATE1M ||\
+ rxmcs == DESC92C_RATE2M ||\
+ rxmcs == DESC92C_RATE5_5M ||\
+ rxmcs == DESC92C_RATE11M)
+
+struct phy_rx_agc_info_t {
+ #if __LITTLE_ENDIAN
+ u8 gain:7, trsw:1;
+ #else
+ u8 trsw:1, gain:7;
+ #endif
+};
+struct phy_status_rpt {
+ struct phy_rx_agc_info_t path_agc[2];
+ u8 ch_corr[2];
+ u8 cck_sig_qual_ofdm_pwdb_all;
+ u8 cck_agc_rpt_ofdm_cfosho_a;
+ u8 cck_rpt_b_ofdm_cfosho_b;
+ u8 rsvd_1;
+ u8 noise_power_db_msb;
+ u8 path_cfotail[2];
+ u8 pcts_mask[2];
+ u8 stream_rxevm[2];
+ u8 path_rxsnr[2];
+ u8 noise_power_db_lsb;
+ u8 rsvd_2[3];
+ u8 stream_csi[2];
+ u8 stream_target_csi[2];
+ u8 sig_evm;
+ u8 rsvd_3;
+#if __LITTLE_ENDIAN
+ u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 idle_long:1;
+ u8 r_ant_train_en:1;
+ u8 ant_sel_b:1;
+ u8 ant_sel:1;
+#else /* _BIG_ENDIAN_ */
+ u8 ant_sel:1;
+ u8 ant_sel_b:1;
+ u8 r_ant_train_en:1;
+ u8 idle_long:1;
+ u8 rxsc:2;
+ u8 sgi_en:1;
+ u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/
+#endif
+} __packed;
+
+struct rx_fwinfo_88e {
+ u8 gain_trsw[4];
+ u8 pwdb_all;
+ u8 cfosho[4];
+ u8 cfotail[4];
+ char rxevm[2];
+ char rxsnr[4];
+ u8 pdsnr[2];
+ u8 csi_current[2];
+ u8 csi_target[2];
+ u8 sigevm;
+ u8 max_ex_pwr;
+ u8 ex_intf_flag:1;
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 reserve:4;
+} __packed;
+
+struct tx_desc_88e {
+ u32 pktsize:16;
+ u32 offset:8;
+ u32 bmc:1;
+ u32 htc:1;
+ u32 lastseg:1;
+ u32 firstseg:1;
+ u32 linip:1;
+ u32 noacm:1;
+ u32 gf:1;
+ u32 own:1;
+
+ u32 macid:6;
+ u32 rsvd0:2;
+ u32 queuesel:5;
+ u32 rd_nav_ext:1;
+ u32 lsig_txop_en:1;
+ u32 pifs:1;
+ u32 rateid:4;
+ u32 nav_usehdr:1;
+ u32 en_descid:1;
+ u32 sectype:2;
+ u32 pktoffset:8;
+
+ u32 rts_rc:6;
+ u32 data_rc:6;
+ u32 agg_en:1;
+ u32 rdg_en:1;
+ u32 bar_retryht:2;
+ u32 agg_break:1;
+ u32 morefrag:1;
+ u32 raw:1;
+ u32 ccx:1;
+ u32 ampdudensity:3;
+ u32 bt_int:1;
+ u32 ant_sela:1;
+ u32 ant_selb:1;
+ u32 txant_cck:2;
+ u32 txant_l:2;
+ u32 txant_ht:2;
+
+ u32 nextheadpage:8;
+ u32 tailpage:8;
+ u32 seq:12;
+ u32 cpu_handle:1;
+ u32 tag1:1;
+ u32 trigger_int:1;
+ u32 hwseq_en:1;
+
+ u32 rtsrate:5;
+ u32 apdcfe:1;
+ u32 qos:1;
+ u32 hwseq_ssn:1;
+ u32 userrate:1;
+ u32 dis_rtsfb:1;
+ u32 dis_datafb:1;
+ u32 cts2self:1;
+ u32 rts_en:1;
+ u32 hwrts_en:1;
+ u32 portid:1;
+ u32 pwr_status:3;
+ u32 waitdcts:1;
+ u32 cts2ap_en:1;
+ u32 txsc:2;
+ u32 stbc:2;
+ u32 txshort:1;
+ u32 txbw:1;
+ u32 rtsshort:1;
+ u32 rtsbw:1;
+ u32 rtssc:2;
+ u32 rtsstbc:2;
+
+ u32 txrate:6;
+ u32 shortgi:1;
+ u32 ccxt:1;
+ u32 txrate_fb_lmt:5;
+ u32 rtsrate_fb_lmt:4;
+ u32 retrylmt_en:1;
+ u32 txretrylmt:6;
+ u32 usb_txaggnum:8;
+
+ u32 txagca:5;
+ u32 txagcb:5;
+ u32 usemaxlen:1;
+ u32 maxaggnum:5;
+ u32 mcsg1maxlen:4;
+ u32 mcsg2maxlen:4;
+ u32 mcsg3maxlen:4;
+ u32 mcs7sgimaxlen:4;
+
+ u32 txbuffersize:16;
+ u32 sw_offset30:8;
+ u32 sw_offset31:4;
+ u32 rsvd1:1;
+ u32 antsel_c:1;
+ u32 null_0:1;
+ u32 null_1:1;
+
+ u32 txbuffaddr;
+ u32 txbufferaddr64;
+ u32 nextdescaddress;
+ u32 nextdescaddress64;
+
+ u32 reserve_pass_pcie_mm_limit[4];
+} __packed;
+
+struct rx_desc_88e {
+ u32 length:14;
+ u32 crc32:1;
+ u32 icverror:1;
+ u32 drv_infosize:4;
+ u32 security:3;
+ u32 qos:1;
+ u32 shift:2;
+ u32 phystatus:1;
+ u32 swdec:1;
+ u32 lastseg:1;
+ u32 firstseg:1;
+ u32 eor:1;
+ u32 own:1;
+
+ u32 macid:6;
+ u32 tid:4;
+ u32 hwrsvd:5;
+ u32 paggr:1;
+ u32 faggr:1;
+ u32 a1_fit:4;
+ u32 a2_fit:4;
+ u32 pam:1;
+ u32 pwr:1;
+ u32 moredata:1;
+ u32 morefrag:1;
+ u32 type:2;
+ u32 mc:1;
+ u32 bc:1;
+
+ u32 seq:12;
+ u32 frag:4;
+ u32 nextpktlen:14;
+ u32 nextind:1;
+ u32 rsvd:1;
+
+ u32 rxmcs:6;
+ u32 rxht:1;
+ u32 amsdu:1;
+ u32 splcp:1;
+ u32 bandwidth:1;
+ u32 htc:1;
+ u32 tcpchk_rpt:1;
+ u32 ipcchk_rpt:1;
+ u32 tcpchk_valid:1;
+ u32 hwpcerr:1;
+ u32 hwpcind:1;
+ u32 iv0:16;
+
+ u32 iv1;
+
+ u32 tsfl;
+
+ u32 bufferaddress;
+ u32 bufferaddress64;
+
+} __packed;
+
+void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
+bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
+ struct rtl_stats *status,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb);
+void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+ bool b_firstseg, bool b_lastseg,
+ struct sk_buff *skb);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index b793a659a465..926e2a34c766 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -174,8 +174,8 @@ static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_digtable->rx_gain_range_max = DM_DIG_MAX;
- dm_digtable->rx_gain_range_min = DM_DIG_MIN;
+ dm_digtable->rx_gain_max = DM_DIG_MAX;
+ dm_digtable->rx_gain_min = DM_DIG_MIN;
dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
@@ -300,11 +300,11 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
}
if ((digtable->rssi_val_min + 10 - digtable->back_val) >
- digtable->rx_gain_range_max)
- digtable->cur_igvalue = digtable->rx_gain_range_max;
+ digtable->rx_gain_max)
+ digtable->cur_igvalue = digtable->rx_gain_max;
else if ((digtable->rssi_val_min + 10 -
- digtable->back_val) < digtable->rx_gain_range_min)
- digtable->cur_igvalue = digtable->rx_gain_range_min;
+ digtable->back_val) < digtable->rx_gain_min)
+ digtable->cur_igvalue = digtable->rx_gain_min;
else
digtable->cur_igvalue = digtable->rssi_val_min + 10 -
digtable->back_val;
@@ -1147,75 +1147,6 @@ void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(rtl92c_dm_init_rate_adaptive_mask);
-static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- struct rate_adaptive *p_ra = &(rtlpriv->ra);
- u32 low_rssi_thresh, high_rssi_thresh;
- struct ieee80211_sta *sta = NULL;
-
- if (is_hal_stop(rtlhal)) {
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
- "<---- driver is going to unload\n");
- return;
- }
-
- if (!rtlpriv->dm.useramask) {
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
- "<---- driver does not control rate adaptive mask\n");
- return;
- }
-
- if (mac->link_state == MAC80211_LINKED &&
- mac->opmode == NL80211_IFTYPE_STATION) {
- switch (p_ra->pre_ratr_state) {
- case DM_RATR_STA_HIGH:
- high_rssi_thresh = 50;
- low_rssi_thresh = 20;
- break;
- case DM_RATR_STA_MIDDLE:
- high_rssi_thresh = 55;
- low_rssi_thresh = 20;
- break;
- case DM_RATR_STA_LOW:
- high_rssi_thresh = 50;
- low_rssi_thresh = 25;
- break;
- default:
- high_rssi_thresh = 50;
- low_rssi_thresh = 20;
- break;
- }
-
- if (rtlpriv->dm.undec_sm_pwdb > (long)high_rssi_thresh)
- p_ra->ratr_state = DM_RATR_STA_HIGH;
- else if (rtlpriv->dm.undec_sm_pwdb > (long)low_rssi_thresh)
- p_ra->ratr_state = DM_RATR_STA_MIDDLE;
- else
- p_ra->ratr_state = DM_RATR_STA_LOW;
-
- if (p_ra->pre_ratr_state != p_ra->ratr_state) {
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, "RSSI = %ld\n",
- rtlpriv->dm.undec_sm_pwdb);
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
- "RSSI_LEVEL = %d\n", p_ra->ratr_state);
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
- "PreState = %d, CurState = %d\n",
- p_ra->pre_ratr_state, p_ra->ratr_state);
-
- rcu_read_lock();
- sta = ieee80211_find_sta(mac->vif, mac->bssid);
- rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
- p_ra->ratr_state);
-
- p_ra->pre_ratr_state = p_ra->ratr_state;
- rcu_read_unlock();
- }
- }
-}
-
static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1437,6 +1368,9 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
(u8 *) (&fw_ps_awake));
+ if (ppsc->p2p_ps_info.p2p_ps_mode)
+ fw_ps_awake = false;
+
if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) &&
fw_ps_awake)
&& (!ppsc->rfchange_inprogress)) {
@@ -1446,7 +1380,7 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
rtl92c_dm_dynamic_bb_powersaving(hw);
rtl92c_dm_dynamic_txpower(hw);
rtl92c_dm_check_txpower_tracking(hw);
- rtl92c_dm_refresh_rate_adaptive_mask(hw);
+ /* rtl92c_dm_refresh_rate_adaptive_mask(hw); */
rtl92c_dm_bt_coexist(hw);
rtl92c_dm_check_edca_turbo(hw);
}
@@ -1651,7 +1585,7 @@ static void rtl92c_bt_set_normal(struct ieee80211_hw *hw)
}
}
-static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw)
+static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw, u8 tmp1byte)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
@@ -1673,9 +1607,9 @@ static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw)
BT_RSSI_STATE_SPECIAL_LOW)) {
rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
} else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) {
- rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte);
} else {
- rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte);
}
}
@@ -1726,12 +1660,17 @@ static void rtl92c_check_bt_change(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp1byte = 0;
+ if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version) &&
+ rtlpcipriv->bt_coexist.bt_coexistence)
+ tmp1byte |= BIT(5);
if (rtlpcipriv->bt_coexist.bt_cur_state) {
if (rtlpcipriv->bt_coexist.bt_ant_isolation)
- rtl92c_bt_ant_isolation(hw);
+ rtl92c_bt_ant_isolation(hw, tmp1byte);
} else {
- rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte);
rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0,
rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 883f23ae9519..04a41628ceed 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -552,7 +552,9 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
- SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+ (rtlpriv->mac80211.p2p) ?
+ ppsc->smart_ps : 1);
SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
ppsc->reg_max_lps_awakeintvl);
@@ -808,3 +810,98 @@ void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
}
EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
+
+static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
+{
+ u8 u1_ctwindow_period[1] = {ctwindow};
+
+ rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+}
+
+void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
+ struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+ u8 i;
+ u16 ctwindow;
+ u32 start_time, tsf_low;
+
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+ memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+ break;
+ case P2P_PS_ENABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+ /* update CTWindow value. */
+ if (p2pinfo->ctwindow > 0) {
+ p2p_ps_offload->ctwindow_en = 1;
+ ctwindow = p2pinfo->ctwindow;
+ rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
+ }
+ /* hw only support 2 set of NoA */
+ for (i = 0; i < p2pinfo->noa_num; i++) {
+ /* To control the register setting for which NOA*/
+ rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+ if (i == 0)
+ p2p_ps_offload->noa0_en = 1;
+ else
+ p2p_ps_offload->noa1_en = 1;
+
+ /* config P2P NoA Descriptor Register */
+ rtl_write_dword(rtlpriv, 0x5E0,
+ p2pinfo->noa_duration[i]);
+ rtl_write_dword(rtlpriv, 0x5E4,
+ p2pinfo->noa_interval[i]);
+
+ /*Get Current TSF value */
+ tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ start_time = p2pinfo->noa_start_time[i];
+ if (p2pinfo->noa_count_type[i] != 1) {
+ while (start_time <= (tsf_low+(50*1024))) {
+ start_time += p2pinfo->noa_interval[i];
+ if (p2pinfo->noa_count_type[i] != 255)
+ p2pinfo->noa_count_type[i]--;
+ }
+ }
+ rtl_write_dword(rtlpriv, 0x5E8, start_time);
+ rtl_write_dword(rtlpriv, 0x5EC,
+ p2pinfo->noa_count_type[i]);
+ }
+
+ if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+ /* rst p2p circuit */
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+ p2p_ps_offload->offload_en = 1;
+
+ if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+ p2p_ps_offload->role = 1;
+ p2p_ps_offload->allstasleep = 0;
+ } else {
+ p2p_ps_offload->role = 0;
+ }
+
+ p2p_ps_offload->discovery = 0;
+ }
+ break;
+ case P2P_PS_SCAN:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+ p2p_ps_offload->discovery = 1;
+ break;
+ case P2P_PS_SCAN_DONE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+ p2p_ps_offload->discovery = 0;
+ p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+ break;
+ default:
+ break;
+ }
+
+ rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
+}
+EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
index 780ea5b1e24c..15b2055e6212 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
@@ -67,6 +67,9 @@ enum rtl8192c_h2c_cmd {
H2C_RSVDPAGE = 3,
H2C_RSSI_REPORT = 5,
H2C_RA_MASK = 6,
+ H2C_MACID_PS_MODE = 7,
+ H2C_P2P_PS_OFFLOAD = 8,
+ H2C_P2P_PS_CTW_CMD = 32,
MAX_H2CCMD
};
@@ -95,5 +98,6 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
void usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 len);
+void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index 1b65db7fd651..a82b30a1996c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -475,6 +475,9 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+ rtl92c_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ break;
case HW_VAR_AID:{
u16 u2btmp;
u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
@@ -505,6 +508,40 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
+ case HW_VAR_FW_LPS_ACTION: {
+ bool enter_fwlps = *((bool *)val);
+ u8 rpwm_val, fw_pwrmode;
+ bool fw_current_inps;
+
+ if (enter_fwlps) {
+ rpwm_val = 0x02; /* RF off */
+ fw_current_inps = true;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ } else {
+ rpwm_val = 0x0C; /* RF on */
+ fw_pwrmode = FW_PS_ACTIVE_MODE;
+ fw_current_inps = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+ break; }
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case not processed\n");
@@ -1105,7 +1142,8 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
type == NL80211_IFTYPE_STATION) {
_rtl92ce_stop_tx_beacon(hw);
_rtl92ce_enable_bcn_sub_func(hw);
- } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) {
+ } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP ||
+ type == NL80211_IFTYPE_MESH_POINT) {
_rtl92ce_resume_tx_beacon(hw);
_rtl92ce_disable_bcn_sub_func(hw);
} else {
@@ -1137,6 +1175,11 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to AP!\n");
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ bt_msr |= MSR_ADHOC;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to Mesh Point!\n");
+ break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Network type %d not supported!\n", type);
@@ -1184,7 +1227,8 @@ int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
return -EOPNOTSUPP;
if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
- if (type != NL80211_IFTYPE_AP)
+ if (type != NL80211_IFTYPE_AP &&
+ type != NL80211_IFTYPE_MESH_POINT)
rtl92ce_set_check_bssid(hw, true);
} else {
rtl92ce_set_check_bssid(hw, false);
@@ -1459,7 +1503,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n",
rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
@@ -1500,11 +1544,11 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
& 0xf0) >> 4);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
@@ -1545,19 +1589,19 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
@@ -1565,7 +1609,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
else
rtlefuse->eeprom_regulatory = 0;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
if (!autoload_fail) {
@@ -1575,7 +1619,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI;
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -1589,7 +1633,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->apk_thermalmeterignore = true;
rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
}
@@ -1629,6 +1673,21 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
if (rtlefuse->autoload_failflag)
return;
+ rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+ rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+ rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+ rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROMId = 0x%4x\n", eeprom_id);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+
for (i = 0; i < 6; i += 2) {
usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
*((u16 *) (&rtlefuse->dev_addr[i])) = usvalue;
@@ -1766,6 +1825,9 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw,
ratr_value = sta->supp_rates[1] << 4;
else
ratr_value = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_value = 0xfff;
+
ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
@@ -1860,7 +1922,8 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
sta_entry = (struct rtl_sta_info *) sta->drv_priv;
wirelessmode = sta_entry->wireless_mode;
- if (mac->opmode == NL80211_IFTYPE_STATION)
+ if (mac->opmode == NL80211_IFTYPE_STATION ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
curtxbw_40mhz = mac->bw_40;
else if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC)
@@ -1870,6 +1933,8 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
ratr_bitmap = sta->supp_rates[1] << 4;
else
ratr_bitmap = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_bitmap = 0xfff;
ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
@@ -2135,7 +2200,8 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
macaddr = cam_const_broad;
entry_id = key_index;
} else {
- if (mac->opmode == NL80211_IFTYPE_AP) {
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
entry_id = rtl_cam_get_free_entry(hw,
p_macaddr);
if (entry_id >= TOTAL_CAM_ENTRY) {
@@ -2157,7 +2223,8 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"delete one entry, entry_id is %d\n",
entry_id);
- if (mac->opmode == NL80211_IFTYPE_AP)
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
rtl_cam_del_entry(hw, p_macaddr);
rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
} else {
@@ -2338,3 +2405,24 @@ void rtl92ce_suspend(struct ieee80211_hw *hw)
void rtl92ce_resume(struct ieee80211_hw *hw)
{
}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl92ce_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ if (allow_all_da) {/* Set BIT0 */
+ rtlpci->receive_config |= RCR_AAP;
+ } else {/* Clear BIT0 */
+ rtlpci->receive_config &= ~RCR_AAP;
+ }
+
+ if (write_into_reg)
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+ RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+ "receive_config=0x%08X, write_into_reg=%d\n",
+ rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
index 52a3aea9b3de..2d063b0c7760 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
@@ -61,6 +61,8 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw,
void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u8 rssi_level);
+void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw);
bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw);
@@ -74,5 +76,7 @@ void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw);
void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw);
void rtl92ce_suspend(struct ieee80211_hw *hw);
void rtl92ce_resume(struct ieee80211_hw *hw);
+void rtl92ce_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
index e4d738f6166d..bd4aef74c056 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
@@ -544,6 +544,7 @@
#define IMR_WLANOFF BIT(0)
#define EFUSE_REAL_CONTENT_LEN 512
+#define EFUSE_OOB_PROTECT_BYTES 15
#define EEPROM_DEFAULT_TSSI 0x0
#define EEPROM_DEFAULT_TXPOWERDIFF 0x0
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index 49f663bd93ff..14203561b6ee 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -228,6 +228,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
.enable_hw_sec = rtl92ce_enable_hw_security_config,
.set_key = rtl92ce_set_key,
.init_sw_leds = rtl92ce_init_sw_leds,
+ .allow_all_destaddr = rtl92ce_allow_all_destaddr,
.get_bbreg = rtl92c_phy_query_bb_reg,
.set_bbreg = rtl92c_phy_set_bb_reg,
.set_rfreg = rtl92ce_phy_set_rf_reg,
@@ -278,6 +279,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
.maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
.maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+ .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
.maps[RWCAM] = REG_CAMCMD,
.maps[WCAMI] = REG_CAMWRITE,
@@ -309,7 +311,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNINT,
.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
.maps[RTL_IMR_RDU] = IMR_RDU,
.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index b9b1a6e0b16e..65bf5fb97002 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../pci.h"
#include "../base.h"
+#include "../stats.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -42,7 +43,7 @@ static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
if (unlikely(ieee80211_is_beacon(fc)))
return QSLT_BEACON;
- if (ieee80211_is_mgmt(fc))
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
return QSLT_MGNT;
return skb->priority;
@@ -78,16 +79,6 @@ static u8 _rtl92c_evm_db_to_percentage(char value)
return ret_val;
}
-static long _rtl92ce_translate_todbm(struct ieee80211_hw *hw,
- u8 signal_strength_index)
-{
- long signal_power;
-
- signal_power = (long)((signal_strength_index + 1) >> 1);
- signal_power -= 95;
- return signal_power;
-}
-
static long _rtl92ce_signal_scale_mapping(struct ieee80211_hw *hw,
long currsig)
{
@@ -139,7 +130,6 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
pstats->packet_toself = packet_toself;
pstats->is_cck = is_cck_rate;
pstats->packet_beacon = packet_beacon;
- pstats->is_cck = is_cck_rate;
pstats->rx_mimo_sig_qual[0] = -1;
pstats->rx_mimo_sig_qual[1] = -1;
@@ -192,10 +182,30 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
}
}
- pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all);
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+ /* CCK gain is smaller than OFDM/MCS gain,
+ * so we add gain diff by experiences,
+ * the val is 6
+ */
+ pwdb_all += 6;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ /* modify the offset to make the same
+ * gain index with OFDM.
+ */
+ if (pwdb_all > 34 && pwdb_all <= 42)
+ pwdb_all -= 2;
+ else if (pwdb_all > 26 && pwdb_all <= 34)
+ pwdb_all -= 6;
+ else if (pwdb_all > 14 && pwdb_all <= 26)
+ pwdb_all -= 8;
+ else if (pwdb_all > 4 && pwdb_all <= 14)
+ pwdb_all -= 4;
+
pstats->rx_pwdb_all = pwdb_all;
pstats->recvsignalpower = rx_pwr_all;
+ /* (3) Get Signal Quality (EVM) */
if (packet_match_bssid) {
u8 sq;
if (pstats->rx_pwdb_all > 40)
@@ -217,29 +227,38 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
} else {
rtlpriv->dm.rfpath_rxenable[0] =
rtlpriv->dm.rfpath_rxenable[1] = true;
+ /* (1)Get RSSI for HT rate */
for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
+ /* we will judge RF RX path now. */
if (rtlpriv->dm.rfpath_rxenable[i])
rf_rx_num++;
rx_pwr[i] =
((p_drvinfo->gain_trsw[i] & 0x3f) * 2) - 110;
+ /* Translate DBM to percentage. */
rssi = _rtl92c_query_rxpwrpercentage(rx_pwr[i]);
total_rssi += rssi;
+ /* Get Rx snr value in DB */
rtlpriv->stats.rx_snr_db[i] =
(long)(p_drvinfo->rxsnr[i] / 2);
+ /* Record Signal Strength for next packet */
if (packet_match_bssid)
pstats->rx_mimo_signalstrength[i] = (u8) rssi;
}
+ /* (2)PWDB, Average PWDB cacluated by
+ * hardware (for rate adaptive)
+ */
rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all);
pstats->rx_pwdb_all = pwdb_all;
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
- if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 &&
- pdesc->rxmcs <= DESC92_RATEMCS15)
+ /* (3)EVM of HT rate */
+ if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 &&
+ pstats->rate <= DESC92_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -248,6 +267,9 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
evm = _rtl92c_evm_db_to_percentage(p_drvinfo->rxevm[i]);
if (packet_match_bssid) {
+ /* Fill value in RFD, Get the first
+ * spatial stream only
+ */
if (i == 0)
pstats->signalquality =
(u8) (evm & 0xff);
@@ -256,6 +278,9 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
}
}
+ /* UI BSS List signal strength(in percentage),
+ * make it good looking, from 0~100.
+ */
if (is_cck_rate)
pstats->signalstrength =
(u8) (_rtl92ce_signal_scale_mapping(hw, pwdb_all));
@@ -265,215 +290,6 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
(hw, total_rssi /= rf_rx_num));
}
-static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
- u8 rfpath;
- u32 last_rssi, tmpval;
-
- if (pstats->packet_toself || pstats->packet_beacon) {
- rtlpriv->stats.rssi_calculate_cnt++;
-
- if (rtlpriv->stats.ui_rssi.total_num++ >=
- PHY_RSSI_SLID_WIN_MAX) {
-
- rtlpriv->stats.ui_rssi.total_num =
- PHY_RSSI_SLID_WIN_MAX;
- last_rssi =
- rtlpriv->stats.ui_rssi.elements[rtlpriv->
- stats.ui_rssi.index];
- rtlpriv->stats.ui_rssi.total_val -= last_rssi;
- }
-
- rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength;
- rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.
- index++] =
- pstats->signalstrength;
-
- if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
- rtlpriv->stats.ui_rssi.index = 0;
-
- tmpval = rtlpriv->stats.ui_rssi.total_val /
- rtlpriv->stats.ui_rssi.total_num;
- rtlpriv->stats.signal_strength =
- _rtl92ce_translate_todbm(hw, (u8) tmpval);
- pstats->rssi = rtlpriv->stats.signal_strength;
- }
-
- if (!pstats->is_cck && pstats->packet_toself) {
- for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
- rfpath++) {
- if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- pstats->rx_mimo_signalstrength[rfpath];
-
- }
-
- if (pstats->rx_mimo_signalstrength[rfpath] >
- rtlpriv->stats.rx_rssi_percentage[rfpath]) {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- ((rtlpriv->stats.
- rx_rssi_percentage[rfpath] *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_signalstrength[rfpath])) /
- (RX_SMOOTH_FACTOR);
-
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- rtlpriv->stats.rx_rssi_percentage[rfpath] +
- 1;
- } else {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- ((rtlpriv->stats.
- rx_rssi_percentage[rfpath] *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_signalstrength[rfpath])) /
- (RX_SMOOTH_FACTOR);
- }
-
- }
- }
-}
-
-static void _rtl92ce_update_rxsignalstatistics(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- int weighting = 0;
-
- if (rtlpriv->stats.recv_signal_power == 0)
- rtlpriv->stats.recv_signal_power = pstats->recvsignalpower;
-
- if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power)
- weighting = 5;
-
- else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power)
- weighting = (-5);
-
- rtlpriv->stats.recv_signal_power =
- (rtlpriv->stats.recv_signal_power * 5 +
- pstats->recvsignalpower + weighting) / 6;
-}
-
-static void _rtl92ce_process_pwdb(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- long undec_sm_pwdb;
-
- if (mac->opmode == NL80211_IFTYPE_ADHOC) {
- return;
- } else {
- undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
- }
-
- if (pstats->packet_toself || pstats->packet_beacon) {
- if (undec_sm_pwdb < 0)
- undec_sm_pwdb = pstats->rx_pwdb_all;
-
- if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
- undec_sm_pwdb = (((undec_sm_pwdb) *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-
- undec_sm_pwdb += 1;
- } else {
- undec_sm_pwdb = (((undec_sm_pwdb) *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
- }
-
- rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
- _rtl92ce_update_rxsignalstatistics(hw, pstats);
- }
-}
-
-static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 last_evm, n_spatialstream, tmpval;
-
- if (pstats->signalquality != 0) {
- if (pstats->packet_toself || pstats->packet_beacon) {
-
- if (rtlpriv->stats.ui_link_quality.total_num++ >=
- PHY_LINKQUALITY_SLID_WIN_MAX) {
- rtlpriv->stats.ui_link_quality.total_num =
- PHY_LINKQUALITY_SLID_WIN_MAX;
- last_evm =
- rtlpriv->stats.
- ui_link_quality.elements[rtlpriv->
- stats.ui_link_quality.
- index];
- rtlpriv->stats.ui_link_quality.total_val -=
- last_evm;
- }
-
- rtlpriv->stats.ui_link_quality.total_val +=
- pstats->signalquality;
- rtlpriv->stats.ui_link_quality.elements[rtlpriv->stats.
- ui_link_quality.
- index++] =
- pstats->signalquality;
-
- if (rtlpriv->stats.ui_link_quality.index >=
- PHY_LINKQUALITY_SLID_WIN_MAX)
- rtlpriv->stats.ui_link_quality.index = 0;
-
- tmpval = rtlpriv->stats.ui_link_quality.total_val /
- rtlpriv->stats.ui_link_quality.total_num;
- rtlpriv->stats.signal_quality = tmpval;
-
- rtlpriv->stats.last_sigstrength_inpercent = tmpval;
-
- for (n_spatialstream = 0; n_spatialstream < 2;
- n_spatialstream++) {
- if (pstats->
- rx_mimo_sig_qual[n_spatialstream] != -1) {
- if (rtlpriv->stats.
- rx_evm_percentage[n_spatialstream]
- == 0) {
- rtlpriv->stats.
- rx_evm_percentage
- [n_spatialstream] =
- pstats->rx_mimo_sig_qual
- [n_spatialstream];
- }
-
- rtlpriv->stats.
- rx_evm_percentage[n_spatialstream] =
- ((rtlpriv->
- stats.rx_evm_percentage
- [n_spatialstream] *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_sig_qual
- [n_spatialstream] * 1)) /
- (RX_SMOOTH_FACTOR);
- }
- }
- }
- } else {
- ;
- }
-}
-
-static void _rtl92ce_process_phyinfo(struct ieee80211_hw *hw,
- u8 *buffer,
- struct rtl_stats *pcurrent_stats)
-{
-
- if (!pcurrent_stats->packet_matchbssid &&
- !pcurrent_stats->packet_beacon)
- return;
-
- _rtl92ce_process_ui_rssi(hw, pcurrent_stats);
- _rtl92ce_process_pwdb(hw, pcurrent_stats);
- _rtl92ce_process_ui_link_quality(hw, pcurrent_stats);
-}
-
static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct rtl_stats *pstats,
@@ -516,7 +332,7 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
packet_matchbssid, packet_toself,
packet_beacon);
- _rtl92ce_process_phyinfo(hw, tmp_buf, pstats);
+ rtl_process_phyinfo(hw, tmp_buf, pstats);
}
bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
@@ -526,7 +342,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
{
struct rx_fwinfo_92c *p_drvinfo;
struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc;
-
+ struct ieee80211_hdr *hdr;
u32 phystatus = GET_RX_DESC_PHYST(pdesc);
stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
stats->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
@@ -539,37 +355,60 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
stats->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
- stats->isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
+ stats->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
&& (GET_RX_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+ stats->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
+
+ stats->is_cck = RX_HAL_IS_CCK_RATE(pdesc);
rx_status->freq = hw->conf.channel->center_freq;
rx_status->band = hw->conf.channel->band;
- if (GET_RX_DESC_CRC32(pdesc))
- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ hdr = (struct ieee80211_hdr *)(skb->data + stats->rx_drvinfo_size
+ + stats->rx_bufshift);
- if (!GET_RX_DESC_SWDEC(pdesc))
- rx_status->flag |= RX_FLAG_DECRYPTED;
+ if (stats->crc)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
- if (GET_RX_DESC_BW(pdesc))
+ if (stats->rx_is40Mhzpacket)
rx_status->flag |= RX_FLAG_40MHZ;
- if (GET_RX_DESC_RXHT(pdesc))
+ if (stats->is_ht)
rx_status->flag |= RX_FLAG_HT;
rx_status->flag |= RX_FLAG_MACTIME_START;
- if (stats->decrypted)
- rx_status->flag |= RX_FLAG_DECRYPTED;
-
+ /* hw will set stats->decrypted true, if it finds the
+ * frame is open data frame or mgmt frame.
+ * So hw will not decryption robust managment frame
+ * for IEEE80211w but still set status->decrypted
+ * true, so here we should set it back to undecrypted
+ * for IEEE80211w frame, and mac80211 sw will help
+ * to decrypt it
+ */
+ if (stats->decrypted) {
+ if (!hdr) {
+ /* In testing, hdr was NULL here */
+ return false;
+ }
+ if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ }
+ /* rate_idx: index of data rate into band's
+ * supported rates or MCS index if HT rates
+ * are use (RX_FLAG_HT)
+ * Notice: this is diff with windows define
+ */
rx_status->rate_idx = rtlwifi_rate_mapping(hw,
- (bool)GET_RX_DESC_RXHT(pdesc),
- (u8)GET_RX_DESC_RXMCS(pdesc),
- (bool)GET_RX_DESC_PAGGR(pdesc));
+ stats->is_ht, stats->rate,
+ stats->isfirst_ampdu);
- rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
+ rx_status->mactime = stats->timestamp_low;
if (phystatus) {
p_drvinfo = (struct rx_fwinfo_92c *)(skb->data +
stats->rx_bufshift);
@@ -580,7 +419,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
}
/*rx_status->qual = stats->signal; */
- rx_status->signal = stats->rssi + 10;
+ rx_status->signal = stats->recvsignalpower + 10;
/*rx_status->noise = -stats->noise; */
return true;
@@ -624,7 +463,8 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
if (mac->opmode == NL80211_IFTYPE_STATION) {
bw_40 = mac->bw_40;
} else if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC) {
+ mac->opmode == NL80211_IFTYPE_ADHOC ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
if (sta)
bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index c08d0f4c5f3d..3d0498e69c8c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -202,7 +202,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n", rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
rtlefuse->txpwrlevel_ht40_1s[rf_path][i],
@@ -238,11 +238,11 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
((rtlefuse->eeprom_pwrlimit_ht40[index]
& 0xf0) >> 4);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
@@ -273,26 +273,26 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->legacy_ht_txpowerdiff =
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
if (!autoload_fail)
rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
else
rtlefuse->eeprom_regulatory = 0;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
if (!autoload_fail) {
rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
@@ -301,7 +301,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI;
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -316,7 +316,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail)
rtlefuse->apk_thermalmeterignore = true;
rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index a73a17bc56dd..23d640a4debd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -223,7 +223,7 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNINT,
.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
.maps[RTL_IMR_RDU] = IMR_RDU,
.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index b6222eedb835..710f7904ecdf 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -434,7 +434,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
(u32)hdr->addr1[2], (u32)hdr->addr1[3],
(u32)hdr->addr1[4], (u32)hdr->addr1[5]);
memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
- ieee80211_rx_irqsafe(hw, skb);
+ ieee80211_rx(hw, skb);
}
void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index 5251fb8a111e..19a765532603 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -171,8 +171,8 @@ static void rtl92d_dm_diginit(struct ieee80211_hw *hw)
de_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
de_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
de_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- de_digtable->rx_gain_range_max = DM_DIG_FA_UPPER;
- de_digtable->rx_gain_range_min = DM_DIG_FA_LOWER;
+ de_digtable->rx_gain_max = DM_DIG_FA_UPPER;
+ de_digtable->rx_gain_min = DM_DIG_FA_LOWER;
de_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
de_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
de_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
@@ -444,8 +444,8 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
"dm_DIG() Before: large_fa_hit=%d, forbidden_igi=%x\n",
de_digtable->large_fa_hit, de_digtable->forbidden_igi);
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
- "dm_DIG() Before: Recover_cnt=%d, rx_gain_range_min=%x\n",
- de_digtable->recover_cnt, de_digtable->rx_gain_range_min);
+ "dm_DIG() Before: Recover_cnt=%d, rx_gain_min=%x\n",
+ de_digtable->recover_cnt, de_digtable->rx_gain_min);
/* deal with abnorally large false alarm */
if (falsealm_cnt->cnt_all > 10000) {
@@ -459,9 +459,9 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
}
if (de_digtable->large_fa_hit >= 3) {
if ((de_digtable->forbidden_igi + 1) > DM_DIG_MAX)
- de_digtable->rx_gain_range_min = DM_DIG_MAX;
+ de_digtable->rx_gain_min = DM_DIG_MAX;
else
- de_digtable->rx_gain_range_min =
+ de_digtable->rx_gain_min =
(de_digtable->forbidden_igi + 1);
de_digtable->recover_cnt = 3600; /* 3600=2hr */
}
@@ -475,12 +475,12 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
DM_DIG_FA_LOWER) {
de_digtable->forbidden_igi =
DM_DIG_FA_LOWER;
- de_digtable->rx_gain_range_min =
+ de_digtable->rx_gain_min =
DM_DIG_FA_LOWER;
} else {
de_digtable->forbidden_igi--;
- de_digtable->rx_gain_range_min =
+ de_digtable->rx_gain_min =
(de_digtable->forbidden_igi + 1);
}
} else if (de_digtable->large_fa_hit == 3) {
@@ -492,13 +492,13 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
"dm_DIG() After: large_fa_hit=%d, forbidden_igi=%x\n",
de_digtable->large_fa_hit, de_digtable->forbidden_igi);
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
- "dm_DIG() After: recover_cnt=%d, rx_gain_range_min=%x\n",
- de_digtable->recover_cnt, de_digtable->rx_gain_range_min);
+ "dm_DIG() After: recover_cnt=%d, rx_gain_min=%x\n",
+ de_digtable->recover_cnt, de_digtable->rx_gain_min);
if (value_igi > DM_DIG_MAX)
value_igi = DM_DIG_MAX;
- else if (value_igi < de_digtable->rx_gain_range_min)
- value_igi = de_digtable->rx_gain_range_min;
+ else if (value_igi < de_digtable->rx_gain_min)
+ value_igi = de_digtable->rx_gain_min;
de_digtable->cur_igvalue = value_igi;
rtl92d_dm_write_dig(hw);
if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G)
@@ -1071,9 +1071,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
}
ele_d = (ofdmswing_table[(u8) ofdm_index[0]] &
0xFFC00000) >> 22;
- val_x = rtlphy->iqk_matrix_regsetting
+ val_x = rtlphy->iqk_matrix
[indexforchannel].value[0][0];
- val_y = rtlphy->iqk_matrix_regsetting
+ val_y = rtlphy->iqk_matrix
[indexforchannel].value[0][1];
if (val_x != 0) {
if ((val_x & 0x00000200) != 0)
@@ -1175,9 +1175,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
if (is2t) {
ele_d = (ofdmswing_table[(u8) ofdm_index[1]] &
0xFFC00000) >> 22;
- val_x = rtlphy->iqk_matrix_regsetting
+ val_x = rtlphy->iqk_matrix
[indexforchannel].value[0][4];
- val_y = rtlphy->iqk_matrix_regsetting
+ val_y = rtlphy->iqk_matrix
[indexforchannel].value[0][5];
if (val_x != 0) {
if ((val_x & 0x00000200) != 0)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index aa5b42521bb4..7dd8f6de0550 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -1183,7 +1183,7 @@ void rtl92d_linked_set_reg(struct ieee80211_hw *hw)
u8 channel = rtlphy->current_channel;
indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel);
- if (!rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done) {
+ if (!rtlphy->iqk_matrix[indexforchannel].iqk_done) {
RT_TRACE(rtlpriv, COMP_SCAN | COMP_INIT, DBG_DMESG,
"Do IQK for channel:%d\n", channel);
rtl92d_phy_iq_calibrate(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
index 33041bd4da81..840bac5fa2f8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
@@ -2479,9 +2479,9 @@ void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw)
rtlphy->current_channel);
for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
- rtlphy->iqk_matrix_regsetting[indexforchannel].
+ rtlphy->iqk_matrix[indexforchannel].
value[0][i] = result[final_candidate][i];
- rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done =
+ rtlphy->iqk_matrix[indexforchannel].iqk_done =
true;
RT_TRACE(rtlpriv, COMP_SCAN | COMP_MLME, DBG_LOUD,
@@ -2501,8 +2501,8 @@ void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel)
indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel);
RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "indexforchannel %d done %d\n",
indexforchannel,
- rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done);
- if (0 && !rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done &&
+ rtlphy->iqk_matrix[indexforchannel].iqk_done);
+ if (0 && !rtlphy->iqk_matrix[indexforchannel].iqk_done &&
rtlphy->need_iqk) {
/* Re Do IQK. */
RT_TRACE(rtlpriv, COMP_SCAN | COMP_INIT, DBG_LOUD,
@@ -2516,23 +2516,23 @@ void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel)
RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD,
"Just Read IQK Matrix reg for channel:%d....\n",
channel);
- if ((rtlphy->iqk_matrix_regsetting[indexforchannel].
+ if ((rtlphy->iqk_matrix[indexforchannel].
value[0] != NULL)
/*&&(regea4 != 0) */)
_rtl92d_phy_patha_fill_iqk_matrix(hw, true,
- rtlphy->iqk_matrix_regsetting[
+ rtlphy->iqk_matrix[
indexforchannel].value, 0,
- (rtlphy->iqk_matrix_regsetting[
+ (rtlphy->iqk_matrix[
indexforchannel].value[0][2] == 0));
if (IS_92D_SINGLEPHY(rtlhal->version)) {
- if ((rtlphy->iqk_matrix_regsetting[
+ if ((rtlphy->iqk_matrix[
indexforchannel].value[0][4] != 0)
/*&&(regec4 != 0) */)
_rtl92d_phy_pathb_fill_iqk_matrix(hw,
true,
- rtlphy->iqk_matrix_regsetting[
+ rtlphy->iqk_matrix[
indexforchannel].value, 0,
- (rtlphy->iqk_matrix_regsetting[
+ (rtlphy->iqk_matrix[
indexforchannel].value[0][6]
== 0));
}
@@ -2830,20 +2830,20 @@ void rtl92d_phy_reset_iqk_result(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"settings regs %d default regs %d\n",
- (int)(sizeof(rtlphy->iqk_matrix_regsetting) /
+ (int)(sizeof(rtlphy->iqk_matrix) /
sizeof(struct iqk_matrix_regs)),
IQK_MATRIX_REG_NUM);
/* 0xe94, 0xe9c, 0xea4, 0xeac, 0xeb4, 0xebc, 0xec4, 0xecc */
for (i = 0; i < IQK_MATRIX_SETTINGS_NUM; i++) {
- rtlphy->iqk_matrix_regsetting[i].value[0][0] = 0x100;
- rtlphy->iqk_matrix_regsetting[i].value[0][2] = 0x100;
- rtlphy->iqk_matrix_regsetting[i].value[0][4] = 0x100;
- rtlphy->iqk_matrix_regsetting[i].value[0][6] = 0x100;
- rtlphy->iqk_matrix_regsetting[i].value[0][1] = 0x0;
- rtlphy->iqk_matrix_regsetting[i].value[0][3] = 0x0;
- rtlphy->iqk_matrix_regsetting[i].value[0][5] = 0x0;
- rtlphy->iqk_matrix_regsetting[i].value[0][7] = 0x0;
- rtlphy->iqk_matrix_regsetting[i].iqk_done = false;
+ rtlphy->iqk_matrix[i].value[0][0] = 0x100;
+ rtlphy->iqk_matrix[i].value[0][2] = 0x100;
+ rtlphy->iqk_matrix[i].value[0][4] = 0x100;
+ rtlphy->iqk_matrix[i].value[0][6] = 0x100;
+ rtlphy->iqk_matrix[i].value[0][1] = 0x0;
+ rtlphy->iqk_matrix[i].value[0][3] = 0x0;
+ rtlphy->iqk_matrix[i].value[0][5] = 0x0;
+ rtlphy->iqk_matrix[i].value[0][7] = 0x0;
+ rtlphy->iqk_matrix[i].iqk_done = false;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
index ebb1d5f5e7b5..b7498c5bafc5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
@@ -543,7 +543,7 @@
#define IMR_TIMEOUT1 BIT(16)
#define IMR_TXFOVW BIT(15)
#define IMR_PSTIMEOUT BIT(14)
-#define IMR_BcnInt BIT(13)
+#define IMR_BCNINT BIT(13)
#define IMR_RXFOVW BIT(12)
#define IMR_RDU BIT(11)
#define IMR_ATIMEND BIT(10)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
index 03c6d18b2e07..c18c04bf0c13 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
@@ -166,7 +166,7 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
/* for early mode */
- rtlpriv->rtlhal.earlymode_enable = true;
+ rtlpriv->rtlhal.earlymode_enable = false;
for (tid = 0; tid < 8; tid++)
skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]);
@@ -319,7 +319,7 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = IMR_BcnInt,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNINT,
.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
.maps[RTL_IMR_RDU] = IMR_RDU,
.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
@@ -333,7 +333,7 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = {
.maps[RTL_IMR_VIDOK] = IMR_VIDOK,
.maps[RTL_IMR_VODOK] = IMR_VODOK,
.maps[RTL_IMR_ROK] = IMR_ROK,
- .maps[RTL_IBSS_INT_MASKS] = (IMR_BcnInt | IMR_TBDOK | IMR_TBDER),
+ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
.maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
.maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
index 2d255e02d795..83c98674bfd3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
@@ -36,9 +36,6 @@
#define SHORT_SLOT_TIME 9
#define NON_SHORT_SLOT_TIME 20
-/* Rx smooth factor */
-#define RX_SMOOTH_FACTOR 20
-
/* Queue Select Value in TxDesc */
#define QSLT_BK 0x2
#define QSLT_BE 0x0
@@ -49,10 +46,6 @@
#define QSLT_MGNT 0x12
#define QSLT_CMD 0x13
-#define PHY_RSSI_SLID_WIN_MAX 100
-#define PHY_LINKQUALITY_SLID_WIN_MAX 20
-#define PHY_BEACON_RSSI_SLID_WIN_MAX 10
-
/* Tx Desc */
#define TX_DESC_SIZE_RTL8192S (16 * 4)
#define TX_CMDDESC_SIZE_RTL8192S (16 * 4)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
index e551fe5f9ccd..b3a2d5ec59e6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
@@ -163,6 +163,7 @@ static void _rtl92s_dm_txpowertracking_callback_thermalmeter(
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u8 thermalvalue = 0;
+ u32 fw_cmd = 0;
rtlpriv->dm.txpower_trackinginit = true;
@@ -175,7 +176,19 @@ static void _rtl92s_dm_txpowertracking_callback_thermalmeter(
if (thermalvalue) {
rtlpriv->dm.thermalvalue = thermalvalue;
- rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL);
+ if (hal_get_firmwareversion(rtlpriv) >= 0x35) {
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL);
+ } else {
+ fw_cmd = (FW_TXPWR_TRACK_THERMAL |
+ (rtlpriv->efuse.thermalmeter[0] << 8) |
+ (thermalvalue << 16));
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Write to FW Thermal Val = 0x%x\n", fw_cmd);
+
+ rtl_write_dword(rtlpriv, WFM5, fw_cmd);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ }
}
rtlpriv->dm.txpowercount = 0;
@@ -217,11 +230,10 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rate_adaptive *ra = &(rtlpriv->ra);
-
+ struct ieee80211_sta *sta = NULL;
u32 low_rssi_thresh = 0;
u32 middle_rssi_thresh = 0;
u32 high_rssi_thresh = 0;
- struct ieee80211_sta *sta = NULL;
if (is_hal_stop(rtlhal))
return;
@@ -229,14 +241,12 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
if (!rtlpriv->dm.useramask)
return;
- if (!rtlpriv->dm.inform_fw_driverctrldm) {
+ if (hal_get_firmwareversion(rtlpriv) >= 61 &&
+ !rtlpriv->dm.inform_fw_driverctrldm) {
rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER);
rtlpriv->dm.inform_fw_driverctrldm = true;
}
- rcu_read_lock();
- if (mac->opmode == NL80211_IFTYPE_STATION)
- sta = get_sta(hw, mac->vif, mac->bssid);
if ((mac->link_state == MAC80211_LINKED) &&
(mac->opmode == NL80211_IFTYPE_STATION)) {
switch (ra->pre_ratr_state) {
@@ -285,12 +295,16 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
rtlpriv->dm.undec_sm_pwdb, ra->ratr_state,
ra->pre_ratr_state, ra->ratr_state);
- rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, mac->bssid);
+ if (sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
ra->ratr_state);
+ rcu_read_unlock();
+
ra->pre_ratr_state = ra->ratr_state;
}
}
- rcu_read_unlock();
}
static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw)
@@ -370,7 +384,8 @@ static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
ra->ratr_state = DM_RATR_STA_MAX;
ra->pre_ratr_state = DM_RATR_STA_MAX;
- if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER &&
+ hal_get_firmwareversion(rtlpriv) >= 60)
rtlpriv->dm.useramask = true;
else
rtlpriv->dm.useramask = false;
@@ -457,13 +472,13 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
digtable->back_val = DM_DIG_BACKOFF;
if ((digtable->rssi_val + 10 - digtable->back_val) >
- digtable->rx_gain_range_max)
+ digtable->rx_gain_max)
digtable->cur_igvalue =
- digtable->rx_gain_range_max;
+ digtable->rx_gain_max;
else if ((digtable->rssi_val + 10 - digtable->back_val)
- < digtable->rx_gain_range_min)
+ < digtable->rx_gain_min)
digtable->cur_igvalue =
- digtable->rx_gain_range_min;
+ digtable->rx_gain_min;
else
digtable->cur_igvalue = digtable->rssi_val + 10
- digtable->back_val;
@@ -475,7 +490,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
if (falsealm_cnt->cnt_all > 16000)
digtable->cur_igvalue =
- digtable->rx_gain_range_max;
+ digtable->rx_gain_max;
/* connected -> connected or disconnected -> disconnected */
} else {
/* Firmware control DIG, do nothing in driver dm */
@@ -677,9 +692,9 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)
/* for dig debug rssi value */
digtable->rssi_val = 50;
digtable->back_val = DM_DIG_BACKOFF;
- digtable->rx_gain_range_max = DM_DIG_MAX;
+ digtable->rx_gain_max = DM_DIG_MAX;
- digtable->rx_gain_range_min = DM_DIG_MIN;
+ digtable->rx_gain_min = DM_DIG_MIN;
digtable->backoffval_range_max = DM_DIG_BACKOFF_MAX;
digtable->backoffval_range_min = DM_DIG_BACKOFF_MIN;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
index 084e7773bce2..4f461786a7eb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -400,6 +400,39 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
+ case HW_VAR_FW_LPS_ACTION: {
+ bool enter_fwlps = *((bool *)val);
+ u8 rpwm_val, fw_pwrmode;
+ bool fw_current_inps;
+
+ if (enter_fwlps) {
+ rpwm_val = 0x02; /* RF off */
+ fw_current_inps = true;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ } else {
+ rpwm_val = 0x0C; /* RF on */
+ fw_pwrmode = FW_PS_ACTIVE_MODE;
+ fw_current_inps = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+ break; }
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case not processed\n");
@@ -438,7 +471,7 @@ void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw)
}
-static u8 _rtl92ce_halset_sysclk(struct ieee80211_hw *hw, u8 data)
+static u8 _rtl92se_halset_sysclk(struct ieee80211_hw *hw, u8 data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 waitcount = 100;
@@ -547,7 +580,7 @@ static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw)
tmpu1b &= ~(BIT(6) | BIT(7));
/* Set failed, return to prevent hang. */
- if (!_rtl92ce_halset_sysclk(hw, tmpu1b))
+ if (!_rtl92se_halset_sysclk(hw, tmpu1b))
return;
}
@@ -650,7 +683,7 @@ static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw)
tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6)));
- if (!_rtl92ce_halset_sysclk(hw, tmpu1b))
+ if (!_rtl92se_halset_sysclk(hw, tmpu1b))
return; /* Set failed, return to prevent hang. */
rtl_write_word(rtlpriv, CMDR, 0x07FC);
@@ -967,6 +1000,15 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
return rtstatus;
}
+ /* because last function modify RCR, so we update
+ * rcr var here, or TP will unstable for receive_config
+ * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+ * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
+ */
+ rtlpci->receive_config = rtl_read_dword(rtlpriv, RCR);
+ rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+ rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config);
+
/* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */
/* We must set flag avoid BB/RF config period later!! */
rtl_write_dword(rtlpriv, CMDR, 0x37FC);
@@ -982,25 +1024,6 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
- /* RF Power Save */
-#if 0
- /* H/W or S/W RF OFF before sleep. */
- if (rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) {
- u32 rfoffreason = rtlpriv->psc.rfoff_reason;
-
- rtlpriv->psc.rfoff_reason = RF_CHANGE_BY_INIT;
- rtlpriv->psc.rfpwr_state = ERFON;
- /* FIXME: check spinlocks if this block is uncommented */
- rtl_ps_set_rf_state(hw, ERFOFF, rfoffreason);
- } else {
- /* gpio radio on/off is out of adapter start */
- if (rtlpriv->psc.hwradiooff == false) {
- rtlpriv->psc.rfpwr_state = ERFON;
- rtlpriv->psc.rfoff_reason = 0;
- }
- }
-#endif
-
/* Before RF-R/W we must execute the IO from Scott's suggestion. */
rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, 0xDB);
if (rtlhal->version == VERSION_8192S_ACUT)
@@ -1058,7 +1081,22 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
/* We enable high power and RA related mechanism after NIC
* initialized. */
- rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT);
+ if (hal_get_firmwareversion(rtlpriv) >= 0x35) {
+ /* Fw v.53 and later. */
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT);
+ } else if (hal_get_firmwareversion(rtlpriv) == 0x34) {
+ /* Fw v.52. */
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_INIT);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ } else {
+ /* Compatible earlier FW version. */
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_RESET);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_ACTIVE);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_REFRESH);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ }
/* Add to prevent ASPM bug. */
/* Always enable hst and NIC clock request. */
@@ -1229,7 +1267,6 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
synchronize_irq(rtlpci->pdev->irq);
}
-
static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1754,7 +1791,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n",
rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
@@ -1791,11 +1828,11 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
((rtlefuse->eeprom_pwrgroup[rf_path][index] &
0xf0) >> 4);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
@@ -1850,27 +1887,27 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
rtlefuse->eeprom_regulatory =
(hwinfo[EEPROM_REGULATORY] & 0x1);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TxPwrSafetyFlag = %d\n", rtlefuse->txpwr_safetyflag);
/* Read RF-indication and Tx Power gain
@@ -1880,7 +1917,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
rtlefuse->legacy_httxpowerdiff =
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0];
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TxPowerDiff = %#x\n", rtlefuse->eeprom_txpowerdiff);
/* Get TSSI value for each path. */
@@ -1889,7 +1926,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
usvalue = hwinfo[EEPROM_TSSI_B];
rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -1897,7 +1934,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
/* and read ThermalMeter from EEPROM */
tempval = hwinfo[EEPROM_THERMALMETER];
rtlefuse->eeprom_thermalmeter = tempval;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
/* ThermalMeter, BIT(0)~3 for RFIC1, BIT(4)~7 for RFIC2 */
@@ -1914,7 +1951,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
/* Version ID, Channel plan */
rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
rtlefuse->txpwr_fromeprom = true;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"EEPROM ChannelPlan = 0x%4x\n", rtlefuse->eeprom_channelplan);
/* Read Customer ID or Board Type!!! */
@@ -1999,6 +2036,8 @@ static void rtl92se_update_hal_rate_table(struct ieee80211_hw *hw,
ratr_value = sta->supp_rates[1] << 4;
else
ratr_value = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_value = 0xfff;
ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
@@ -2112,6 +2151,8 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw,
ratr_bitmap = sta->supp_rates[1] << 4;
else
ratr_bitmap = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_bitmap = 0xfff;
ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
@@ -2200,6 +2241,7 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw,
ratr_bitmap &= 0x0f8ff0ff;
break;
}
+ sta_entry->ratr_index = ratr_index;
if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT)
ratr_bitmap &= 0x0FFFFFFF;
@@ -2438,23 +2480,9 @@ void rtl92se_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr,
rtl_cam_del_entry(hw, p_macaddr);
rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
} else {
- RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
- "The insert KEY length is %d\n",
- rtlpriv->sec.key_len[PAIRWISE_KEYIDX]);
- RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
- "The insert KEY is %x %x\n",
- rtlpriv->sec.key_buf[0][0],
- rtlpriv->sec.key_buf[0][1]);
-
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"add one entry\n");
if (is_pairwise) {
- RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD,
- "Pairwise Key content",
- rtlpriv->sec.pairwise_key,
- rtlpriv->sec.
- key_len[PAIRWISE_KEYIDX]);
-
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"set Pairwise key\n");
@@ -2502,3 +2530,23 @@ void rtl92se_resume(struct ieee80211_hw *hw)
pci_write_config_dword(rtlpci->pdev, 0x40,
val & 0xffff00ff);
}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl92se_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ if (allow_all_da) /* Set BIT0 */
+ rtlpci->receive_config |= RCR_AAP;
+ else /* Clear BIT0 */
+ rtlpci->receive_config &= ~RCR_AAP;
+
+ if (write_into_reg)
+ rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config);
+
+ RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+ "receive_config=0x%08X, write_into_reg=%d\n",
+ rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
index a8e068c76e47..da48aa8cbe6f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
@@ -74,6 +74,7 @@ void rtl92se_set_key(struct ieee80211_hw *hw,
u8 enc_algo, bool is_wepkey, bool clear_all);
void rtl92se_suspend(struct ieee80211_hw *hw);
void rtl92se_resume(struct ieee80211_hw *hw);
+void rtl92se_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg);
#endif
-
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
index 67404975e00b..9c092e6eb3fe 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
@@ -1307,6 +1307,8 @@ static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw)
if (is_hal_stop(rtlhal))
return;
+ if (hal_get_firmwareversion(rtlpriv) < 0x34)
+ goto skip;
/* We re-map RA related CMD IO to combinational ones */
/* if FW version is v.52 or later. */
switch (rtlhal->current_fwcmd_io) {
@@ -1320,6 +1322,7 @@ static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw)
break;
}
+skip:
switch (rtlhal->current_fwcmd_io) {
case FW_CMD_RA_RESET:
RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_RA_RESET\n");
@@ -1440,7 +1443,7 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u32 fw_param = FW_CMD_IO_PARA_QUERY(rtlpriv);
u16 fw_cmdmap = FW_CMD_IO_QUERY(rtlpriv);
- bool bPostProcessing = false;
+ bool postprocessing = false;
RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
"Set FW Cmd(%#x), set_fwcmd_inprogress(%d)\n",
@@ -1449,15 +1452,24 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
do {
/* We re-map to combined FW CMD ones if firmware version */
/* is v.53 or later. */
- switch (fw_cmdio) {
- case FW_CMD_RA_REFRESH_N:
- fw_cmdio = FW_CMD_RA_REFRESH_N_COMB;
- break;
- case FW_CMD_RA_REFRESH_BG:
- fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB;
- break;
- default:
- break;
+ if (hal_get_firmwareversion(rtlpriv) >= 0x35) {
+ switch (fw_cmdio) {
+ case FW_CMD_RA_REFRESH_N:
+ fw_cmdio = FW_CMD_RA_REFRESH_N_COMB;
+ break;
+ case FW_CMD_RA_REFRESH_BG:
+ fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB;
+ break;
+ default:
+ break;
+ }
+ } else {
+ if ((fw_cmdio == FW_CMD_IQK_ENABLE) ||
+ (fw_cmdio == FW_CMD_RA_REFRESH_N) ||
+ (fw_cmdio == FW_CMD_RA_REFRESH_BG)) {
+ postprocessing = true;
+ break;
+ }
}
/* If firmware version is v.62 or later,
@@ -1588,19 +1600,19 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
fw_cmdmap &= ~FW_DIG_ENABLE_CTL;
FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
- bPostProcessing = true;
+ postprocessing = true;
break;
case FW_CMD_PAUSE_DM_BY_SCAN:
fw_cmdmap &= ~(FW_DIG_ENABLE_CTL |
FW_HIGH_PWR_ENABLE_CTL |
FW_SS_CTL);
FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
- bPostProcessing = true;
+ postprocessing = true;
break;
case FW_CMD_HIGH_PWR_DISABLE:
fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL;
FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
- bPostProcessing = true;
+ postprocessing = true;
break;
case FW_CMD_HIGH_PWR_ENABLE:
if (!(rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) &&
@@ -1608,7 +1620,7 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
fw_cmdmap |= (FW_HIGH_PWR_ENABLE_CTL |
FW_SS_CTL);
FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
- bPostProcessing = true;
+ postprocessing = true;
}
break;
case FW_CMD_DIG_MODE_FA:
@@ -1629,14 +1641,15 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
default:
/* Pass to original FW CMD processing callback
* routine. */
- bPostProcessing = true;
+ postprocessing = true;
break;
}
} while (false);
/* We shall post processing these FW CMD if
- * variable bPostProcessing is set. */
- if (bPostProcessing && !rtlhal->set_fwcmd_inprogress) {
+ * variable postprocessing is set.
+ */
+ if (postprocessing && !rtlhal->set_fwcmd_inprogress) {
rtlhal->set_fwcmd_inprogress = true;
/* Update current FW Cmd for callback use. */
rtlhal->current_fwcmd_io = fw_cmdio;
@@ -1697,8 +1710,18 @@ void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw)
}
-void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 BeaconInterval)
+void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 beaconinterval)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- rtl_write_dword(rtlpriv, WFM5, 0xF1000000 | (BeaconInterval << 8));
+ u32 new_bcn_num = 0;
+
+ if (hal_get_firmwareversion(rtlpriv) >= 0x33) {
+ /* Fw v.51 and later. */
+ rtl_write_dword(rtlpriv, WFM5, 0xF1000000 |
+ (beaconinterval << 8));
+ } else {
+ new_bcn_num = beaconinterval * 32 - 64;
+ rtl_write_dword(rtlpriv, WFM3 + 4, new_bcn_num);
+ rtl_write_dword(rtlpriv, WFM3, 0xB026007C);
+ }
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
index ac0387770630..8acf4765a7a6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
@@ -39,6 +39,7 @@
#define MAX_POSTCMD_CNT 16
#define RF90_PATH_MAX 4
+#define RF6052_MAX_PATH 2
enum version_8192s {
VERSION_8192S_ACUT,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
index cecc377e9e61..2e8e6f8d2d51 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -290,6 +290,7 @@ static struct rtl_hal_ops rtl8192se_hal_ops = {
.enable_hw_sec = rtl92se_enable_hw_security_config,
.set_key = rtl92se_set_key,
.init_sw_leds = rtl92se_init_sw_leds,
+ .allow_all_destaddr = rtl92se_allow_all_destaddr,
.get_bbreg = rtl92s_phy_query_bb_reg,
.set_bbreg = rtl92s_phy_set_bb_reg,
.get_rfreg = rtl92s_phy_query_rf_reg,
@@ -366,7 +367,7 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNINT,
.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
.maps[RTL_IMR_RDU] = IMR_RDU,
.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 7b0a2e75b8b8..960bc28cc51e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../pci.h"
#include "../base.h"
+#include "../stats.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -43,7 +44,7 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue)
if (unlikely(ieee80211_is_beacon(fc)))
return QSLT_BEACON;
- if (ieee80211_is_mgmt(fc))
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
return QSLT_MGNT;
if (ieee80211_is_nullfunc(fc))
return QSLT_HIGH;
@@ -51,65 +52,6 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue)
return skb->priority;
}
-static u8 _rtl92s_query_rxpwrpercentage(char antpower)
-{
- if ((antpower <= -100) || (antpower >= 20))
- return 0;
- else if (antpower >= 0)
- return 100;
- else
- return 100 + antpower;
-}
-
-static u8 _rtl92s_evm_db_to_percentage(char value)
-{
- char ret_val;
- ret_val = value;
-
- if (ret_val >= 0)
- ret_val = 0;
-
- if (ret_val <= -33)
- ret_val = -33;
-
- ret_val = 0 - ret_val;
- ret_val *= 3;
-
- if (ret_val == 99)
- ret_val = 100;
-
- return ret_val;
-}
-
-static long _rtl92se_translate_todbm(struct ieee80211_hw *hw,
- u8 signal_strength_index)
-{
- long signal_power;
-
- signal_power = (long)((signal_strength_index + 1) >> 1);
- signal_power -= 95;
- return signal_power;
-}
-
-static long _rtl92se_signal_scale_mapping(struct ieee80211_hw *hw,
- long currsig)
-{
- long retsig = 0;
-
- /* Step 1. Scale mapping. */
- if (currsig > 47)
- retsig = 100;
- else if (currsig > 14 && currsig <= 47)
- retsig = 100 - ((47 - currsig) * 3) / 2;
- else if (currsig > 2 && currsig <= 14)
- retsig = 48 - ((14 - currsig) * 15) / 7;
- else if (currsig >= 0)
- retsig = currsig * 9 + 1;
-
- return retsig;
-}
-
-
static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
struct rtl_stats *pstats, u8 *pdesc,
struct rx_fwinfo *p_drvinfo,
@@ -119,11 +61,11 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct phy_sts_cck_8192s_t *cck_buf;
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
s8 rx_pwr_all = 0, rx_pwr[4];
u8 rf_rx_num = 0, evm, pwdb_all;
u8 i, max_spatial_stream;
u32 rssi, total_rssi = 0;
- bool in_powersavemode = false;
bool is_cck = pstats->is_cck;
pstats->packet_matchbssid = packet_match_bssid;
@@ -136,7 +78,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
u8 report, cck_highpwr;
cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
- if (!in_powersavemode)
+ if (ppsc->rfpwr_state == ERFON)
cck_highpwr = (u8) rtl_get_bbreg(hw,
RFPGA0_XA_HSSIPARAMETER2,
0x200);
@@ -181,7 +123,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
}
}
- pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all);
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
/* CCK gain is smaller than OFDM/MCS gain, */
/* so we add gain diff by experiences, the val is 6 */
@@ -222,13 +164,13 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
} else {
rtlpriv->dm.rfpath_rxenable[0] =
rtlpriv->dm.rfpath_rxenable[1] = true;
- for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
+ for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
if (rtlpriv->dm.rfpath_rxenable[i])
rf_rx_num++;
rx_pwr[i] = ((p_drvinfo->gain_trsw[i] &
0x3f) * 2) - 110;
- rssi = _rtl92s_query_rxpwrpercentage(rx_pwr[i]);
+ rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
total_rssi += rssi;
rtlpriv->stats.rx_snr_db[i] =
(long)(p_drvinfo->rxsnr[i] / 2);
@@ -238,7 +180,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
}
rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
- pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all);
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
pstats->rx_pwdb_all = pwdb_all;
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
@@ -250,7 +192,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
max_spatial_stream = 1;
for (i = 0; i < max_spatial_stream; i++) {
- evm = _rtl92s_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+ evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]);
if (packet_match_bssid) {
if (i == 0)
@@ -262,212 +204,13 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
}
if (is_cck)
- pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw,
+ pstats->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
pwdb_all));
else if (rf_rx_num != 0)
- pstats->signalstrength = (u8) (_rtl92se_signal_scale_mapping(hw,
+ pstats->signalstrength = (u8) (rtl_signal_scale_mapping(hw,
total_rssi /= rf_rx_num));
}
-static void _rtl92se_process_ui_rssi(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
- u8 rfpath;
- u32 last_rssi, tmpval;
-
- if (pstats->packet_toself || pstats->packet_beacon) {
- rtlpriv->stats.rssi_calculate_cnt++;
-
- if (rtlpriv->stats.ui_rssi.total_num++ >=
- PHY_RSSI_SLID_WIN_MAX) {
- rtlpriv->stats.ui_rssi.total_num =
- PHY_RSSI_SLID_WIN_MAX;
- last_rssi = rtlpriv->stats.ui_rssi.elements[
- rtlpriv->stats.ui_rssi.index];
- rtlpriv->stats.ui_rssi.total_val -= last_rssi;
- }
-
- rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength;
- rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++]
- = pstats->signalstrength;
-
- if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
- rtlpriv->stats.ui_rssi.index = 0;
-
- tmpval = rtlpriv->stats.ui_rssi.total_val /
- rtlpriv->stats.ui_rssi.total_num;
- rtlpriv->stats.signal_strength = _rtl92se_translate_todbm(hw,
- (u8) tmpval);
- pstats->rssi = rtlpriv->stats.signal_strength;
- }
-
- if (!pstats->is_cck && pstats->packet_toself) {
- for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
- rfpath++) {
- if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- pstats->rx_mimo_signalstrength[rfpath];
-
- }
-
- if (pstats->rx_mimo_signalstrength[rfpath] >
- rtlpriv->stats.rx_rssi_percentage[rfpath]) {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- ((rtlpriv->stats.rx_rssi_percentage[rfpath]
- * (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_signalstrength[rfpath])) /
- (RX_SMOOTH_FACTOR);
-
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- rtlpriv->stats.rx_rssi_percentage[rfpath]
- + 1;
- } else {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- ((rtlpriv->stats.rx_rssi_percentage[rfpath]
- * (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_signalstrength[rfpath])) /
- (RX_SMOOTH_FACTOR);
- }
-
- }
- }
-}
-
-static void _rtl92se_update_rxsignalstatistics(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- int weighting = 0;
-
- if (rtlpriv->stats.recv_signal_power == 0)
- rtlpriv->stats.recv_signal_power = pstats->recvsignalpower;
-
- if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power)
- weighting = 5;
- else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power)
- weighting = (-5);
-
- rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 5
- + pstats->recvsignalpower +
- weighting) / 6;
-}
-
-static void _rtl92se_process_pwdb(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- long undec_sm_pwdb = 0;
-
- if (mac->opmode == NL80211_IFTYPE_ADHOC) {
- return;
- } else {
- undec_sm_pwdb =
- rtlpriv->dm.undec_sm_pwdb;
- }
-
- if (pstats->packet_toself || pstats->packet_beacon) {
- if (undec_sm_pwdb < 0)
- undec_sm_pwdb = pstats->rx_pwdb_all;
-
- if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
- undec_sm_pwdb =
- (((undec_sm_pwdb) *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-
- undec_sm_pwdb = undec_sm_pwdb + 1;
- } else {
- undec_sm_pwdb = (((undec_sm_pwdb) *
- (RX_SMOOTH_FACTOR - 1)) + (pstats->rx_pwdb_all)) /
- (RX_SMOOTH_FACTOR);
- }
-
- rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
- _rtl92se_update_rxsignalstatistics(hw, pstats);
- }
-}
-
-static void rtl_92s_process_streams(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 stream;
-
- for (stream = 0; stream < 2; stream++) {
- if (pstats->rx_mimo_sig_qual[stream] != -1) {
- if (rtlpriv->stats.rx_evm_percentage[stream] == 0) {
- rtlpriv->stats.rx_evm_percentage[stream] =
- pstats->rx_mimo_sig_qual[stream];
- }
-
- rtlpriv->stats.rx_evm_percentage[stream] =
- ((rtlpriv->stats.rx_evm_percentage[stream] *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_sig_qual[stream] *
- 1)) / (RX_SMOOTH_FACTOR);
- }
- }
-}
-
-static void _rtl92se_process_ui_link_quality(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 last_evm = 0, tmpval;
-
- if (pstats->signalquality != 0) {
- if (pstats->packet_toself || pstats->packet_beacon) {
-
- if (rtlpriv->stats.ui_link_quality.total_num++ >=
- PHY_LINKQUALITY_SLID_WIN_MAX) {
- rtlpriv->stats.ui_link_quality.total_num =
- PHY_LINKQUALITY_SLID_WIN_MAX;
- last_evm =
- rtlpriv->stats.ui_link_quality.elements[
- rtlpriv->stats.ui_link_quality.index];
- rtlpriv->stats.ui_link_quality.total_val -=
- last_evm;
- }
-
- rtlpriv->stats.ui_link_quality.total_val +=
- pstats->signalquality;
- rtlpriv->stats.ui_link_quality.elements[
- rtlpriv->stats.ui_link_quality.index++] =
- pstats->signalquality;
-
- if (rtlpriv->stats.ui_link_quality.index >=
- PHY_LINKQUALITY_SLID_WIN_MAX)
- rtlpriv->stats.ui_link_quality.index = 0;
-
- tmpval = rtlpriv->stats.ui_link_quality.total_val /
- rtlpriv->stats.ui_link_quality.total_num;
- rtlpriv->stats.signal_quality = tmpval;
-
- rtlpriv->stats.last_sigstrength_inpercent = tmpval;
-
- rtl_92s_process_streams(hw, pstats);
-
- }
- }
-}
-
-static void _rtl92se_process_phyinfo(struct ieee80211_hw *hw,
- u8 *buffer,
- struct rtl_stats *pcurrent_stats)
-{
-
- if (!pcurrent_stats->packet_matchbssid &&
- !pcurrent_stats->packet_beacon)
- return;
-
- _rtl92se_process_ui_rssi(hw, pcurrent_stats);
- _rtl92se_process_pwdb(hw, pcurrent_stats);
- _rtl92se_process_ui_link_quality(hw, pcurrent_stats);
-}
-
static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_stats *pstats,
u8 *pdesc, struct rx_fwinfo *p_drvinfo)
@@ -505,7 +248,7 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
_rtl92se_query_rxphystatus(hw, pstats, pdesc, p_drvinfo,
packet_matchbssid, packet_toself, packet_beacon);
- _rtl92se_process_phyinfo(hw, tmp_buf, pstats);
+ rtl_process_phyinfo(hw, tmp_buf, pstats);
}
bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
@@ -541,9 +284,6 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
rx_status->freq = hw->conf.channel->center_freq;
rx_status->band = hw->conf.channel->band;
- hdr = (struct ieee80211_hdr *)(skb->data + stats->rx_drvinfo_size
- + stats->rx_bufshift);
-
if (stats->crc)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
@@ -563,6 +303,13 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
* for IEEE80211w frame, and mac80211 sw will help
* to decrypt it */
if (stats->decrypted) {
+ hdr = (struct ieee80211_hdr *)(skb->data +
+ stats->rx_drvinfo_size + stats->rx_bufshift);
+
+ if (!hdr) {
+ /* during testing, hdr was NULL here */
+ return false;
+ }
if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
(ieee80211_has_protected(hdr->frame_control)))
rx_status->flag &= ~RX_FLAG_DECRYPTED;
@@ -630,6 +377,11 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE_RTL8192S);
+ if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+ firstseg = true;
+ lastseg = true;
+ }
+
if (firstseg) {
if (rtlpriv->dm.useramask) {
/* set txdesc macId */
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
index 12e2a3cb0701..a36eee28f9e7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
@@ -166,8 +166,8 @@ static void rtl8723ae_dm_diginit(struct ieee80211_hw *hw)
dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_digtable->rx_gain_range_max = DM_DIG_MAX;
- dm_digtable->rx_gain_range_min = DM_DIG_MIN;
+ dm_digtable->rx_gain_max = DM_DIG_MAX;
+ dm_digtable->rx_gain_min = DM_DIG_MIN;
dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
@@ -291,11 +291,11 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
}
if ((dgtbl->rssi_val_min + 10 - dgtbl->back_val) >
- dgtbl->rx_gain_range_max)
- dgtbl->cur_igvalue = dgtbl->rx_gain_range_max;
+ dgtbl->rx_gain_max)
+ dgtbl->cur_igvalue = dgtbl->rx_gain_max;
else if ((dgtbl->rssi_val_min + 10 -
- dgtbl->back_val) < dgtbl->rx_gain_range_min)
- dgtbl->cur_igvalue = dgtbl->rx_gain_range_min;
+ dgtbl->back_val) < dgtbl->rx_gain_min)
+ dgtbl->cur_igvalue = dgtbl->rx_gain_min;
else
dgtbl->cur_igvalue = dgtbl->rssi_val_min + 10 - dgtbl->back_val;
@@ -707,6 +707,77 @@ void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
rtlpriv->dm.useramask = false;
}
+static void rtl8723ae_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rate_adaptive *p_ra = &(rtlpriv->ra);
+ u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
+ struct ieee80211_sta *sta = NULL;
+
+ if (is_hal_stop(rtlhal)) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ " driver is going to unload\n");
+ return;
+ }
+
+ if (!rtlpriv->dm.useramask) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ " driver does not control rate adaptive mask\n");
+ return;
+ }
+
+ if (mac->link_state == MAC80211_LINKED &&
+ mac->opmode == NL80211_IFTYPE_STATION) {
+ switch (p_ra->pre_ratr_state) {
+ case DM_RATR_STA_HIGH:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 20;
+ break;
+ case DM_RATR_STA_MIDDLE:
+ high_rssithresh_for_ra = 55;
+ low_rssithresh_for_ra = 20;
+ break;
+ case DM_RATR_STA_LOW:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 25;
+ break;
+ default:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 20;
+ break;
+ }
+
+ if (rtlpriv->dm.undec_sm_pwdb > high_rssithresh_for_ra)
+ p_ra->ratr_state = DM_RATR_STA_HIGH;
+ else if (rtlpriv->dm.undec_sm_pwdb > low_rssithresh_for_ra)
+ p_ra->ratr_state = DM_RATR_STA_MIDDLE;
+ else
+ p_ra->ratr_state = DM_RATR_STA_LOW;
+
+ if (p_ra->pre_ratr_state != p_ra->ratr_state) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI = %ld\n",
+ rtlpriv->dm.undec_sm_pwdb);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI_LEVEL = %d\n", p_ra->ratr_state);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "PreState = %d, CurState = %d\n",
+ p_ra->pre_ratr_state, p_ra->ratr_state);
+
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, mac->bssid);
+ if (sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ p_ra->ratr_state);
+ rcu_read_unlock();
+
+ p_ra->pre_ratr_state = p_ra->ratr_state;
+ }
+ }
+}
+
static void rtl8723ae_dm_init_dynamic_bpowersaving(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -853,6 +924,9 @@ void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
(u8 *) (&fw_ps_awake));
+ if (ppsc->p2p_ps_info.p2p_ps_mode)
+ fw_ps_awake = false;
+
if ((ppsc->rfpwr_state == ERFON) &&
((!fw_current_inpsmode) && fw_ps_awake) &&
(!ppsc->rfchange_inprogress)) {
@@ -861,7 +935,7 @@ void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
rtl8723ae_dm_false_alarm_counter_statistics(hw);
rtl8723ae_dm_dynamic_bpowersaving(hw);
rtl8723ae_dm_dynamic_txpower(hw);
- /* rtl92c_dm_refresh_rate_adaptive_mask(hw); */
+ rtl8723ae_dm_refresh_rate_adaptive_mask(hw);
rtl8723ae_dm_bt_coexist(hw);
rtl8723ae_dm_check_edca_turbo(hw);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
index 39d246196247..a372b0204456 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
@@ -55,7 +55,13 @@
#define DM_DIG_BACKOFF_MIN -4
#define DM_DIG_BACKOFF_DEFAULT 10
+#define RXPATHSELECTION_SS_TH_LOW 30
+#define RXPATHSELECTION_DIFF_TH 18
+
#define DM_RATR_STA_INIT 0
+#define DM_RATR_STA_HIGH 1
+#define DM_RATR_STA_MIDDLE 2
+#define DM_RATR_STA_LOW 3
#define TXHIGHPWRLEVEL_NORMAL 0
#define TXHIGHPWRLEVEL_LEVEL1 1
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
index 35cb8f83eed4..dedfa1ed3e02 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
@@ -494,7 +494,9 @@ void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
- SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+ (rtlpriv->mac80211.p2p) ?
+ ppsc->smart_ps : 1);
SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
ppsc->reg_max_lps_awakeintvl);
@@ -741,3 +743,96 @@ void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
rtl8723ae_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
}
+
+static void rtl8723e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
+ u8 ctwindow)
+{
+ u8 u1_ctwindow_period[1] = {ctwindow};
+
+ rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+}
+
+void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
+ struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+ u8 i;
+ u16 ctwindow;
+ u32 start_time, tsf_low;
+
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+ memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+ break;
+ case P2P_PS_ENABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+ /* update CTWindow value. */
+ if (p2pinfo->ctwindow > 0) {
+ p2p_ps_offload->ctwindow_en = 1;
+ ctwindow = p2pinfo->ctwindow;
+ rtl8723e_set_p2p_ctw_period_cmd(hw, ctwindow);
+ }
+
+ /* hw only support 2 set of NoA */
+ for (i = 0; i < p2pinfo->noa_num; i++) {
+ /* To control the register setting for which NOA*/
+ rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+ if (i == 0)
+ p2p_ps_offload->noa0_en = 1;
+ else
+ p2p_ps_offload->noa1_en = 1;
+
+ /* config P2P NoA Descriptor Register */
+ rtl_write_dword(rtlpriv, 0x5E0,
+ p2pinfo->noa_duration[i]);
+ rtl_write_dword(rtlpriv, 0x5E4,
+ p2pinfo->noa_interval[i]);
+
+ /*Get Current TSF value */
+ tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ start_time = p2pinfo->noa_start_time[i];
+ if (p2pinfo->noa_count_type[i] != 1) {
+ while (start_time <= (tsf_low+(50*1024))) {
+ start_time += p2pinfo->noa_interval[i];
+ if (p2pinfo->noa_count_type[i] != 255)
+ p2pinfo->noa_count_type[i]--;
+ }
+ }
+ rtl_write_dword(rtlpriv, 0x5E8, start_time);
+ rtl_write_dword(rtlpriv, 0x5EC,
+ p2pinfo->noa_count_type[i]);
+ }
+ if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+ /* rst p2p circuit */
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+ p2p_ps_offload->offload_en = 1;
+
+ if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+ p2p_ps_offload->role = 1;
+ p2p_ps_offload->allstasleep = 0;
+ } else {
+ p2p_ps_offload->role = 0;
+ }
+ p2p_ps_offload->discovery = 0;
+ }
+ break;
+ case P2P_PS_SCAN:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+ p2p_ps_offload->discovery = 1;
+ break;
+ case P2P_PS_SCAN_DONE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+ p2p_ps_offload->discovery = 0;
+ p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+ break;
+ default:
+ break;
+ }
+ rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
index 89994e16dc83..ed3b795e6980 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
@@ -70,8 +70,10 @@ enum rtl8192c_h2c_cmd {
H2C_SETPWRMODE = 1,
H2C_JOINBSSRPT = 2,
H2C_RSVDPAGE = 3,
- H2C_RSSI_REPORT = 5,
- H2C_RA_MASK = 6,
+ H2C_RSSI_REPORT = 4,
+ H2C_P2P_PS_CTW_CMD = 5,
+ H2C_P2P_PS_OFFLOAD = 6,
+ H2C_RA_MASK = 7,
MAX_H2CCMD
};
@@ -97,5 +99,6 @@ void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw);
void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
+void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
index 9a0c71c2e15e..c333dfd116b8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
@@ -449,6 +449,9 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtl8723ae_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
break; }
+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+ rtl8723ae_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ break;
case HW_VAR_AID:{
u16 u2btmp;
u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
@@ -474,6 +477,39 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
if (btype_ibss == true)
_rtl8723ae_resume_tx_beacon(hw);
break; }
+ case HW_VAR_FW_LPS_ACTION: {
+ bool enter_fwlps = *((bool *)val);
+ u8 rpwm_val, fw_pwrmode;
+ bool fw_current_inps;
+
+ if (enter_fwlps) {
+ rpwm_val = 0x02; /* RF off */
+ fw_current_inps = true;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ } else {
+ rpwm_val = 0x0C; /* RF on */
+ fw_pwrmode = FW_PS_ACTIVE_MODE;
+ fw_current_inps = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+ break; }
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case not processed\n");
@@ -1379,7 +1415,7 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = "
"[0x%x / 0x%x / 0x%x]\n", rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
@@ -1420,10 +1456,10 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
0xf0) >> 4);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n", rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n", rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
}
@@ -1463,19 +1499,19 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i,
rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i,
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i,
rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i,
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
@@ -1483,14 +1519,14 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
else
rtlefuse->eeprom_regulatory = 0;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
if (!autoload_fail)
rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
else
rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -1505,7 +1541,7 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->apk_thermalmeterignore = true;
rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
}
@@ -1713,19 +1749,7 @@ static void _rtl8723ae_hal_customized_behavior(struct ieee80211_hw *hw)
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- switch (rtlhal->oem_id) {
- case RT_CID_819x_HP:
- pcipriv->ledctl.led_opendrain = true;
- break;
- case RT_CID_819x_Lenovo:
- case RT_CID_DEFAULT:
- case RT_CID_TOSHIBA:
- case RT_CID_CCX:
- case RT_CID_819x_Acer:
- case RT_CID_WHQL:
- default:
- break;
- }
+ pcipriv->ledctl.led_opendrain = true;
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"RT Customized ID: 0x%02X\n", rtlhal->oem_id);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/led.c b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
index 9c4e1d811187..061526fe6e2d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
@@ -54,8 +54,9 @@ void rtl8723ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
case LED_PIN_GPIO0:
break;
case LED_PIN_LED0:
+ ledcfg &= ~BIT(6);
rtl_write_byte(rtlpriv,
- REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6));
+ REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5));
break;
case LED_PIN_LED1:
rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5));
@@ -84,16 +85,21 @@ void rtl8723ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
break;
case LED_PIN_LED0:
ledcfg &= 0xf0;
- if (pcipriv->ledctl.led_opendrain)
+ if (pcipriv->ledctl.led_opendrain) {
+ ledcfg &= 0x90;
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3)));
+ ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
+ ledcfg &= 0xFE;
+ rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg);
+ } else {
+ ledcfg &= ~BIT(6);
rtl_write_byte(rtlpriv, REG_LEDCFG2,
- (ledcfg | BIT(1) | BIT(5) | BIT(6)));
- else
- rtl_write_byte(rtlpriv, REG_LEDCFG2,
- (ledcfg | BIT(3) | BIT(5) | BIT(6)));
+ (ledcfg | BIT(3) | BIT(5)));
+ }
break;
case LED_PIN_LED1:
- ledcfg &= 0x0f;
- rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3)));
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1) & 0x10;
+ rtl_write_byte(rtlpriv, REG_LEDCFG1, (ledcfg | BIT(3)));
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
index bb7cc90bafb2..e4c4cdc3eb67 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
@@ -305,7 +305,7 @@ static struct rtl_hal_cfg rtl8723ae_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = PHIMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = PHIMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = PHIMR_BCNDMAINT0,
+ .maps[RTL_IMR_BCNINT] = PHIMR_BCNDMAINT0,
.maps[RTL_IMR_RXFOVW] = PHIMR_RXFOVW,
.maps[RTL_IMR_RDU] = PHIMR_RDU,
.maps[RTL_IMR_ATIMEND] = PHIMR_ATIMEND_E,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
index ac081297db50..6c64365308d3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -307,9 +307,6 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
rx_status->freq = hw->conf.channel->center_freq;
rx_status->band = hw->conf.channel->band;
- hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size
- + status->rx_bufshift);
-
if (status->crc)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
@@ -330,6 +327,13 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
* to decrypt it
*/
if (status->decrypted) {
+ hdr = (struct ieee80211_hdr *)(skb->data +
+ status->rx_drvinfo_size + status->rx_bufshift);
+
+ if (!hdr) {
+ /* during testing, hdr could be NULL here */
+ return false;
+ }
if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
(ieee80211_has_protected(hdr->frame_control)))
rx_status->flag &= ~RX_FLAG_DECRYPTED;
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 41dce83ff41a..83915dcd0e58 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -308,6 +308,8 @@ static int _rtl_usb_init_tx(struct ieee80211_hw *hw)
return 0;
}
+static void _rtl_rx_work(unsigned long param);
+
static int _rtl_usb_init_rx(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -324,6 +326,12 @@ static int _rtl_usb_init_rx(struct ieee80211_hw *hw)
pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n",
rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep);
init_usb_anchor(&rtlusb->rx_submitted);
+ init_usb_anchor(&rtlusb->rx_cleanup_urbs);
+
+ skb_queue_head_init(&rtlusb->rx_queue);
+ rtlusb->rx_work_tasklet.func = _rtl_rx_work;
+ rtlusb->rx_work_tasklet.data = (unsigned long)rtlusb;
+
return 0;
}
@@ -405,40 +413,30 @@ static void rtl_usb_init_sw(struct ieee80211_hw *hw)
rtlusb->disableHWSM = true;
}
-#define __RADIO_TAP_SIZE_RSV 32
-
static void _rtl_rx_completed(struct urb *urb);
-static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw,
- struct rtl_usb *rtlusb,
- struct urb *urb,
- gfp_t gfp_mask)
+static int _rtl_prep_rx_urb(struct ieee80211_hw *hw, struct rtl_usb *rtlusb,
+ struct urb *urb, gfp_t gfp_mask)
{
- struct sk_buff *skb;
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ void *buf;
- skb = __dev_alloc_skb((rtlusb->rx_max_size + __RADIO_TAP_SIZE_RSV),
- gfp_mask);
- if (!skb) {
+ buf = usb_alloc_coherent(rtlusb->udev, rtlusb->rx_max_size, gfp_mask,
+ &urb->transfer_dma);
+ if (!buf) {
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
- "Failed to __dev_alloc_skb!!\n");
- return ERR_PTR(-ENOMEM);
+ "Failed to usb_alloc_coherent!!\n");
+ return -ENOMEM;
}
- /* reserve some space for mac80211's radiotap */
- skb_reserve(skb, __RADIO_TAP_SIZE_RSV);
usb_fill_bulk_urb(urb, rtlusb->udev,
usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep),
- skb->data, min(skb_tailroom(skb),
- (int)rtlusb->rx_max_size),
- _rtl_rx_completed, skb);
+ buf, rtlusb->rx_max_size, _rtl_rx_completed, rtlusb);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep);
- return skb;
+ return 0;
}
-#undef __RADIO_TAP_SIZE_RSV
-
static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
@@ -522,22 +520,11 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw,
if (unicast)
rtlpriv->link_info.num_rx_inperiod++;
}
- if (likely(rtl_action_proc(hw, skb, false))) {
- struct sk_buff *uskb = NULL;
- u8 *pdata;
-
- uskb = dev_alloc_skb(skb->len + 128);
- if (uskb) { /* drop packet on allocation failure */
- memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status,
- sizeof(rx_status));
- pdata = (u8 *)skb_put(uskb, skb->len);
- memcpy(pdata, skb->data, skb->len);
- ieee80211_rx_irqsafe(hw, uskb);
- }
- dev_kfree_skb_any(skb);
- } else {
+
+ if (likely(rtl_action_proc(hw, skb, false)))
+ ieee80211_rx(hw, skb);
+ else
dev_kfree_skb_any(skb);
- }
}
}
@@ -554,15 +541,70 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb)
while (!skb_queue_empty(&rx_queue)) {
_skb = skb_dequeue(&rx_queue);
_rtl_usb_rx_process_agg(hw, _skb);
- ieee80211_rx_irqsafe(hw, _skb);
+ ieee80211_rx(hw, _skb);
}
}
+#define __RX_SKB_MAX_QUEUED 32
+
+static void _rtl_rx_work(unsigned long param)
+{
+ struct rtl_usb *rtlusb = (struct rtl_usb *)param;
+ struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf);
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&rtlusb->rx_queue))) {
+ if (unlikely(IS_USB_STOP(rtlusb))) {
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ if (likely(!rtlusb->usb_rx_segregate_hdl)) {
+ _rtl_usb_rx_process_noagg(hw, skb);
+ } else {
+ /* TO DO */
+ _rtl_rx_pre_process(hw, skb);
+ pr_err("rx agg not supported\n");
+ }
+ }
+}
+
+static unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr,
+ unsigned int len)
+{
+ unsigned int padding = 0;
+
+ /* make function no-op when possible */
+ if (NET_IP_ALIGN == 0 || len < sizeof(*hdr))
+ return 0;
+
+ /* alignment calculation as in lbtf_rx() / carl9170_rx_copy_data() */
+ /* TODO: deduplicate common code, define helper function instead? */
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+
+ padding ^= NET_IP_ALIGN;
+
+ /* Input might be invalid, avoid accessing memory outside
+ * the buffer.
+ */
+ if ((unsigned long)qc - (unsigned long)hdr < len &&
+ *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
+ padding ^= NET_IP_ALIGN;
+ }
+
+ if (ieee80211_has_a4(hdr->frame_control))
+ padding ^= NET_IP_ALIGN;
+
+ return padding;
+}
+
+#define __RADIO_TAP_SIZE_RSV 32
+
static void _rtl_rx_completed(struct urb *_urb)
{
- struct sk_buff *skb = (struct sk_buff *)_urb->context;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0];
+ struct rtl_usb *rtlusb = (struct rtl_usb *)_urb->context;
struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf);
struct rtl_priv *rtlpriv = rtl_priv(hw);
int err = 0;
@@ -571,28 +613,50 @@ static void _rtl_rx_completed(struct urb *_urb)
goto free;
if (likely(0 == _urb->status)) {
- /* If this code were moved to work queue, would CPU
- * utilization be improved? NOTE: We shall allocate another skb
- * and reuse the original one.
- */
- skb_put(skb, _urb->actual_length);
+ unsigned int padding;
+ struct sk_buff *skb;
+ unsigned int qlen;
+ unsigned int size = _urb->actual_length;
+ struct ieee80211_hdr *hdr;
- if (likely(!rtlusb->usb_rx_segregate_hdl)) {
- struct sk_buff *_skb;
- _rtl_usb_rx_process_noagg(hw, skb);
- _skb = _rtl_prep_rx_urb(hw, rtlusb, _urb, GFP_ATOMIC);
- if (IS_ERR(_skb)) {
- err = PTR_ERR(_skb);
- RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
- "Can't allocate skb for bulk IN!\n");
- return;
- }
- skb = _skb;
- } else{
- /* TO DO */
- _rtl_rx_pre_process(hw, skb);
- pr_err("rx agg not supported\n");
+ if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) {
+ RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
+ "Too short packet from bulk IN! (len: %d)\n",
+ size);
+ goto resubmit;
+ }
+
+ qlen = skb_queue_len(&rtlusb->rx_queue);
+ if (qlen >= __RX_SKB_MAX_QUEUED) {
+ RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
+ "Pending RX skbuff queue full! (qlen: %d)\n",
+ qlen);
+ goto resubmit;
}
+
+ hdr = (void *)(_urb->transfer_buffer + RTL_RX_DESC_SIZE);
+ padding = _rtl_rx_get_padding(hdr, size - RTL_RX_DESC_SIZE);
+
+ skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV + padding);
+ if (!skb) {
+ RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
+ "Can't allocate skb for bulk IN!\n");
+ goto resubmit;
+ }
+
+ _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep);
+
+ /* Make sure the payload data is 4 byte aligned. */
+ skb_reserve(skb, padding);
+
+ /* reserve some space for mac80211's radiotap */
+ skb_reserve(skb, __RADIO_TAP_SIZE_RSV);
+
+ memcpy(skb_put(skb, size), _urb->transfer_buffer, size);
+
+ skb_queue_tail(&rtlusb->rx_queue, skb);
+ tasklet_schedule(&rtlusb->rx_work_tasklet);
+
goto resubmit;
}
@@ -608,9 +672,6 @@ static void _rtl_rx_completed(struct urb *_urb)
}
resubmit:
- skb_reset_tail_pointer(skb);
- skb_trim(skb, 0);
-
usb_anchor_urb(_urb, &rtlusb->rx_submitted);
err = usb_submit_urb(_urb, GFP_ATOMIC);
if (unlikely(err)) {
@@ -620,13 +681,34 @@ resubmit:
return;
free:
- dev_kfree_skb_irq(skb);
+ /* On some architectures, usb_free_coherent must not be called from
+ * hardirq context. Queue urb to cleanup list.
+ */
+ usb_anchor_urb(_urb, &rtlusb->rx_cleanup_urbs);
+}
+
+#undef __RADIO_TAP_SIZE_RSV
+
+static void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw)
+{
+ struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
+ struct urb *urb;
+
+ usb_kill_anchored_urbs(&rtlusb->rx_submitted);
+
+ tasklet_kill(&rtlusb->rx_work_tasklet);
+ skb_queue_purge(&rtlusb->rx_queue);
+
+ while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) {
+ usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ }
}
static int _rtl_usb_receive(struct ieee80211_hw *hw)
{
struct urb *urb;
- struct sk_buff *skb;
int err;
int i;
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -645,11 +727,10 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
goto err_out;
}
- skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL);
- if (IS_ERR(skb)) {
+ err = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL);
+ if (err < 0) {
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
"Failed to prep_rx_urb!!\n");
- err = PTR_ERR(skb);
usb_free_urb(urb);
goto err_out;
}
@@ -664,6 +745,7 @@ 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;
}
@@ -705,7 +787,7 @@ static void rtl_usb_cleanup(struct ieee80211_hw *hw)
SET_USB_STOP(rtlusb);
/* clean up rx stuff. */
- usb_kill_anchored_urbs(&rtlusb->rx_submitted);
+ _rtl_usb_cleanup_rx(hw);
/* clean up tx stuff */
for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) {
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h
index fb986f98d1df..685273ca9561 100644
--- a/drivers/net/wireless/rtlwifi/usb.h
+++ b/drivers/net/wireless/rtlwifi/usb.h
@@ -136,11 +136,14 @@ struct rtl_usb {
void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *);
/* Rx */
- u8 in_ep_nums ;
+ u8 in_ep_nums;
u32 in_ep; /* Bulk IN endpoint number */
u32 rx_max_size; /* Bulk IN max buffer size */
u32 rx_urb_num; /* How many Bulk INs are submitted to host. */
struct usb_anchor rx_submitted;
+ struct usb_anchor rx_cleanup_urbs;
+ struct tasklet_struct rx_work_tasklet;
+ struct sk_buff_head rx_queue;
void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *,
struct sk_buff_head *);
void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index c3eff32acf6c..44328baa6389 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -99,11 +99,36 @@
#define CHANNEL_GROUP_MAX_5G 9
#define CHANNEL_MAX_NUMBER_2G 14
#define AVG_THERMAL_NUM 8
+#define AVG_THERMAL_NUM_88E 4
#define MAX_TID_COUNT 9
/* for early mode */
#define FCS_LEN 4
#define EM_HDR_LEN 8
+
+#define MAX_TX_COUNT 4
+#define MAX_RF_PATH 4
+#define MAX_CHNL_GROUP_24G 6
+#define MAX_CHNL_GROUP_5G 14
+
+struct txpower_info_2g {
+ u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
+ u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
+ /*If only one tx, only BW20 and OFDM are used.*/
+ u8 cck_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
+struct txpower_info_5g {
+ u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_5G];
+ /*If only one tx, only BW20, OFDM, BW80 and BW160 are used.*/
+ u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
enum intf_type {
INTF_PCI = 0,
INTF_USB = 1,
@@ -137,6 +162,7 @@ enum hardware_type {
HARDWARE_TYPE_RTL8192DU,
HARDWARE_TYPE_RTL8723AE,
HARDWARE_TYPE_RTL8723U,
+ HARDWARE_TYPE_RTL8188EE,
/* keep it last */
HARDWARE_TYPE_NUM
@@ -263,7 +289,7 @@ enum hw_variables {
HW_VAR_RATR_0,
HW_VAR_RRSR,
HW_VAR_CPU_RST,
- HW_VAR_CECHK_BSSID,
+ HW_VAR_CHECK_BSSID,
HW_VAR_LBK_MODE,
HW_VAR_AES_11N_FIX,
HW_VAR_USB_RX_AGGR,
@@ -278,7 +304,10 @@ enum hw_variables {
HW_VAR_SET_RPWM,
HW_VAR_H2C_FW_PWRMODE,
HW_VAR_H2C_FW_JOINBSSRPT,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
HW_VAR_FW_PSMODE_STATUS,
+ HW_VAR_RESUME_CLK_ON,
+ HW_VAR_FW_LPS_ACTION,
HW_VAR_1X1_RECV_COMBINE,
HW_VAR_STOP_SEND_BEACON,
HW_VAR_TSF_TIMER,
@@ -305,6 +334,7 @@ enum hw_variables {
HW_VAR_INT_AC,
HW_VAR_RF_TIMING,
+ HAL_DEF_WOWLAN,
HW_VAR_MRC,
HW_VAR_MGT_FILTER,
@@ -461,6 +491,7 @@ enum rtl_var_map {
EFUSE_MAX_SECTION_MAP,
EFUSE_REAL_CONTENT_SIZE,
EFUSE_OOB_PROTECT_BYTES_LEN,
+ EFUSE_ACCESS,
/*CAM map */
RWCAM,
@@ -493,7 +524,7 @@ enum rtl_var_map {
RTL_IMR_TIMEOUT1, /*Timeout interrupt 1 */
RTL_IMR_TXFOVW, /*Transmit FIFO Overflow */
RTL_IMR_PSTIMEOUT, /*Power save time out interrupt */
- RTL_IMR_BcnInt, /*Beacon DMA Interrupt 0 */
+ RTL_IMR_BCNINT, /*Beacon DMA Interrupt 0 */
RTL_IMR_RXFOVW, /*Receive FIFO Overflow */
RTL_IMR_RDU, /*Receive Descriptor Unavailable */
RTL_IMR_ATIMEND, /*For 92C,ATIM Window End Interrupt */
@@ -508,7 +539,7 @@ enum rtl_var_map {
RTL_IMR_VIDOK, /*AC_VI DMA OK Interrupt */
RTL_IMR_VODOK, /*AC_VO DMA Interrupt */
RTL_IMR_ROK, /*Receive DMA OK Interrupt */
- RTL_IBSS_INT_MASKS, /*(RTL_IMR_BcnInt | RTL_IMR_TBDOK |
+ RTL_IBSS_INT_MASKS, /*(RTL_IMR_BCNINT | RTL_IMR_TBDOK |
* RTL_IMR_TBDER) */
RTL_IMR_C2HCMD, /*fw interrupt*/
@@ -742,6 +773,11 @@ struct false_alarm_statistics {
u32 cnt_ofdm_fail;
u32 cnt_cck_fail;
u32 cnt_all;
+ u32 cnt_ofdm_cca;
+ u32 cnt_cck_cca;
+ u32 cnt_cca_all;
+ u32 cnt_bw_usc;
+ u32 cnt_bw_lsc;
};
struct init_gain {
@@ -826,8 +862,67 @@ struct rtl_rfkill {
bool rfkill_state; /*0 is off, 1 is on */
};
+/*for P2P PS**/
+#define P2P_MAX_NOA_NUM 2
+
+enum p2p_role {
+ P2P_ROLE_DISABLE = 0,
+ P2P_ROLE_DEVICE = 1,
+ P2P_ROLE_CLIENT = 2,
+ P2P_ROLE_GO = 3
+};
+
+enum p2p_ps_state {
+ P2P_PS_DISABLE = 0,
+ P2P_PS_ENABLE = 1,
+ P2P_PS_SCAN = 2,
+ P2P_PS_SCAN_DONE = 3,
+ P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */
+};
+
+enum p2p_ps_mode {
+ P2P_PS_NONE = 0,
+ P2P_PS_CTWINDOW = 1,
+ P2P_PS_NOA = 2,
+ P2P_PS_MIX = 3, /* CTWindow and NoA */
+};
+
+struct rtl_p2p_ps_info {
+ enum p2p_ps_mode p2p_ps_mode; /* indicate p2p ps mode */
+ enum p2p_ps_state p2p_ps_state; /* indicate p2p ps state */
+ u8 noa_index; /* Identifies instance of Notice of Absence timing. */
+ /* Client traffic window. A period of time in TU after TBTT. */
+ u8 ctwindow;
+ u8 opp_ps; /* opportunistic power save. */
+ u8 noa_num; /* number of NoA descriptor in P2P IE. */
+ /* Count for owner, Type of client. */
+ u8 noa_count_type[P2P_MAX_NOA_NUM];
+ /* Max duration for owner, preferred or min acceptable duration
+ * for client.
+ */
+ u32 noa_duration[P2P_MAX_NOA_NUM];
+ /* Length of interval for owner, preferred or max acceptable intervali
+ * of client.
+ */
+ u32 noa_interval[P2P_MAX_NOA_NUM];
+ /* schedule in terms of the lower 4 bytes of the TSF timer. */
+ u32 noa_start_time[P2P_MAX_NOA_NUM];
+};
+
+struct p2p_ps_offload_t {
+ u8 offload_en:1;
+ u8 role:1; /* 1: Owner, 0: Client */
+ u8 ctwindow_en:1;
+ u8 noa0_en:1;
+ u8 noa1_en:1;
+ u8 allstasleep:1;
+ u8 discovery:1;
+ u8 reserved:1;
+};
+
#define IQK_MATRIX_REG_NUM 8
#define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21)
+
struct iqk_matrix_regs {
bool iqk_done;
long value[1][IQK_MATRIX_REG_NUM];
@@ -889,7 +984,7 @@ struct rtl_phy {
/* Dual mac */
bool need_iqk;
- struct iqk_matrix_regs iqk_matrix_regsetting[IQK_MATRIX_SETTINGS_NUM];
+ struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM];
bool rfpi_enable;
@@ -902,6 +997,8 @@ struct rtl_phy {
/* the current Tx power level */
u8 cur_cck_txpwridx;
u8 cur_ofdm24g_txpwridx;
+ u8 cur_bw20_txpwridx;
+ u8 cur_bw40_txpwridx;
u32 rfreg_chnlval[2];
bool apk_done;
@@ -940,20 +1037,21 @@ struct rtl_ht_agg {
u8 rx_agg_state;
};
+struct rssi_sta {
+ long undec_sm_pwdb;
+};
+
struct rtl_tid_data {
u16 seq_number;
struct rtl_ht_agg agg;
};
-struct rssi_sta {
- long undec_sm_pwdb;
-};
-
struct rtl_sta_info {
struct list_head list;
u8 ratr_index;
u8 wireless_mode;
u8 mimo_ps;
+ u8 mac_addr[ETH_ALEN];
struct rtl_tid_data tids[MAX_TID_COUNT];
/* just used for ap adhoc or mesh*/
@@ -1005,6 +1103,8 @@ struct rtl_mac {
int n_bitrates;
bool offchan_delay;
+ u8 p2p; /*using p2p role*/
+ bool p2p_in_use;
/*filters */
u32 rx_conf;
@@ -1014,11 +1114,11 @@ struct rtl_mac {
bool act_scanning;
u8 cnt_after_linked;
+ bool skip_scan;
/* early mode */
/* skb wait queue */
struct sk_buff_head skb_waitq[MAX_TID_COUNT];
- u8 earlymode_threshold;
/*RDG*/
bool rdg_en;
@@ -1042,6 +1142,7 @@ struct rtl_mac {
u8 retry_short;
u8 retry_long;
u16 assoc_id;
+ bool hiddenssid;
/*IBSS*/
int beacon_interval;
@@ -1111,10 +1212,13 @@ struct bt_coexist_8723 {
struct rtl_hal {
struct ieee80211_hw *hw;
- struct bt_coexist_8723 hal_coex_8723;
+ bool driver_is_goingto_unload;
bool up_first_time;
+ bool first_init;
bool being_init_adapter;
bool bbrf_ready;
+ bool mac_func_enable;
+ struct bt_coexist_8723 hal_coex_8723;
enum intf_type interface;
u16 hw_type; /*92c or 92d or 92s and so on */
@@ -1122,6 +1226,7 @@ struct rtl_hal {
u8 oem_id;
u32 version; /*version of chip */
u8 state; /*stop 0, start 1 */
+ u8 board_type;
/*firmware */
u32 fwsize;
@@ -1141,6 +1246,10 @@ struct rtl_hal {
bool set_fwcmd_inprogress;
u8 current_fwcmd_io;
+ struct p2p_ps_offload_t p2p_ps_offload;
+ bool fw_clk_change_in_progress;
+ bool allow_sw_to_change_hwclc;
+ u8 fw_ps_state;
/**/
bool driver_going2unload;
@@ -1157,6 +1266,7 @@ struct rtl_hal {
/* just for DualMac S3S4 */
u8 macphyctl_reg;
bool earlymode_enable;
+ u8 max_earlymode_num;
/* Dual mac*/
bool during_mac0init_radiob;
bool during_mac1init_radioa;
@@ -1193,6 +1303,29 @@ struct rtl_security {
u8 *pairwise_key;
};
+#define ASSOCIATE_ENTRY_NUM 33
+
+struct fast_ant_training {
+ u8 bssid[6];
+ u8 antsel_rx_keep_0;
+ u8 antsel_rx_keep_1;
+ u8 antsel_rx_keep_2;
+ u32 ant_sum[7];
+ u32 ant_cnt[7];
+ u32 ant_ave[7];
+ u8 fat_state;
+ u32 train_idx;
+ u8 antsel_a[ASSOCIATE_ENTRY_NUM];
+ u8 antsel_b[ASSOCIATE_ENTRY_NUM];
+ u8 antsel_c[ASSOCIATE_ENTRY_NUM];
+ u32 main_ant_sum[ASSOCIATE_ENTRY_NUM];
+ u32 aux_ant_sum[ASSOCIATE_ENTRY_NUM];
+ u32 main_ant_cnt[ASSOCIATE_ENTRY_NUM];
+ u32 aux_ant_cnt[ASSOCIATE_ENTRY_NUM];
+ u8 rx_idle_ant;
+ bool becomelinked;
+};
+
struct rtl_dm {
/*PHY status for Dynamic Management */
long entry_min_undec_sm_pwdb;
@@ -1229,9 +1362,24 @@ struct rtl_dm {
bool disable_tx_int;
char ofdm_index[2];
char cck_index;
+ char delta_power_index;
+ char delta_power_index_last;
+ char power_index_offset;
+
+ /*88e tx power tracking*/
+ u8 swing_idx_ofdm[2];
+ u8 swing_idx_ofdm_cur;
+ u8 swing_idx_ofdm_base;
+ bool swing_flag_ofdm;
+ u8 swing_idx_cck;
+ u8 swing_idx_cck_cur;
+ u8 swing_idx_cck_base;
+ bool swing_flag_cck;
/* DMSP */
bool supp_phymode_switch;
+
+ struct fast_ant_training fat_table;
};
#define EFUSE_MAX_LOGICAL_SIZE 256
@@ -1264,6 +1412,9 @@ struct rtl_efuse {
u8 external_pa;
u8 dev_addr[6];
+ u8 wowlan_enable;
+ u8 antenna_div_cfg;
+ u8 antenna_div_type;
bool txpwr_fromeprom;
u8 eeprom_crystalcap;
@@ -1319,14 +1470,12 @@ struct rtl_ps_ctl {
bool rfchange_inprogress;
bool swrf_processing;
bool hwradiooff;
-
/*
* just for PCIE ASPM
* If it supports ASPM, Offset[560h] = 0x40,
* otherwise Offset[560h] = 0x00.
* */
bool support_aspm;
-
bool support_backdoor;
/*for LPS */
@@ -1341,6 +1490,7 @@ struct rtl_ps_ctl {
bool fw_current_inpsmode;
u8 reg_max_lps_awakeintvl;
bool report_linked;
+ bool low_power_enable;/*for 32k*/
/*for IPS */
bool inactiveps;
@@ -1373,6 +1523,11 @@ struct rtl_ps_ctl {
unsigned long last_beacon;
unsigned long last_action;
unsigned long last_slept;
+
+ /*For P2P PS */
+ struct rtl_p2p_ps_info p2p_ps_info;
+ u8 pwr_mode;
+ u8 smart_ps;
};
struct rtl_stats {
@@ -1381,7 +1536,7 @@ struct rtl_stats {
s8 rssi;
u8 signal;
u8 noise;
- u16 rate; /*in 100 kbps */
+ u8 rate; /* hw desc rate */
u8 received_channel;
u8 control;
u8 mask;
@@ -1423,8 +1578,16 @@ struct rtl_stats {
bool packet_toself;
bool packet_beacon; /*for rssi */
char cck_adc_pwdb[4]; /*for rx path selection */
+
+ u8 packet_report_type;
+
+ u32 macid;
+ u8 wake_match;
+ u32 bt_rx_rssi_percentage;
+ u32 macid_valid_entry[2];
};
+
struct rt_link_detect {
/* count for roaming */
u32 bcn_rx_inperiod;
@@ -1477,7 +1640,8 @@ struct rtl_tcb_desc {
/* early mode */
u8 empkt_num;
/* The max value by HW */
- u32 empkt_len[5];
+ u32 empkt_len[10];
+ bool btx_enable_sw_calc_duration;
};
struct rtl_hal_ops {
@@ -1553,7 +1717,7 @@ struct rtl_hal_ops {
void (*allow_all_destaddr)(struct ieee80211_hw *hw,
bool allow_all_da, bool write_into_reg);
void (*linked_set_reg) (struct ieee80211_hw *hw);
- void (*check_switch_to_dmdp) (struct ieee80211_hw *hw);
+ void (*chk_switch_dmdp) (struct ieee80211_hw *hw);
void (*dualmac_easy_concurrent) (struct ieee80211_hw *hw);
void (*dualmac_switch_to_dmdp) (struct ieee80211_hw *hw);
bool (*phy_rf6052_config) (struct ieee80211_hw *hw);
@@ -1662,6 +1826,8 @@ struct rtl_locks {
/*spin lock */
spinlock_t ips_lock;
spinlock_t irq_th_lock;
+ spinlock_t irq_pci_lock;
+ spinlock_t tx_lock;
spinlock_t h2c_lock;
spinlock_t rf_ps_lock;
spinlock_t rf_lock;
@@ -1670,6 +1836,9 @@ struct rtl_locks {
spinlock_t entry_list_lock;
spinlock_t usb_lock;
+ /*FW clock change */
+ spinlock_t fw_ps_lock;
+
/*Dual mac*/
spinlock_t cck_and_rw_pagea_lock;
@@ -1683,7 +1852,8 @@ struct rtl_works {
/*timer */
struct timer_list watchdog_timer;
struct timer_list dualmac_easyconcurrent_retrytimer;
-
+ struct timer_list fw_clockoff_timer;
+ struct timer_list fast_antenna_training_timer;
/*task */
struct tasklet_struct irq_tasklet;
struct tasklet_struct irq_prepare_bcn_tasklet;
@@ -1696,8 +1866,9 @@ struct rtl_works {
/* For SW LPS */
struct delayed_work ps_work;
struct delayed_work ps_rfon_wq;
+ struct delayed_work fwevt_wq;
- struct work_struct lps_leave_work;
+ struct work_struct lps_change_work;
};
struct rtl_debug {
@@ -1767,10 +1938,12 @@ struct dig_t {
char back_val;
char back_range_max;
char back_range_min;
- u8 rx_gain_range_max;
- u8 rx_gain_range_min;
+ u8 rx_gain_max;
+ u8 rx_gain_min;
u8 min_undec_pwdb_for_dm;
u8 rssi_val_min;
+ u8 pre_cck_cca_thres;
+ u8 cur_cck_cca_thres;
u8 pre_cck_pd_state;
u8 cur_cck_pd_state;
u8 pre_cck_fa_state;
@@ -1792,6 +1965,13 @@ struct dig_t {
u8 backoff_enable_flag;
char backoffval_range_max;
char backoffval_range_min;
+ u8 dig_min_0;
+ u8 dig_min_1;
+ bool media_connect_0;
+ bool media_connect_1;
+
+ u32 antdiv_rssi_max;
+ u32 rssi_max;
};
struct rtl_global_var {
@@ -1802,6 +1982,7 @@ struct rtl_global_var {
};
struct rtl_priv {
+ struct ieee80211_hw *hw;
struct completion firmware_loading_complete;
struct list_head list;
struct rtl_priv *buddy_priv;
@@ -1866,6 +2047,7 @@ struct rtl_priv {
bool bt_operation_on;
};
};
+ bool enter_ps; /* true when entering PS */
/*This must be the last item so
that it points to the data allocated
@@ -2127,6 +2309,7 @@ value to host byte ordering.*/
#define WLAN_FC_GET_TYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE)
#define WLAN_FC_GET_STYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE)
#define WLAN_FC_MORE_DATA(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA)
+#define rtl_dm(rtlpriv) (&((rtlpriv)->dm))
#define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */
#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c
index e57ee48edff6..e2b3d9c541e8 100644
--- a/drivers/net/wireless/ti/wl1251/sdio.c
+++ b/drivers/net/wireless/ti/wl1251/sdio.c
@@ -186,8 +186,10 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
wl->set_power(true);
ret = pm_runtime_get_sync(&func->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_sync(&func->dev);
goto out;
+ }
sdio_claim_host(func);
sdio_enable_func(func);
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index 09694e39bb14..1c627da85083 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -723,6 +723,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ;
+ wl->ba_rx_session_count_max = WL12XX_RX_BA_MAX_SESSIONS;
out:
return ret;
}
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h
index d4552857480c..222d03540200 100644
--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
@@ -63,6 +63,8 @@
#define WL12XX_NUM_MAC_ADDRESSES 2
+#define WL12XX_RX_BA_MAX_SESSIONS 3
+
struct wl127x_rx_mem_pool_addr {
u32 addr;
u32 addr_extra;
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index da3ef1b10a9c..9fa692d11025 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -678,6 +678,7 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
+ wl->ba_rx_session_count_max = WL18XX_RX_BA_MAX_SESSIONS;
out:
return ret;
}
@@ -1144,6 +1145,7 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
{
u32 fuse;
+ s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0;
int ret;
ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
@@ -1154,8 +1156,29 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
if (ret < 0)
goto out;
+ pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
+ rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
+
+ if (rom <= 0xE)
+ metal = (fuse & WL18XX_METAL_VER_MASK) >>
+ WL18XX_METAL_VER_OFFSET;
+ else
+ metal = (fuse & WL18XX_NEW_METAL_VER_MASK) >>
+ WL18XX_NEW_METAL_VER_OFFSET;
+
+ ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
+ if (ret < 0)
+ goto out;
+
+ rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET;
+ if (rdl_ver > RDL_MAX)
+ rdl_ver = RDL_NONE;
+
+ wl1271_info("wl18xx HW: RDL %d, %s, PG %x.%x (ROM %x)",
+ rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom);
+
if (ver)
- *ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
+ *ver = pg_ver;
ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
diff --git a/drivers/net/wireless/ti/wl18xx/reg.h b/drivers/net/wireless/ti/wl18xx/reg.h
index 937b71d8783f..6306e04cd258 100644
--- a/drivers/net/wireless/ti/wl18xx/reg.h
+++ b/drivers/net/wireless/ti/wl18xx/reg.h
@@ -131,6 +131,16 @@
#define WL18XX_REG_FUSE_DATA_1_3 0xA0260C
#define WL18XX_PG_VER_MASK 0x70
#define WL18XX_PG_VER_OFFSET 4
+#define WL18XX_ROM_VER_MASK 0x3
+#define WL18XX_ROM_VER_OFFSET 0
+#define WL18XX_METAL_VER_MASK 0xC
+#define WL18XX_METAL_VER_OFFSET 2
+#define WL18XX_NEW_METAL_VER_MASK 0x180
+#define WL18XX_NEW_METAL_VER_OFFSET 7
+
+#define WL18XX_REG_FUSE_DATA_2_3 0xA02614
+#define WL18XX_RDL_VER_MASK 0x1f00
+#define WL18XX_RDL_VER_OFFSET 8
#define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602
#define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606
@@ -188,4 +198,23 @@ enum {
NUM_BOARD_TYPES,
};
+enum {
+ RDL_NONE = 0,
+ RDL_1_HP = 1,
+ RDL_2_SP = 2,
+ RDL_3_HP = 3,
+ RDL_4_SP = 4,
+
+ _RDL_LAST,
+ RDL_MAX = _RDL_LAST - 1,
+};
+
+static const char * const rdl_names[] = {
+ [RDL_NONE] = "",
+ [RDL_1_HP] = "1853 SISO",
+ [RDL_2_SP] = "1857 MIMO",
+ [RDL_3_HP] = "1893 SISO",
+ [RDL_4_SP] = "1897 MIMO",
+};
+
#endif /* __REG_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index b6739e79efcf..9204e07ee432 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -29,7 +29,7 @@
#define WL18XX_IFTYPE_VER 5
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
-#define WL18XX_MINOR_VER 28
+#define WL18XX_MINOR_VER 39
#define WL18XX_CMD_MAX_SIZE 740
@@ -40,6 +40,8 @@
#define WL18XX_NUM_MAC_ADDRESSES 3
+#define WL18XX_RX_BA_MAX_SESSIONS 5
+
struct wl18xx_priv {
/* buffer for sending commands to FW */
u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index c79654323396..7a970cd9c555 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1736,6 +1736,35 @@ out:
}
+int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ s8 *avg_rssi)
+{
+ struct acx_roaming_stats *acx;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx roaming statistics");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->role_id = wlvif->role_id;
+ ret = wl1271_cmd_interrogate(wl, ACX_ROAMING_STATISTICS_TBL,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx roaming statistics failed: %d", ret);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ *avg_rssi = acx->rssi_beacon;
+out:
+ kfree(acx);
+ return ret;
+}
+
#ifdef CONFIG_PM
/* Set the global behaviour of RX filters - On/Off + default action */
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h
index 126536c6a393..6dcfad9b0472 100644
--- a/drivers/net/wireless/ti/wlcore/acx.h
+++ b/drivers/net/wireless/ti/wlcore/acx.h
@@ -728,8 +728,6 @@ struct wl1271_acx_ht_information {
u8 padding[2];
} __packed;
-#define RX_BA_MAX_SESSIONS 3
-
struct wl1271_acx_ba_initiator_policy {
struct acx_header header;
@@ -955,6 +953,18 @@ struct acx_rx_filter_cfg {
u8 fields[0];
} __packed;
+struct acx_roaming_stats {
+ struct acx_header header;
+
+ u8 role_id;
+ u8 pad[3];
+ u32 missed_beacons;
+ u8 snr_data;
+ u8 snr_bacon;
+ s8 rssi_data;
+ s8 rssi_beacon;
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0000,
ACX_MEM_CFG = 0x0001,
@@ -1112,6 +1122,8 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl);
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
int wl12xx_acx_config_hangover(struct wl1271 *wl);
+int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ s8 *avg_rssi);
#ifdef CONFIG_PM
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 6331f9e1cb39..c9e060795d13 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -327,6 +327,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl->links[link].prev_freed_pkts =
wl->fw_status_2->counters.tx_lnk_free_pkts[link];
wl->links[link].wlvif = wlvif;
+
+ /*
+ * Take saved value for total freed packets from wlvif, in case this is
+ * recovery/resume
+ */
+ if (wlvif->bss_type != BSS_TYPE_AP_BSS)
+ wl->links[link].total_freed_pkts = wlvif->total_freed_pkts;
+
*hlid = link;
wl->active_link_count++;
@@ -358,6 +366,26 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl1271_tx_reset_link_queues(wl, *hlid);
wl->links[*hlid].wlvif = NULL;
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
+ (wlvif->bss_type == BSS_TYPE_AP_BSS &&
+ *hlid == wlvif->ap.bcast_hlid)) {
+ /*
+ * save the total freed packets in the wlvif, in case this is
+ * recovery or suspend
+ */
+ wlvif->total_freed_pkts = wl->links[*hlid].total_freed_pkts;
+
+ /*
+ * increment the initial seq number on recovery to account for
+ * transmitted packets that we haven't yet got in the FW status
+ */
+ if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+ wlvif->total_freed_pkts +=
+ WL1271_TX_SQN_POST_RECOVERY_PADDING;
+ }
+
+ wl->links[*hlid].total_freed_pkts = 0;
+
*hlid = WL12XX_INVALID_LINK_ID;
wl->active_link_count--;
WARN_ON_ONCE(wl->active_link_count < 0);
@@ -609,6 +637,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (ret < 0)
goto out_free_global;
+ /* use the previous security seq, if this is a recovery/resume */
+ wl->links[wlvif->ap.bcast_hlid].total_freed_pkts =
+ wlvif->total_freed_pkts;
+
cmd->role_id = wlvif->role_id;
cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
diff --git a/drivers/net/wireless/ti/wlcore/debug.h b/drivers/net/wireless/ti/wlcore/debug.h
index db4bf5a68ce2..0420bd45e4ee 100644
--- a/drivers/net/wireless/ti/wlcore/debug.h
+++ b/drivers/net/wireless/ti/wlcore/debug.h
@@ -89,25 +89,24 @@ extern u32 wl12xx_debug_level;
} while (0)
#endif
-/* TODO: use pr_debug_hex_dump when it becomes available */
-#define wl1271_dump(level, prefix, buf, len) \
- do { \
- if (level & wl12xx_debug_level) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- 0); \
+#define wl1271_dump(level, prefix, buf, len) \
+ do { \
+ if (level & wl12xx_debug_level) \
+ print_hex_dump_debug(DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ 0); \
} while (0)
-#define wl1271_dump_ascii(level, prefix, buf, len) \
- do { \
- if (level & wl12xx_debug_level) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- true); \
+#define wl1271_dump_ascii(level, prefix, buf, len) \
+ do { \
+ if (level & wl12xx_debug_level) \
+ print_hex_dump_debug(DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ true); \
} while (0)
#endif /* __DEBUG_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index e70a7c864865..c3e1f79c7856 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -598,8 +598,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(last_rssi_event);
VIF_STATE_PRINT_INT(ba_support);
VIF_STATE_PRINT_INT(ba_allowed);
- VIF_STATE_PRINT_LLHEX(tx_security_seq);
- VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
+ VIF_STATE_PRINT_LLHEX(total_freed_pkts);
}
#undef VIF_STATE_PRINT_INT
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 70f289aa1bc6..67f61689b49e 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -237,6 +237,14 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
!test_bit(wlvif->role_id , &roles_bitmap))
continue;
+ vif = wl12xx_wlvif_to_vif(wlvif);
+
+ /* don't attempt roaming in case of p2p */
+ if (wlvif->p2p) {
+ ieee80211_connection_loss(vif);
+ continue;
+ }
+
/*
* if the work is already queued, it should take place.
* We don't want to delay the connection loss
@@ -246,7 +254,6 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
&wlvif->connection_loss_work,
msecs_to_jiffies(delay));
- vif = wl12xx_wlvif_to_vif(wlvif);
ieee80211_cqm_rssi_notify(
vif,
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index d7e306333f6c..d10954c0c181 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -108,8 +108,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy,
}
- if (likely(wl->state == WLCORE_STATE_ON))
- wlcore_regdomain_config(wl);
+ wlcore_regdomain_config(wl);
}
static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -332,10 +331,9 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
u8 hlid, u8 tx_pkts)
{
- bool fw_ps, single_link;
+ bool fw_ps;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
- single_link = (wl->active_link_count == 1);
/*
* Wake up from high level PS if the STA is asleep with too little
@@ -348,8 +346,13 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
* Start high-level PS if the STA is asleep with enough blocks in FW.
* Make an exception if this is the only connected link. In this
* case FW-memory congestion is less of a problem.
+ * Note that a single connected STA means 3 active links, since we must
+ * account for the global and broadcast AP links. The "fw_ps" check
+ * assures us the third link is a STA connected to the AP. Otherwise
+ * the FW would not set the PSM bit.
*/
- else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ else if (wl->active_link_count > 3 && fw_ps &&
+ tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
@@ -414,13 +417,21 @@ static int wlcore_fw_status(struct wl1271 *wl,
for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
+ u8 diff;
lnk = &wl->links[i];
+
/* prevent wrap-around in freed-packets counter */
- lnk->allocated_pkts -=
- (status_2->counters.tx_lnk_free_pkts[i] -
- lnk->prev_freed_pkts) & 0xff;
+ diff = (status_2->counters.tx_lnk_free_pkts[i] -
+ lnk->prev_freed_pkts) & 0xff;
+
+ if (diff == 0)
+ continue;
+ lnk->allocated_pkts -= diff;
lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
+
+ /* accumulate the prev_freed_pkts counter */
+ lnk->total_freed_pkts += diff;
}
/* prevent wrap-around in total blocks counter */
@@ -640,6 +651,25 @@ static irqreturn_t wlcore_irq(int irq, void *cookie)
unsigned long flags;
struct wl1271 *wl = cookie;
+ /* complete the ELP completion */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
+ if (wl->elp_compl) {
+ complete(wl->elp_compl);
+ wl->elp_compl = NULL;
+ }
+
+ if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
+ /* don't enqueue a work right now. mark it as pending */
+ set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
+ wl1271_debug(DEBUG_IRQ, "should not enqueue work");
+ disable_irq_nosync(wl->irq);
+ pm_wakeup_event(wl->dev, 0);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ return IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
/* TX might be handled here, avoid redundant work */
set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
cancel_work_sync(&wl->tx_work);
@@ -919,18 +949,6 @@ static void wl1271_recovery_work(struct work_struct *work)
goto out_unlock;
}
- /*
- * Advance security sequence number to overcome potential progress
- * in the firmware during recovery. This doens't hurt if the network is
- * not encrypted.
- */
- wl12xx_for_each_wlvif(wl, wlvif) {
- if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
- test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
- wlvif->tx_security_seq +=
- WL1271_TX_SQN_POST_RECOVERY_PADDING;
- }
-
/* Prevent spurious TX during FW restart */
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
@@ -2523,6 +2541,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl1271_ps_elp_sleep(wl);
}
deinit:
+ wl12xx_tx_reset_wlvif(wl, wlvif);
+
/* clear all hlids (except system_hlid) */
wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
@@ -2546,7 +2566,6 @@ deinit:
dev_kfree_skb(wlvif->probereq);
wlvif->probereq = NULL;
- wl12xx_tx_reset_wlvif(wl, wlvif);
if (wl->last_wlvif == wlvif)
wl->last_wlvif = NULL;
list_del(&wlvif->list);
@@ -2860,10 +2879,6 @@ static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wlvif->sta.klv_template_id,
ACX_KEEP_ALIVE_TPL_INVALID);
- /* reset TX security counters on a clean disconnect */
- wlvif->tx_security_last_seq_lsb = 0;
- wlvif->tx_security_seq = 0;
-
return 0;
}
@@ -3262,6 +3277,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
u32 tx_seq_32 = 0;
u16 tx_seq_16 = 0;
u8 key_type;
+ u8 hlid;
wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
@@ -3271,6 +3287,22 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
key_conf->keylen, key_conf->flags);
wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+ if (sta) {
+ struct wl1271_station *wl_sta = (void *)sta->drv_priv;
+ hlid = wl_sta->hlid;
+ } else {
+ hlid = wlvif->ap.bcast_hlid;
+ }
+ else
+ hlid = wlvif->sta.hlid;
+
+ if (hlid != WL12XX_INVALID_LINK_ID) {
+ u64 tx_seq = wl->links[hlid].total_freed_pkts;
+ tx_seq_32 = WL1271_TX_SECURITY_HI32(tx_seq);
+ tx_seq_16 = WL1271_TX_SECURITY_LO16(tx_seq);
+ }
+
switch (key_conf->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -3280,22 +3312,14 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
break;
case WLAN_CIPHER_SUITE_TKIP:
key_type = KEY_TKIP;
-
key_conf->hw_key_idx = key_conf->keyidx;
- tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
- tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
break;
case WLAN_CIPHER_SUITE_CCMP:
key_type = KEY_AES;
-
key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
- tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
- tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
break;
case WL1271_CIPHER_SUITE_GEM:
key_type = KEY_GEM;
- tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
- tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
break;
default:
wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
@@ -3358,6 +3382,10 @@ void wlcore_regdomain_config(struct wl1271 *wl)
return;
mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
@@ -4499,6 +4527,9 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
return -EBUSY;
}
+ /* use the previous security seq, if this is a recovery/resume */
+ wl->links[wl_sta->hlid].total_freed_pkts = wl_sta->total_freed_pkts;
+
set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
wl->active_sta_count++;
@@ -4507,12 +4538,37 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
{
+ struct wl1271_station *wl_sta;
+ struct ieee80211_sta *sta;
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+
if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
return;
clear_bit(hlid, wlvif->ap.sta_hlid_map);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+
+ /*
+ * save the last used PN in the private part of iee80211_sta,
+ * in case of recovery/suspend
+ */
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
+ if (sta) {
+ wl_sta = (void *)sta->drv_priv;
+ wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts;
+
+ /*
+ * increment the initial seq number on recovery to account for
+ * transmitted packets that we haven't yet got in the FW status
+ */
+ if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+ wl_sta->total_freed_pkts +=
+ WL1271_TX_SQN_POST_RECOVERY_PADDING;
+ }
+ rcu_read_unlock();
+
wl12xx_free_link(wl, wlvif, &hlid);
wl->active_sta_count--;
@@ -4616,13 +4672,11 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
enum ieee80211_sta_state new_state)
{
struct wl1271_station *wl_sta;
- u8 hlid;
bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
int ret;
wl_sta = (struct wl1271_station *)sta->drv_priv;
- hlid = wl_sta->hlid;
/* Add station (AP mode) */
if (is_ap &&
@@ -4648,12 +4702,12 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
/* Authorize station (AP mode) */
if (is_ap &&
new_state == IEEE80211_STA_AUTHORIZED) {
- ret = wl12xx_cmd_set_peer_state(wl, wlvif, hlid);
+ ret = wl12xx_cmd_set_peer_state(wl, wlvif, wl_sta->hlid);
if (ret < 0)
return ret;
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
- hlid);
+ wl_sta->hlid);
if (ret)
return ret;
@@ -4784,7 +4838,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
break;
}
- if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
+ if (wl->ba_rx_session_count >= wl->ba_rx_session_count_max) {
ret = -EBUSY;
wl1271_error("exceeded max RX BA sessions");
break;
@@ -4946,7 +5000,7 @@ out:
mutex_unlock(&wl->mutex);
}
-static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
+static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct wl1271 *wl = hw->priv;
@@ -5092,6 +5146,39 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
}
+static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ s8 *rssi_dbm)
+{
+ struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ int ret = 0;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
@@ -5291,6 +5378,7 @@ static const struct ieee80211_ops wl1271_ops = {
.assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
.unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
.sta_rc_update = wlcore_op_sta_rc_update,
+ .get_rssi = wlcore_op_get_rssi,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -5930,35 +6018,6 @@ int wlcore_free_hw(struct wl1271 *wl)
}
EXPORT_SYMBOL_GPL(wlcore_free_hw);
-static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
-{
- struct wl1271 *wl = cookie;
- unsigned long flags;
-
- wl1271_debug(DEBUG_IRQ, "IRQ");
-
- /* complete the ELP completion */
- spin_lock_irqsave(&wl->wl_lock, flags);
- set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
- if (wl->elp_compl) {
- complete(wl->elp_compl);
- wl->elp_compl = NULL;
- }
-
- if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
- /* don't enqueue a work right now. mark it as pending */
- set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
- wl1271_debug(DEBUG_IRQ, "should not enqueue work");
- disable_irq_nosync(wl->irq);
- pm_wakeup_event(wl->dev, 0);
- spin_unlock_irqrestore(&wl->wl_lock, flags);
- return IRQ_HANDLED;
- }
- spin_unlock_irqrestore(&wl->wl_lock, flags);
-
- return IRQ_WAKE_THREAD;
-}
-
static void wlcore_nvs_cb(const struct firmware *fw, void *context)
{
struct wl1271 *wl = context;
@@ -6000,9 +6059,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
else
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
- ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wlcore_irq,
- irqflags,
- pdev->name, wl);
+ ret = request_threaded_irq(wl->irq, NULL, wlcore_irq,
+ irqflags, pdev->name, wl);
if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret);
goto out_free_nvs;
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index 9b7b6e2e4fbc..9654577efd01 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -29,6 +29,7 @@
#define WL1271_WAKEUP_TIMEOUT 500
#define ELP_ENTRY_DELAY 30
+#define ELP_ENTRY_DELAY_FORCE_PS 5
void wl1271_elp_work(struct work_struct *work)
{
@@ -98,7 +99,8 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
return;
}
- timeout = ELP_ENTRY_DELAY;
+ timeout = wl->conf.conn.forced_ps ?
+ ELP_ENTRY_DELAY_FORCE_PS : ELP_ENTRY_DELAY;
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(timeout));
}
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index ece392c54d9c..004d02e71f01 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
+#include <linux/spinlock.h>
#include "wlcore.h"
#include "debug.h"
@@ -104,7 +105,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
u8 hlid)
{
- bool fw_ps, single_link;
+ bool fw_ps;
u8 tx_pkts;
if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
@@ -112,15 +113,19 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts;
- single_link = (wl->active_link_count == 1);
/*
* if in FW PS and there is enough data in FW we can put the link
* into high-level PS and clean out its TX queues.
* Make an exception if this is the only connected link. In this
* case FW-memory congestion is less of a problem.
+ * Note that a single connected STA means 3 active links, since we must
+ * account for the global and broadcast AP links. The "fw_ps" check
+ * assures us the third link is a STA connected to the AP. Otherwise
+ * the FW would not set the PSM bit.
*/
- if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ if (wl->active_link_count > 3 && fw_ps &&
+ tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
@@ -639,6 +644,7 @@ next:
}
+out:
if (!skb &&
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
int q;
@@ -652,7 +658,6 @@ next:
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
-out:
return skb;
}
@@ -928,25 +933,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
wl->stats.retry_count += result->ack_failures;
- /*
- * update sequence number only when relevant, i.e. only in
- * sessions of TKIP, AES and GEM (not in open or WEP sessions)
- */
- if (info->control.hw_key &&
- (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP ||
- info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP ||
- info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) {
- u8 fw_lsb = result->tx_security_sequence_number_lsb;
- u8 cur_lsb = wlvif->tx_security_last_seq_lsb;
-
- /*
- * update security sequence number, taking care of potential
- * wrap-around
- */
- wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff;
- wlvif->tx_security_last_seq_lsb = fw_lsb;
- }
-
/* remove private header from packet */
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
@@ -1061,7 +1047,8 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
/* TX failure */
for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
- if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
+ i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) {
/* this calls wl12xx_free_link */
wl1271_free_sta(wl, wlvif, i);
} else {
@@ -1304,7 +1291,7 @@ bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
{
int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
- WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
+ assert_spin_locked(&wl->wl_lock);
return test_bit(reason, &wl->queue_stop_reasons[hwq]);
}
@@ -1313,6 +1300,6 @@ bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
{
int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
- WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
+ assert_spin_locked(&wl->wl_lock);
return !!wl->queue_stop_reasons[hwq];
}
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index af9fecaefc30..0034979e97cb 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -390,6 +390,9 @@ struct wl1271 {
/* number of currently active RX BA sessions */
int ba_rx_session_count;
+ /* Maximum number of supported RX BA sessions */
+ int ba_rx_session_count_max;
+
/* AP-mode - number of currently connected stations */
int active_sta_count;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 508f5b0f8a70..e5e146435fe7 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -274,6 +274,13 @@ struct wl1271_link {
/* The wlvif this link belongs to. Might be null for global links */
struct wl12xx_vif *wlvif;
+
+ /*
+ * total freed FW packets on the link - used for tracking the
+ * AES/TKIP PN across recoveries. Re-initialized each time
+ * from the wl1271_station structure.
+ */
+ u64 total_freed_pkts;
};
#define WL1271_MAX_RX_FILTERS 5
@@ -318,6 +325,13 @@ struct wl12xx_rx_filter {
struct wl1271_station {
u8 hlid;
bool in_connection;
+
+ /*
+ * total freed FW packets on the link to the STA - used for tracking the
+ * AES/TKIP PN across recoveries. Re-initialized each time from the
+ * wl1271_station structure.
+ */
+ u64 total_freed_pkts;
};
struct wl12xx_vif {
@@ -449,16 +463,15 @@ struct wl12xx_vif {
*/
struct {
u8 persistent[0];
+
/*
- * Security sequence number
- * bits 0-15: lower 16 bits part of sequence number
- * bits 16-47: higher 32 bits part of sequence number
- * bits 48-63: not in use
+ * total freed FW packets on the link - used for
+ * storing the AES/TKIP PN during recovery, as this
+ * structure is not zeroed out.
+ * For STA this holds the PN of the link to the AP.
+ * For AP this holds the PN of the broadcast link.
*/
- u64 tx_security_seq;
-
- /* 8 bits of the last sequence number in use */
- u8 tx_security_last_seq_lsb;
+ u64 total_freed_pkts;
};
};
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 63ff69f9d3eb..a8dc95ebf2d6 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -347,6 +347,21 @@ static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
return (s8)gain;
}
+static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
+{
+ SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+ SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
+ SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
+ SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
+ SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
+ SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
+ SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
+ SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
+ SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
+ SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
+ SSB_SPROM2_MAXP_A_LO_SHIFT);
+}
+
static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
{
u16 loc[3];
@@ -369,6 +384,7 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
+ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
if (out->revision == 1)
SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
SSB_SPROM1_BINF_CCODE_SHIFT);
@@ -395,8 +411,7 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
SSB_SPROM1_ITSSI_A_SHIFT);
SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
- if (out->revision >= 2)
- SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+
SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
@@ -407,6 +422,8 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
SSB_SPROM1_AGAIN_A,
SSB_SPROM1_AGAIN_A_SHIFT);
+ if (out->revision >= 2)
+ sprom_extract_r23(out, in);
}
/* Revs 4 5 and 8 have partially shared layout */
@@ -464,6 +481,7 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
SSB_SPROM4_ETHPHY_ET1A_SHIFT);
SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
+ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
if (out->revision == 4) {
SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
@@ -535,6 +553,7 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
+ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index e0ce311011c0..0ab6712fd76b 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -173,6 +173,60 @@ struct bcma_host_ops {
#define BCMA_CHIP_ID_BCM53572 53572
#define BCMA_PKG_ID_BCM47188 9
+/* Board types (on PCI usually equals to the subsystem dev id) */
+/* BCM4313 */
+#define BCMA_BOARD_TYPE_BCM94313BU 0X050F
+#define BCMA_BOARD_TYPE_BCM94313HM 0X0510
+#define BCMA_BOARD_TYPE_BCM94313EPA 0X0511
+#define BCMA_BOARD_TYPE_BCM94313HMG 0X051C
+/* BCM4716 */
+#define BCMA_BOARD_TYPE_BCM94716NR2 0X04CD
+/* BCM43224 */
+#define BCMA_BOARD_TYPE_BCM943224X21 0X056E
+#define BCMA_BOARD_TYPE_BCM943224X21_FCC 0X00D1
+#define BCMA_BOARD_TYPE_BCM943224X21B 0X00E9
+#define BCMA_BOARD_TYPE_BCM943224M93 0X008B
+#define BCMA_BOARD_TYPE_BCM943224M93A 0X0090
+#define BCMA_BOARD_TYPE_BCM943224X16 0X0093
+#define BCMA_BOARD_TYPE_BCM94322X9 0X008D
+#define BCMA_BOARD_TYPE_BCM94322M35E 0X008E
+/* BCM43228 */
+#define BCMA_BOARD_TYPE_BCM943228BU8 0X0540
+#define BCMA_BOARD_TYPE_BCM943228BU9 0X0541
+#define BCMA_BOARD_TYPE_BCM943228BU 0X0542
+#define BCMA_BOARD_TYPE_BCM943227HM4L 0X0543
+#define BCMA_BOARD_TYPE_BCM943227HMB 0X0544
+#define BCMA_BOARD_TYPE_BCM943228HM4L 0X0545
+#define BCMA_BOARD_TYPE_BCM943228SD 0X0573
+/* BCM4331 */
+#define BCMA_BOARD_TYPE_BCM94331X19 0X00D6
+#define BCMA_BOARD_TYPE_BCM94331X28 0X00E4
+#define BCMA_BOARD_TYPE_BCM94331X28B 0X010E
+#define BCMA_BOARD_TYPE_BCM94331PCIEBT3AX 0X00E4
+#define BCMA_BOARD_TYPE_BCM94331X12_2G 0X00EC
+#define BCMA_BOARD_TYPE_BCM94331X12_5G 0X00ED
+#define BCMA_BOARD_TYPE_BCM94331X29B 0X00EF
+#define BCMA_BOARD_TYPE_BCM94331CSAX 0X00EF
+#define BCMA_BOARD_TYPE_BCM94331X19C 0X00F5
+#define BCMA_BOARD_TYPE_BCM94331X33 0X00F4
+#define BCMA_BOARD_TYPE_BCM94331BU 0X0523
+#define BCMA_BOARD_TYPE_BCM94331S9BU 0X0524
+#define BCMA_BOARD_TYPE_BCM94331MC 0X0525
+#define BCMA_BOARD_TYPE_BCM94331MCI 0X0526
+#define BCMA_BOARD_TYPE_BCM94331PCIEBT4 0X0527
+#define BCMA_BOARD_TYPE_BCM94331HM 0X0574
+#define BCMA_BOARD_TYPE_BCM94331PCIEDUAL 0X059B
+#define BCMA_BOARD_TYPE_BCM94331MCH5 0X05A9
+#define BCMA_BOARD_TYPE_BCM94331CS 0X05C6
+#define BCMA_BOARD_TYPE_BCM94331CD 0X05DA
+/* BCM53572 */
+#define BCMA_BOARD_TYPE_BCM953572BU 0X058D
+#define BCMA_BOARD_TYPE_BCM953572NR2 0X058E
+#define BCMA_BOARD_TYPE_BCM947188NR2 0X058F
+#define BCMA_BOARD_TYPE_BCM953572SDRNR2 0X0590
+/* BCM43142 */
+#define BCMA_BOARD_TYPE_BCM943142HM 0X05E0
+
struct bcma_device {
struct bcma_bus *bus;
struct bcma_device_id id;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 8390c474f69a..453fcc914683 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -104,6 +104,7 @@
#define BCMA_CC_CHIPST_4706_MIPS_BENDIAN BIT(3) /* 0: little, 1: big endian */
#define BCMA_CC_CHIPST_4706_PCIE1_DISABLE BIT(5) /* PCIE1 enable strap pin */
#define BCMA_CC_CHIPST_5357_NAND_BOOT BIT(4) /* NAND boot, valid for CC rev 38 and/or BCM5357 */
+#define BCMA_CC_CHIPST_4360_XTAL_40MZ 0x00000001
#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
#define BCMA_CC_JCMD_START 0x80000000
#define BCMA_CC_JCMD_BUSY 0x80000000
@@ -607,6 +608,8 @@ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
+extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
+
void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask);
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 8b1322296fed..c64999fd1660 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -340,13 +340,61 @@ enum ssb_bustype {
#define SSB_BOARDVENDOR_DELL 0x1028 /* Dell */
#define SSB_BOARDVENDOR_HP 0x0E11 /* HP */
/* board_type */
+#define SSB_BOARD_BCM94301CB 0x0406
+#define SSB_BOARD_BCM94301MP 0x0407
+#define SSB_BOARD_BU4309 0x040A
+#define SSB_BOARD_BCM94309CB 0x040B
+#define SSB_BOARD_BCM4309MP 0x040C
+#define SSB_BOARD_BU4306 0x0416
#define SSB_BOARD_BCM94306MP 0x0418
#define SSB_BOARD_BCM4309G 0x0421
#define SSB_BOARD_BCM4306CB 0x0417
-#define SSB_BOARD_BCM4309MP 0x040C
+#define SSB_BOARD_BCM94306PC 0x0425 /* pcmcia 3.3v 4306 card */
+#define SSB_BOARD_BCM94306CBSG 0x042B /* with SiGe PA */
+#define SSB_BOARD_PCSG94306 0x042D /* with SiGe PA */
+#define SSB_BOARD_BU4704SD 0x042E /* with sdram */
+#define SSB_BOARD_BCM94704AGR 0x042F /* dual 11a/11g Router */
+#define SSB_BOARD_BCM94308MP 0x0430 /* 11a-only minipci */
+#define SSB_BOARD_BU4318 0x0447
+#define SSB_BOARD_CB4318 0x0448
+#define SSB_BOARD_MPG4318 0x0449
#define SSB_BOARD_MP4318 0x044A
-#define SSB_BOARD_BU4306 0x0416
-#define SSB_BOARD_BU4309 0x040A
+#define SSB_BOARD_SD4318 0x044B
+#define SSB_BOARD_BCM94306P 0x044C /* with SiGe */
+#define SSB_BOARD_BCM94303MP 0x044E
+#define SSB_BOARD_BCM94306MPM 0x0450
+#define SSB_BOARD_BCM94306MPL 0x0453
+#define SSB_BOARD_PC4303 0x0454 /* pcmcia */
+#define SSB_BOARD_BCM94306MPLNA 0x0457
+#define SSB_BOARD_BCM94306MPH 0x045B
+#define SSB_BOARD_BCM94306PCIV 0x045C
+#define SSB_BOARD_BCM94318MPGH 0x0463
+#define SSB_BOARD_BU4311 0x0464
+#define SSB_BOARD_BCM94311MC 0x0465
+#define SSB_BOARD_BCM94311MCAG 0x0466
+/* 4321 boards */
+#define SSB_BOARD_BU4321 0x046B
+#define SSB_BOARD_BU4321E 0x047C
+#define SSB_BOARD_MP4321 0x046C
+#define SSB_BOARD_CB2_4321 0x046D
+#define SSB_BOARD_CB2_4321_AG 0x0066
+#define SSB_BOARD_MC4321 0x046E
+/* 4325 boards */
+#define SSB_BOARD_BCM94325DEVBU 0x0490
+#define SSB_BOARD_BCM94325BGABU 0x0491
+#define SSB_BOARD_BCM94325SDGWB 0x0492
+#define SSB_BOARD_BCM94325SDGMDL 0x04AA
+#define SSB_BOARD_BCM94325SDGMDL2 0x04C6
+#define SSB_BOARD_BCM94325SDGMDL3 0x04C9
+#define SSB_BOARD_BCM94325SDABGWBA 0x04E1
+/* 4322 boards */
+#define SSB_BOARD_BCM94322MC 0x04A4
+#define SSB_BOARD_BCM94322USB 0x04A8 /* dualband */
+#define SSB_BOARD_BCM94322HM 0x04B0
+#define SSB_BOARD_BCM94322USB2D 0x04Bf /* single band discrete front end */
+/* 4312 boards */
+#define SSB_BOARD_BU4312 0x048A
+#define SSB_BOARD_BCM4312MCGSG 0x04B5
/* chip_package */
#define SSB_CHIPPACK_BCM4712S 1 /* Small 200pin 4712 */
#define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
index 6ecfa02ddbac..3a7256955b10 100644
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -289,11 +289,11 @@
#define SSB_SPROM4_ETHPHY_ET1A_SHIFT 5
#define SSB_SPROM4_ETHPHY_ET0M (1<<14) /* MDIO for enet0 */
#define SSB_SPROM4_ETHPHY_ET1M (1<<15) /* MDIO for enet1 */
-#define SSB_SPROM4_ANTAVAIL 0x005D /* Antenna available bitfields */
-#define SSB_SPROM4_ANTAVAIL_A 0x00FF /* A-PHY bitfield */
-#define SSB_SPROM4_ANTAVAIL_A_SHIFT 0
-#define SSB_SPROM4_ANTAVAIL_BG 0xFF00 /* B-PHY and G-PHY bitfield */
-#define SSB_SPROM4_ANTAVAIL_BG_SHIFT 8
+#define SSB_SPROM4_ANTAVAIL 0x005C /* Antenna available bitfields */
+#define SSB_SPROM4_ANTAVAIL_BG 0x00FF /* B-PHY and G-PHY bitfield */
+#define SSB_SPROM4_ANTAVAIL_BG_SHIFT 0
+#define SSB_SPROM4_ANTAVAIL_A 0xFF00 /* A-PHY bitfield */
+#define SSB_SPROM4_ANTAVAIL_A_SHIFT 8
#define SSB_SPROM4_AGAIN01 0x005E /* Antenna Gain (in dBm Q5.2) */
#define SSB_SPROM4_AGAIN0 0x00FF /* Antenna 0 */
#define SSB_SPROM4_AGAIN0_SHIFT 0
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 9531beee09b5..ed6e9552252e 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -232,7 +232,7 @@ struct bt_sock_list {
};
int bt_sock_register(int proto, const struct net_proto_family *ops);
-int bt_sock_unregister(int proto);
+void bt_sock_unregister(int proto);
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
@@ -260,12 +260,22 @@ struct l2cap_ctrl {
__u8 retries;
};
+struct hci_dev;
+
+typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status);
+
+struct hci_req_ctrl {
+ bool start;
+ hci_req_complete_t complete;
+};
+
struct bt_skb_cb {
__u8 pkt_type;
__u8 incoming;
__u16 expect;
__u8 force_active;
struct l2cap_ctrl control;
+ struct hci_req_ctrl req;
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 7f12c25f1fca..b3308927a0a1 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -119,10 +119,16 @@ enum {
HCI_CONNECTABLE,
HCI_DISCOVERABLE,
HCI_LINK_SECURITY,
- HCI_PENDING_CLASS,
HCI_PERIODIC_INQ,
+ HCI_FAST_CONNECTABLE,
};
+/* A mask for the flags that are supposed to remain when a reset happens
+ * or the HCI device is closed.
+ */
+#define HCI_PERSISTENT_MASK (BIT(HCI_LE_SCAN) | BIT(HCI_PERIODIC_INQ) | \
+ BIT(HCI_FAST_CONNECTABLE))
+
/* HCI ioctl defines */
#define HCIDEVUP _IOW('H', 201, int)
#define HCIDEVDOWN _IOW('H', 202, int)
@@ -881,12 +887,25 @@ struct hci_rp_read_data_block_size {
__le16 num_blocks;
} __packed;
+#define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
+struct hci_rp_read_page_scan_activity {
+ __u8 status;
+ __le16 interval;
+ __le16 window;
+} __packed;
+
#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
struct hci_cp_write_page_scan_activity {
__le16 interval;
__le16 window;
} __packed;
+#define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46
+struct hci_rp_read_page_scan_type {
+ __u8 status;
+ __u8 type;
+} __packed;
+
#define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47
#define PAGE_SCAN_TYPE_STANDARD 0x00
#define PAGE_SCAN_TYPE_INTERLACED 0x01
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 90cf75afcb02..358a6983d3bb 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -165,6 +165,10 @@ struct hci_dev {
__u16 voice_setting;
__u8 io_capability;
__s8 inq_tx_power;
+ __u16 page_scan_interval;
+ __u16 page_scan_window;
+ __u8 page_scan_type;
+
__u16 devid_source;
__u16 devid_vendor;
__u16 devid_product;
@@ -248,8 +252,6 @@ struct hci_dev {
__u32 req_status;
__u32 req_result;
- __u16 init_last_cmd;
-
struct list_head mgmt_pending;
struct discovery_state discovery;
@@ -574,7 +576,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
return NULL;
}
-void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
+void hci_disconnect(struct hci_conn *conn, __u8 reason);
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
@@ -742,8 +744,6 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer);
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_update_ad(struct hci_dev *hdev);
-
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb);
@@ -1041,6 +1041,22 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
int hci_register_cb(struct hci_cb *hcb);
int hci_unregister_cb(struct hci_cb *hcb);
+struct hci_request {
+ struct hci_dev *hdev;
+ struct sk_buff_head cmd_q;
+
+ /* If something goes wrong when building the HCI request, the error
+ * value is stored in this field.
+ */
+ int err;
+};
+
+void hci_req_init(struct hci_request *req, struct hci_dev *hdev);
+int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
+void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param);
+void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
+void hci_req_cmd_status(struct hci_dev *hdev, u16 opcode, u8 status);
+
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
@@ -1153,7 +1169,7 @@ struct hci_sec_filter {
#define hci_req_lock(d) mutex_lock(&d->req_lock)
#define hci_req_unlock(d) mutex_unlock(&d->req_lock)
-void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
+void hci_update_ad(struct hci_request *req);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier);
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index e2e3ecad1008..7afd4199d6b6 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -158,7 +158,6 @@ struct rfcomm_session {
struct timer_list timer;
unsigned long state;
unsigned long flags;
- atomic_t refcnt;
int initiator;
/* Default DLC parameters */
@@ -276,11 +275,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src,
bdaddr_t *dst);
-static inline void rfcomm_session_hold(struct rfcomm_session *s)
-{
- atomic_inc(&s->refcnt);
-}
-
/* ---- RFCOMM sockets ---- */
struct sockaddr_rc {
sa_family_t rc_family;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cdd7cea1fd4c..dd73b8c6746b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -93,9 +93,11 @@ struct device;
* enum ieee80211_max_queues - maximum number of queues
*
* @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
+ * @IEEE80211_MAX_QUEUE_MAP: bitmap with maximum queues set
*/
enum ieee80211_max_queues {
IEEE80211_MAX_QUEUES = 16,
+ IEEE80211_MAX_QUEUE_MAP = BIT(IEEE80211_MAX_QUEUES) - 1,
};
#define IEEE80211_INVAL_HW_QUEUE 0xff
@@ -1067,6 +1069,9 @@ enum ieee80211_vif_flags {
* path needing to access it; even though the netdev carrier will always
* be off when it is %NULL there can still be races and packets could be
* processed after it switches back to %NULL.
+ * @debugfs_dir: debugfs dentry, can be used by drivers to create own per
+ * interface debug files. Note that it will be NULL for the virtual
+ * monitor interface (if that is requested.)
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *).
*/
@@ -1083,6 +1088,10 @@ struct ieee80211_vif {
u32 driver_flags;
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *debugfs_dir;
+#endif
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
@@ -1946,14 +1955,14 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
* filter those response frames except in the case of frames that
* are buffered in the driver -- those must remain buffered to avoid
* reordering. Because it is possible that no frames are released
- * in this case, the driver must call ieee80211_sta_eosp_irqsafe()
+ * in this case, the driver must call ieee80211_sta_eosp()
* to indicate to mac80211 that the service period ended anyway.
*
* Finally, if frames from multiple TIDs are released from mac80211
* but the driver might reorder them, it must clear & set the flags
* appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP)
* and also take care of the EOSP and MORE_DATA bits in the frame.
- * The driver may also use ieee80211_sta_eosp_irqsafe() in this case.
+ * The driver may also use ieee80211_sta_eosp() in this case.
*/
/**
@@ -2226,18 +2235,6 @@ enum ieee80211_roc_type {
* MAC address of the device going away.
* Hence, this callback must be implemented. It can sleep.
*
- * @add_interface_debugfs: Drivers can use this callback to add debugfs files
- * when a vif is added to mac80211. This callback and
- * @remove_interface_debugfs should be within a CONFIG_MAC80211_DEBUGFS
- * conditional. @remove_interface_debugfs must be provided for cleanup.
- * This callback can sleep.
- *
- * @remove_interface_debugfs: Remove the debugfs files which were added using
- * @add_interface_debugfs. This callback must remove all debugfs entries
- * that were added because mac80211 only removes interface debugfs when the
- * interface is destroyed, not when it is removed from the driver.
- * This callback can sleep.
- *
* @config: Handler for configuration requests. IEEE 802.11 code calls this
* function to change hardware configuration, e.g., channel.
* This function should never fail but returns a negative error code
@@ -2259,6 +2256,9 @@ enum ieee80211_roc_type {
* See the section "Frame filtering" for more information.
* This callback must be implemented and can sleep.
*
+ * @set_multicast_list: Configure the device's interface specific RX multicast
+ * filter. This callback is optional. This callback must be atomic.
+ *
* @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
* must be set or cleared for a given STA. Must be atomic.
*
@@ -2440,8 +2440,11 @@ enum ieee80211_roc_type {
* @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep.
*
* @flush: Flush all pending frames from the hardware queue, making sure
- * that the hardware queues are empty. If the parameter @drop is set
- * to %true, pending frames may be dropped. The callback can sleep.
+ * that the hardware queues are empty. The @queues parameter is a bitmap
+ * of queues to flush, which is useful if different virtual interfaces
+ * use different hardware queues; it may also indicate all queues.
+ * If the parameter @drop is set to %true, pending frames may be dropped.
+ * The callback can sleep.
*
* @channel_switch: Drivers that need (or want) to offload the channel
* switch operation for CSAs received from the AP may implement this
@@ -2506,7 +2509,7 @@ enum ieee80211_roc_type {
* setting the EOSP flag in the QoS header of the frames. Also, when the
* service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP
* on the last frame in the SP. Alternatively, it may call the function
- * ieee80211_sta_eosp_irqsafe() to inform mac80211 of the end of the SP.
+ * ieee80211_sta_eosp() to inform mac80211 of the end of the SP.
* This callback must be atomic.
* @allow_buffered_frames: Prepare device to allow the given number of frames
* to go out to the given station. The frames will be sent by mac80211
@@ -2517,7 +2520,7 @@ enum ieee80211_roc_type {
* them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
* on the last frame and clear it on all others and also handle the EOSP
* bit in the QoS header correctly. Alternatively, it can also call the
- * ieee80211_sta_eosp_irqsafe() function.
+ * ieee80211_sta_eosp() function.
* The @tids parameter is a bitmap and tells the driver which TIDs the
* frames will be on; it will at most have two bits set.
* This callback must be atomic.
@@ -2605,6 +2608,10 @@ struct ieee80211_ops {
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast);
+ void (*set_multicast_list)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, bool allmulti,
+ struct netdev_hw_addr_list *mc_list);
+
int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set);
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -2651,12 +2658,6 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
- void (*add_interface_debugfs)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct dentry *dir);
- void (*remove_interface_debugfs)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct dentry *dir);
#endif
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd, struct ieee80211_sta *sta);
@@ -2691,7 +2692,7 @@ struct ieee80211_ops {
struct netlink_callback *cb,
void *data, int len);
#endif
- void (*flush)(struct ieee80211_hw *hw, bool drop);
+ void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop);
void (*channel_switch)(struct ieee80211_hw *hw,
struct ieee80211_channel_switch *ch_switch);
int (*napi_poll)(struct ieee80211_hw *hw, int budget);
@@ -3857,14 +3858,17 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
* %IEEE80211_TX_STATUS_EOSP bit and call this function instead.
* This applies for PS-Poll as well as uAPSD.
*
- * Note that there is no non-_irqsafe version right now as
- * it wasn't needed, but just like _tx_status() and _rx()
- * must not be mixed in irqsafe/non-irqsafe versions, this
- * function must not be mixed with those either. Use the
- * all irqsafe, or all non-irqsafe, don't mix! If you need
- * the non-irqsafe version of this, you need to add it.
+ * Note that just like with _tx_status() and _rx() drivers must
+ * not mix calls to irqsafe/non-irqsafe versions, this function
+ * must not be mixed with those either. Use the all irqsafe, or
+ * all non-irqsafe, don't mix!
+ *
+ * NB: the _irqsafe version of this function doesn't exist, no
+ * driver needs it right now. Don't call this function if
+ * you'd need the _irqsafe version, look at the git history
+ * and restore the _irqsafe version!
*/
-void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta);
+void ieee80211_sta_eosp(struct ieee80211_sta *pubsta);
/**
* ieee80211_iter_keys - iterate keys programmed into the device
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index eb0f4b16ff09..17f33a62f6db 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -397,13 +397,12 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
if (ctrl) {
u8 *assoc;
- assoc = kzalloc(assoc_len, GFP_KERNEL);
+ assoc = kmemdup(rsp->amp_assoc, assoc_len, GFP_KERNEL);
if (!assoc) {
amp_ctrl_put(ctrl);
return -ENOMEM;
}
- memcpy(assoc, rsp->amp_assoc, assoc_len);
ctrl->assoc = assoc;
ctrl->assoc_len = assoc_len;
ctrl->assoc_rem_len = assoc_len;
@@ -472,13 +471,12 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req);
u8 *assoc;
- assoc = kzalloc(assoc_len, GFP_KERNEL);
+ assoc = kmemdup(req->amp_assoc, assoc_len, GFP_KERNEL);
if (!assoc) {
amp_ctrl_put(ctrl);
return -ENOMEM;
}
- memcpy(assoc, req->amp_assoc, assoc_len);
ctrl->assoc = assoc;
ctrl->assoc_len = assoc_len;
ctrl->assoc_rem_len = assoc_len;
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index d5a973bf8a6f..e5338f787d68 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -92,23 +92,14 @@ int bt_sock_register(int proto, const struct net_proto_family *ops)
}
EXPORT_SYMBOL(bt_sock_register);
-int bt_sock_unregister(int proto)
+void bt_sock_unregister(int proto)
{
- int err = 0;
-
if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
+ return;
write_lock(&bt_proto_lock);
-
- if (!bt_proto[proto])
- err = -ENOENT;
- else
- bt_proto[proto] = NULL;
-
+ bt_proto[proto] = NULL;
write_unlock(&bt_proto_lock);
-
- return err;
}
EXPORT_SYMBOL(bt_sock_unregister);
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index e7154a58465f..5b1c04e28821 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -253,8 +253,6 @@ error:
void __exit bnep_sock_cleanup(void)
{
bt_procfs_cleanup(&init_net, "bnep");
- if (bt_sock_unregister(BTPROTO_BNEP) < 0)
- BT_ERR("Can't unregister BNEP socket");
-
+ bt_sock_unregister(BTPROTO_BNEP);
proto_unregister(&bnep_proto);
}
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 1c57482112b6..58d9edebab4b 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -264,8 +264,6 @@ error:
void cmtp_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "cmtp");
- if (bt_sock_unregister(BTPROTO_CMTP) < 0)
- BT_ERR("Can't unregister CMTP socket");
-
+ bt_sock_unregister(BTPROTO_CMTP);
proto_unregister(&cmtp_proto);
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 4925a02ae7e4..b9f90169940b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -117,7 +117,7 @@ static void hci_acl_create_connection_cancel(struct hci_conn *conn)
hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
}
-void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
+void hci_disconnect(struct hci_conn *conn, __u8 reason)
{
struct hci_cp_disconnect cp;
@@ -253,7 +253,7 @@ static void hci_conn_disconnect(struct hci_conn *conn)
hci_amp_disconn(conn, reason);
break;
default:
- hci_acl_disconn(conn, reason);
+ hci_disconnect(conn, reason);
break;
}
}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 60793e7b768b..cfcad5423f1c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -57,36 +57,9 @@ static void hci_notify(struct hci_dev *hdev, int event)
/* ---- HCI requests ---- */
-void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
+static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
{
- BT_DBG("%s command 0x%4.4x result 0x%2.2x", hdev->name, cmd, result);
-
- /* If this is the init phase check if the completed command matches
- * the last init command, and if not just return.
- */
- if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) {
- struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
- u16 opcode = __le16_to_cpu(sent->opcode);
- struct sk_buff *skb;
-
- /* Some CSR based controllers generate a spontaneous
- * reset complete event during init and any pending
- * command will never be completed. In such a case we
- * need to resend whatever was the last sent
- * command.
- */
-
- if (cmd != HCI_OP_RESET || opcode == HCI_OP_RESET)
- return;
-
- skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC);
- if (skb) {
- skb_queue_head(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
-
- return;
- }
+ BT_DBG("%s result 0x%2.2x", hdev->name, result);
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = result;
@@ -107,21 +80,41 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
}
/* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev,
- void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+static int __hci_req_sync(struct hci_dev *hdev,
+ void (*func)(struct hci_request *req,
+ unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
+ struct hci_request req;
DECLARE_WAITQUEUE(wait, current);
int err = 0;
BT_DBG("%s start", hdev->name);
+ hci_req_init(&req, hdev);
+
hdev->req_status = HCI_REQ_PEND;
+ func(&req, opt);
+
+ err = hci_req_run(&req, hci_req_sync_complete);
+ if (err < 0) {
+ hdev->req_status = 0;
+
+ /* ENODATA means the HCI request command queue is empty.
+ * This can happen when a request with conditionals doesn't
+ * trigger any commands to be sent. This is normal behavior
+ * and should not trigger an error return.
+ */
+ if (err == -ENODATA)
+ return 0;
+
+ return err;
+ }
+
add_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- req(hdev, opt);
schedule_timeout(timeout);
remove_wait_queue(&hdev->req_wait_q, &wait);
@@ -150,9 +143,10 @@ static int __hci_request(struct hci_dev *hdev,
return err;
}
-static int hci_request(struct hci_dev *hdev,
- void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+static int hci_req_sync(struct hci_dev *hdev,
+ void (*req)(struct hci_request *req,
+ unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
int ret;
@@ -161,75 +155,86 @@ static int hci_request(struct hci_dev *hdev,
/* Serialize all requests */
hci_req_lock(hdev);
- ret = __hci_request(hdev, req, opt, timeout);
+ ret = __hci_req_sync(hdev, req, opt, timeout);
hci_req_unlock(hdev);
return ret;
}
-static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_reset_req(struct hci_request *req, unsigned long opt)
{
- BT_DBG("%s %ld", hdev->name, opt);
+ BT_DBG("%s %ld", req->hdev->name, opt);
/* Reset device */
- set_bit(HCI_RESET, &hdev->flags);
- hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
+ set_bit(HCI_RESET, &req->hdev->flags);
+ hci_req_add(req, HCI_OP_RESET, 0, NULL);
}
-static void bredr_init(struct hci_dev *hdev)
+static void bredr_init(struct hci_request *req)
{
- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
+ req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
/* Read Local Supported Features */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
/* Read Local Version */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
+
+ /* Read BD Address */
+ hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL);
}
-static void amp_init(struct hci_dev *hdev)
+static void amp_init(struct hci_request *req)
{
- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
+ req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
/* Read Local Version */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
/* Read Local AMP Info */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
/* Read Data Blk size */
- hci_send_cmd(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
}
-static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_init1_req(struct hci_request *req, unsigned long opt)
{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_request init_req;
struct sk_buff *skb;
BT_DBG("%s %ld", hdev->name, opt);
/* Driver initialization */
+ hci_req_init(&init_req, hdev);
+
/* Special commands */
while ((skb = skb_dequeue(&hdev->driver_init))) {
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev;
- skb_queue_tail(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
+ if (skb_queue_empty(&init_req.cmd_q))
+ bt_cb(skb)->req.start = true;
+
+ skb_queue_tail(&init_req.cmd_q, skb);
}
skb_queue_purge(&hdev->driver_init);
+ hci_req_run(&init_req, NULL);
+
/* Reset */
if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
- hci_reset_req(hdev, 0);
+ hci_reset_req(req, 0);
switch (hdev->dev_type) {
case HCI_BREDR:
- bredr_init(hdev);
+ bredr_init(req);
break;
case HCI_AMP:
- amp_init(hdev);
+ amp_init(req);
break;
default:
@@ -238,44 +243,327 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
}
}
-static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
+static void bredr_setup(struct hci_request *req)
+{
+ struct hci_cp_delete_stored_link_key cp;
+ __le16 param;
+ __u8 flt_type;
+
+ /* Read Buffer Size (ACL mtu, max pkt, etc.) */
+ hci_req_add(req, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
+
+ /* Read Class of Device */
+ hci_req_add(req, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+
+ /* Read Local Name */
+ hci_req_add(req, HCI_OP_READ_LOCAL_NAME, 0, NULL);
+
+ /* Read Voice Setting */
+ hci_req_add(req, HCI_OP_READ_VOICE_SETTING, 0, NULL);
+
+ /* Clear Event Filters */
+ flt_type = HCI_FLT_CLEAR_ALL;
+ hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
+
+ /* Connection accept timeout ~20 secs */
+ param = __constant_cpu_to_le16(0x7d00);
+ hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
+
+ bacpy(&cp.bdaddr, BDADDR_ANY);
+ cp.delete_all = 0x01;
+ hci_req_add(req, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
+
+ /* Read page scan parameters */
+ if (req->hdev->hci_ver > BLUETOOTH_VER_1_1) {
+ hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_PAGE_SCAN_TYPE, 0, NULL);
+ }
+}
+
+static void le_setup(struct hci_request *req)
+{
+ /* Read LE Buffer Size */
+ hci_req_add(req, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+
+ /* Read LE Local Supported Features */
+ hci_req_add(req, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
+
+ /* Read LE Advertising Channel TX Power */
+ hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
+
+ /* Read LE White List Size */
+ hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
+
+ /* Read LE Supported States */
+ hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
+}
+
+static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
+{
+ if (lmp_ext_inq_capable(hdev))
+ return 0x02;
+
+ if (lmp_inq_rssi_capable(hdev))
+ return 0x01;
+
+ if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
+ hdev->lmp_subver == 0x0757)
+ return 0x01;
+
+ if (hdev->manufacturer == 15) {
+ if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
+ return 0x01;
+ if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
+ return 0x01;
+ if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
+ return 0x01;
+ }
+
+ if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
+ hdev->lmp_subver == 0x1805)
+ return 0x01;
+
+ return 0x00;
+}
+
+static void hci_setup_inquiry_mode(struct hci_request *req)
+{
+ u8 mode;
+
+ mode = hci_get_inquiry_mode(req->hdev);
+
+ hci_req_add(req, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
+}
+
+static void hci_setup_event_mask(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+
+ /* The second byte is 0xff instead of 0x9f (two reserved bits
+ * disabled) since a Broadcom 1.2 dongle doesn't respond to the
+ * command otherwise.
+ */
+ u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
+
+ /* CSR 1.1 dongles does not accept any bitfield so don't try to set
+ * any event mask for pre 1.2 devices.
+ */
+ if (hdev->hci_ver < BLUETOOTH_VER_1_2)
+ return;
+
+ if (lmp_bredr_capable(hdev)) {
+ events[4] |= 0x01; /* Flow Specification Complete */
+ events[4] |= 0x02; /* Inquiry Result with RSSI */
+ events[4] |= 0x04; /* Read Remote Extended Features Complete */
+ events[5] |= 0x08; /* Synchronous Connection Complete */
+ events[5] |= 0x10; /* Synchronous Connection Changed */
+ }
+
+ if (lmp_inq_rssi_capable(hdev))
+ events[4] |= 0x02; /* Inquiry Result with RSSI */
+
+ if (lmp_sniffsubr_capable(hdev))
+ events[5] |= 0x20; /* Sniff Subrating */
+
+ if (lmp_pause_enc_capable(hdev))
+ events[5] |= 0x80; /* Encryption Key Refresh Complete */
+
+ if (lmp_ext_inq_capable(hdev))
+ events[5] |= 0x40; /* Extended Inquiry Result */
+
+ if (lmp_no_flush_capable(hdev))
+ events[7] |= 0x01; /* Enhanced Flush Complete */
+
+ if (lmp_lsto_capable(hdev))
+ events[6] |= 0x80; /* Link Supervision Timeout Changed */
+
+ if (lmp_ssp_capable(hdev)) {
+ events[6] |= 0x01; /* IO Capability Request */
+ events[6] |= 0x02; /* IO Capability Response */
+ events[6] |= 0x04; /* User Confirmation Request */
+ events[6] |= 0x08; /* User Passkey Request */
+ events[6] |= 0x10; /* Remote OOB Data Request */
+ events[6] |= 0x20; /* Simple Pairing Complete */
+ events[7] |= 0x04; /* User Passkey Notification */
+ events[7] |= 0x08; /* Keypress Notification */
+ events[7] |= 0x10; /* Remote Host Supported
+ * Features Notification
+ */
+ }
+
+ if (lmp_le_capable(hdev))
+ events[7] |= 0x20; /* LE Meta-Event */
+
+ hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
+
+ if (lmp_le_capable(hdev)) {
+ memset(events, 0, sizeof(events));
+ events[0] = 0x1f;
+ hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK,
+ sizeof(events), events);
+ }
+}
+
+static void hci_init2_req(struct hci_request *req, unsigned long opt)
+{
+ struct hci_dev *hdev = req->hdev;
+
+ if (lmp_bredr_capable(hdev))
+ bredr_setup(req);
+
+ if (lmp_le_capable(hdev))
+ le_setup(req);
+
+ hci_setup_event_mask(req);
+
+ if (hdev->hci_ver > BLUETOOTH_VER_1_1)
+ hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
+
+ if (lmp_ssp_capable(hdev)) {
+ if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+ u8 mode = 0x01;
+ hci_req_add(req, HCI_OP_WRITE_SSP_MODE,
+ sizeof(mode), &mode);
+ } else {
+ struct hci_cp_write_eir cp;
+
+ memset(hdev->eir, 0, sizeof(hdev->eir));
+ memset(&cp, 0, sizeof(cp));
+
+ hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+ }
+ }
+
+ if (lmp_inq_rssi_capable(hdev))
+ hci_setup_inquiry_mode(req);
+
+ if (lmp_inq_tx_pwr_capable(hdev))
+ hci_req_add(req, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
+
+ if (lmp_ext_feat_capable(hdev)) {
+ struct hci_cp_read_local_ext_features cp;
+
+ cp.page = 0x01;
+ hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES,
+ sizeof(cp), &cp);
+ }
+
+ if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
+ u8 enable = 1;
+ hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
+ &enable);
+ }
+}
+
+static void hci_setup_link_policy(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_write_def_link_policy cp;
+ u16 link_policy = 0;
+
+ if (lmp_rswitch_capable(hdev))
+ link_policy |= HCI_LP_RSWITCH;
+ if (lmp_hold_capable(hdev))
+ link_policy |= HCI_LP_HOLD;
+ if (lmp_sniff_capable(hdev))
+ link_policy |= HCI_LP_SNIFF;
+ if (lmp_park_capable(hdev))
+ link_policy |= HCI_LP_PARK;
+
+ cp.policy = cpu_to_le16(link_policy);
+ hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
+}
+
+static void hci_set_le_support(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_write_le_host_supported cp;
+
+ memset(&cp, 0, sizeof(cp));
+
+ if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+ cp.le = 0x01;
+ cp.simul = lmp_le_br_capable(hdev);
+ }
+
+ if (cp.le != lmp_host_le_capable(hdev))
+ hci_req_add(req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
+ &cp);
+}
+
+static void hci_init3_req(struct hci_request *req, unsigned long opt)
+{
+ struct hci_dev *hdev = req->hdev;
+
+ if (hdev->commands[5] & 0x10)
+ hci_setup_link_policy(req);
+
+ if (lmp_le_capable(hdev)) {
+ hci_set_le_support(req);
+ hci_update_ad(req);
+ }
+}
+
+static int __hci_init(struct hci_dev *hdev)
+{
+ int err;
+
+ err = __hci_req_sync(hdev, hci_init1_req, 0, HCI_INIT_TIMEOUT);
+ if (err < 0)
+ return err;
+
+ /* HCI_BREDR covers both single-mode LE, BR/EDR and dual-mode
+ * BR/EDR/LE type controllers. AMP controllers only need the
+ * first stage init.
+ */
+ if (hdev->dev_type != HCI_BREDR)
+ return 0;
+
+ err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT);
+ if (err < 0)
+ return err;
+
+ return __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT);
+}
+
+static void hci_scan_req(struct hci_request *req, unsigned long opt)
{
__u8 scan = opt;
- BT_DBG("%s %x", hdev->name, scan);
+ BT_DBG("%s %x", req->hdev->name, scan);
/* Inquiry and Page scans */
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+ hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}
-static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_auth_req(struct hci_request *req, unsigned long opt)
{
__u8 auth = opt;
- BT_DBG("%s %x", hdev->name, auth);
+ BT_DBG("%s %x", req->hdev->name, auth);
/* Authentication */
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
+ hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
}
-static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_encrypt_req(struct hci_request *req, unsigned long opt)
{
__u8 encrypt = opt;
- BT_DBG("%s %x", hdev->name, encrypt);
+ BT_DBG("%s %x", req->hdev->name, encrypt);
/* Encryption */
- hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
+ hci_req_add(req, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
}
-static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_linkpol_req(struct hci_request *req, unsigned long opt)
{
__le16 policy = cpu_to_le16(opt);
- BT_DBG("%s %x", hdev->name, policy);
+ BT_DBG("%s %x", req->hdev->name, policy);
/* Default link policy */
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
+ hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
}
/* Get HCI device by index.
@@ -512,9 +800,10 @@ static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
return copied;
}
-static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_inq_req(struct hci_request *req, unsigned long opt)
{
struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_inquiry cp;
BT_DBG("%s", hdev->name);
@@ -526,7 +815,7 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
memcpy(&cp.lap, &ir->lap, 3);
cp.length = ir->length;
cp.num_rsp = ir->num_rsp;
- hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
}
int hci_inquiry(void __user *arg)
@@ -556,7 +845,8 @@ int hci_inquiry(void __user *arg)
timeo = ir.length * msecs_to_jiffies(2000);
if (do_inquiry) {
- err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo);
+ err = hci_req_sync(hdev, hci_inq_req, (unsigned long) &ir,
+ timeo);
if (err < 0)
goto done;
}
@@ -654,39 +944,29 @@ static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}
-int hci_update_ad(struct hci_dev *hdev)
+void hci_update_ad(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
u8 len;
- int err;
- hci_dev_lock(hdev);
-
- if (!lmp_le_capable(hdev)) {
- err = -EINVAL;
- goto unlock;
- }
+ if (!lmp_le_capable(hdev))
+ return;
memset(&cp, 0, sizeof(cp));
len = create_ad(hdev, cp.data);
if (hdev->adv_data_len == len &&
- memcmp(cp.data, hdev->adv_data, len) == 0) {
- err = 0;
- goto unlock;
- }
+ memcmp(cp.data, hdev->adv_data, len) == 0)
+ return;
memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
hdev->adv_data_len = len;
cp.length = len;
- err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
-unlock:
- hci_dev_unlock(hdev);
-
- return err;
+ hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}
/* ---- HCI ioctl helpers ---- */
@@ -735,10 +1015,7 @@ int hci_dev_open(__u16 dev)
if (!test_bit(HCI_RAW, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
set_bit(HCI_INIT, &hdev->flags);
- hdev->init_last_cmd = 0;
-
- ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
-
+ ret = __hci_init(hdev);
clear_bit(HCI_INIT, &hdev->flags);
}
@@ -746,7 +1023,6 @@ int hci_dev_open(__u16 dev)
hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP);
- hci_update_ad(hdev);
if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
@@ -828,7 +1104,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
if (!test_bit(HCI_RAW, &hdev->flags) &&
test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
set_bit(HCI_INIT, &hdev->flags);
- __hci_request(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
+ __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
clear_bit(HCI_INIT, &hdev->flags);
}
@@ -851,6 +1127,10 @@ static int hci_dev_do_close(struct hci_dev *hdev)
* and no tasks are scheduled. */
hdev->close(hdev);
+ /* Clear flags */
+ hdev->flags = 0;
+ hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
+
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
@@ -858,9 +1138,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_unlock(hdev);
}
- /* Clear flags */
- hdev->flags = 0;
-
/* Controller radio is available but is currently powered down */
hdev->amp_status = 0;
@@ -921,7 +1198,7 @@ int hci_dev_reset(__u16 dev)
hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
if (!test_bit(HCI_RAW, &hdev->flags))
- ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
+ ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
done:
hci_req_unlock(hdev);
@@ -960,8 +1237,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
switch (cmd) {
case HCISETAUTH:
- err = hci_request(hdev, hci_auth_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
break;
case HCISETENCRYPT:
@@ -972,24 +1249,24 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
if (!test_bit(HCI_AUTH, &hdev->flags)) {
/* Auth must be enabled first */
- err = hci_request(hdev, hci_auth_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
if (err)
break;
}
- err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_encrypt_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
break;
case HCISETSCAN:
- err = hci_request(hdev, hci_scan_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
break;
case HCISETLINKPOL:
- err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_linkpol_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
break;
case HCISETLINKMODE:
@@ -1566,7 +1843,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return mgmt_device_unblocked(hdev, bdaddr, type);
}
-static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
+static void le_scan_param_req(struct hci_request *req, unsigned long opt)
{
struct le_scan_params *param = (struct le_scan_params *) opt;
struct hci_cp_le_set_scan_param cp;
@@ -1576,10 +1853,10 @@ static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
cp.interval = cpu_to_le16(param->interval);
cp.window = cpu_to_le16(param->window);
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
}
-static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
+static void le_scan_enable_req(struct hci_request *req, unsigned long opt)
{
struct hci_cp_le_set_scan_enable cp;
@@ -1587,7 +1864,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
cp.enable = 1;
cp.filter_dup = 1;
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
}
static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
@@ -1608,10 +1885,10 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
hci_req_lock(hdev);
- err = __hci_request(hdev, le_scan_param_req, (unsigned long) &param,
- timeo);
+ err = __hci_req_sync(hdev, le_scan_param_req, (unsigned long) &param,
+ timeo);
if (!err)
- err = __hci_request(hdev, le_scan_enable_req, 0, timeo);
+ err = __hci_req_sync(hdev, le_scan_enable_req, 0, timeo);
hci_req_unlock(hdev);
@@ -2160,20 +2437,55 @@ static int hci_send_frame(struct sk_buff *skb)
return hdev->send(skb);
}
-/* Send HCI command */
-int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
+void hci_req_init(struct hci_request *req, struct hci_dev *hdev)
+{
+ skb_queue_head_init(&req->cmd_q);
+ req->hdev = hdev;
+ req->err = 0;
+}
+
+int hci_req_run(struct hci_request *req, hci_req_complete_t complete)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ BT_DBG("length %u", skb_queue_len(&req->cmd_q));
+
+ /* If an error occured during request building, remove all HCI
+ * commands queued on the HCI request queue.
+ */
+ if (req->err) {
+ skb_queue_purge(&req->cmd_q);
+ return req->err;
+ }
+
+ /* Do not allow empty requests */
+ if (skb_queue_empty(&req->cmd_q))
+ return -ENODATA;
+
+ skb = skb_peek_tail(&req->cmd_q);
+ bt_cb(skb)->req.complete = complete;
+
+ spin_lock_irqsave(&hdev->cmd_q.lock, flags);
+ skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
+ spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
+
+ queue_work(hdev->workqueue, &hdev->cmd_work);
+
+ return 0;
+}
+
+static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode,
+ u32 plen, void *param)
{
int len = HCI_COMMAND_HDR_SIZE + plen;
struct hci_command_hdr *hdr;
struct sk_buff *skb;
- BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
-
skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for command", hdev->name);
- return -ENOMEM;
- }
+ if (!skb)
+ return NULL;
hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
hdr->opcode = cpu_to_le16(opcode);
@@ -2187,8 +2499,26 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev;
- if (test_bit(HCI_INIT, &hdev->flags))
- hdev->init_last_cmd = opcode;
+ return skb;
+}
+
+/* Send HCI command */
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
+{
+ struct sk_buff *skb;
+
+ BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
+
+ skb = hci_prepare_cmd(hdev, opcode, plen, param);
+ if (!skb) {
+ BT_ERR("%s no memory for command", hdev->name);
+ return -ENOMEM;
+ }
+
+ /* Stand-alone HCI commands must be flaged as
+ * single-command requests.
+ */
+ bt_cb(skb)->req.start = true;
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
@@ -2196,6 +2526,34 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
return 0;
}
+/* Queue a command to an asynchronous HCI request */
+void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct sk_buff *skb;
+
+ BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
+
+ /* If an error occured during request building, there is no point in
+ * queueing the HCI command. We can simply return.
+ */
+ if (req->err)
+ return;
+
+ skb = hci_prepare_cmd(hdev, opcode, plen, param);
+ if (!skb) {
+ BT_ERR("%s no memory for command (opcode 0x%4.4x)",
+ hdev->name, opcode);
+ req->err = -ENOMEM;
+ return;
+ }
+
+ if (skb_queue_empty(&req->cmd_q))
+ bt_cb(skb)->req.start = true;
+
+ skb_queue_tail(&req->cmd_q, skb);
+}
+
/* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
{
@@ -2398,7 +2756,7 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
if (c->type == type && c->sent) {
BT_ERR("%s killing stalled connection %pMR",
hdev->name, &c->dst);
- hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
+ hci_disconnect(c, HCI_ERROR_REMOTE_USER_TERM);
}
}
@@ -2860,6 +3218,123 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
kfree_skb(skb);
}
+static bool hci_req_is_complete(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+
+ skb = skb_peek(&hdev->cmd_q);
+ if (!skb)
+ return true;
+
+ return bt_cb(skb)->req.start;
+}
+
+static void hci_resend_last(struct hci_dev *hdev)
+{
+ struct hci_command_hdr *sent;
+ struct sk_buff *skb;
+ u16 opcode;
+
+ if (!hdev->sent_cmd)
+ return;
+
+ sent = (void *) hdev->sent_cmd->data;
+ opcode = __le16_to_cpu(sent->opcode);
+ if (opcode == HCI_OP_RESET)
+ return;
+
+ skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ skb_queue_head(&hdev->cmd_q, skb);
+ queue_work(hdev->workqueue, &hdev->cmd_work);
+}
+
+void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
+{
+ hci_req_complete_t req_complete = NULL;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ BT_DBG("opcode 0x%04x status 0x%02x", opcode, status);
+
+ /* If the completed command doesn't match the last one that was
+ * sent we need to do special handling of it.
+ */
+ if (!hci_sent_cmd_data(hdev, opcode)) {
+ /* Some CSR based controllers generate a spontaneous
+ * reset complete event during init and any pending
+ * command will never be completed. In such a case we
+ * need to resend whatever was the last sent
+ * command.
+ */
+ if (test_bit(HCI_INIT, &hdev->flags) && opcode == HCI_OP_RESET)
+ hci_resend_last(hdev);
+
+ return;
+ }
+
+ /* If the command succeeded and there's still more commands in
+ * this request the request is not yet complete.
+ */
+ if (!status && !hci_req_is_complete(hdev))
+ return;
+
+ /* If this was the last command in a request the complete
+ * callback would be found in hdev->sent_cmd instead of the
+ * command queue (hdev->cmd_q).
+ */
+ if (hdev->sent_cmd) {
+ req_complete = bt_cb(hdev->sent_cmd)->req.complete;
+ if (req_complete)
+ goto call_complete;
+ }
+
+ /* Remove all pending commands belonging to this request */
+ spin_lock_irqsave(&hdev->cmd_q.lock, flags);
+ while ((skb = __skb_dequeue(&hdev->cmd_q))) {
+ if (bt_cb(skb)->req.start) {
+ __skb_queue_head(&hdev->cmd_q, skb);
+ break;
+ }
+
+ req_complete = bt_cb(skb)->req.complete;
+ kfree_skb(skb);
+ }
+ spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
+
+call_complete:
+ if (req_complete)
+ req_complete(hdev, status);
+}
+
+void hci_req_cmd_status(struct hci_dev *hdev, u16 opcode, u8 status)
+{
+ hci_req_complete_t req_complete = NULL;
+
+ BT_DBG("opcode 0x%04x status 0x%02x", opcode, status);
+
+ if (status) {
+ hci_req_cmd_complete(hdev, opcode, status);
+ return;
+ }
+
+ /* No need to handle success status if there are more commands */
+ if (!hci_req_is_complete(hdev))
+ return;
+
+ if (hdev->sent_cmd)
+ req_complete = bt_cb(hdev->sent_cmd)->req.complete;
+
+ /* If the request doesn't have a complete callback or there
+ * are other commands/requests in the hdev queue we consider
+ * this request as completed.
+ */
+ if (!req_complete || !skb_queue_empty(&hdev->cmd_q))
+ hci_req_cmd_complete(hdev, opcode, status);
+}
+
static void hci_rx_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 477726a63512..138580745c2c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -53,7 +53,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev);
- hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
+ hci_req_cmd_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev);
}
@@ -183,8 +183,6 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
if (!status)
hdev->link_policy = get_unaligned_le16(sent);
-
- hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status);
}
static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
@@ -195,11 +193,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_RESET, &hdev->flags);
- hci_req_complete(hdev, HCI_OP_RESET, status);
-
/* Reset all non-persistent flags */
- hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS) |
- BIT(HCI_PERIODIC_INQ));
+ hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
hdev->discovery.state = DISCOVERY_STOPPED;
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
@@ -228,11 +223,6 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
hci_dev_unlock(hdev);
-
- if (!status && !test_bit(HCI_INIT, &hdev->flags))
- hci_update_ad(hdev);
-
- hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
}
static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -270,8 +260,6 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_auth_enable_complete(hdev, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
}
static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
@@ -293,8 +281,6 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
else
clear_bit(HCI_ENCRYPT, &hdev->flags);
}
-
- hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status);
}
static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
@@ -343,7 +329,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
done:
hci_dev_unlock(hdev);
- hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
}
static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
@@ -435,15 +420,6 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev,
hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
}
-static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
-}
-
static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -472,211 +448,6 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
}
}
-static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
-{
- if (lmp_ext_inq_capable(hdev))
- return 2;
-
- if (lmp_inq_rssi_capable(hdev))
- return 1;
-
- if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
- hdev->lmp_subver == 0x0757)
- return 1;
-
- if (hdev->manufacturer == 15) {
- if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
- return 1;
- }
-
- if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
- hdev->lmp_subver == 0x1805)
- return 1;
-
- return 0;
-}
-
-static void hci_setup_inquiry_mode(struct hci_dev *hdev)
-{
- u8 mode;
-
- mode = hci_get_inquiry_mode(hdev);
-
- hci_send_cmd(hdev, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
-}
-
-static void hci_setup_event_mask(struct hci_dev *hdev)
-{
- /* The second byte is 0xff instead of 0x9f (two reserved bits
- * disabled) since a Broadcom 1.2 dongle doesn't respond to the
- * command otherwise */
- u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
- /* CSR 1.1 dongles does not accept any bitfield so don't try to set
- * any event mask for pre 1.2 devices */
- if (hdev->hci_ver < BLUETOOTH_VER_1_2)
- return;
-
- if (lmp_bredr_capable(hdev)) {
- events[4] |= 0x01; /* Flow Specification Complete */
- events[4] |= 0x02; /* Inquiry Result with RSSI */
- events[4] |= 0x04; /* Read Remote Extended Features Complete */
- events[5] |= 0x08; /* Synchronous Connection Complete */
- events[5] |= 0x10; /* Synchronous Connection Changed */
- }
-
- if (lmp_inq_rssi_capable(hdev))
- events[4] |= 0x02; /* Inquiry Result with RSSI */
-
- if (lmp_sniffsubr_capable(hdev))
- events[5] |= 0x20; /* Sniff Subrating */
-
- if (lmp_pause_enc_capable(hdev))
- events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
- if (lmp_ext_inq_capable(hdev))
- events[5] |= 0x40; /* Extended Inquiry Result */
-
- if (lmp_no_flush_capable(hdev))
- events[7] |= 0x01; /* Enhanced Flush Complete */
-
- if (lmp_lsto_capable(hdev))
- events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
- if (lmp_ssp_capable(hdev)) {
- events[6] |= 0x01; /* IO Capability Request */
- events[6] |= 0x02; /* IO Capability Response */
- events[6] |= 0x04; /* User Confirmation Request */
- events[6] |= 0x08; /* User Passkey Request */
- events[6] |= 0x10; /* Remote OOB Data Request */
- events[6] |= 0x20; /* Simple Pairing Complete */
- events[7] |= 0x04; /* User Passkey Notification */
- events[7] |= 0x08; /* Keypress Notification */
- events[7] |= 0x10; /* Remote Host Supported
- * Features Notification */
- }
-
- if (lmp_le_capable(hdev))
- events[7] |= 0x20; /* LE Meta-Event */
-
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
-
- if (lmp_le_capable(hdev)) {
- memset(events, 0, sizeof(events));
- events[0] = 0x1f;
- hci_send_cmd(hdev, HCI_OP_LE_SET_EVENT_MASK,
- sizeof(events), events);
- }
-}
-
-static void bredr_setup(struct hci_dev *hdev)
-{
- struct hci_cp_delete_stored_link_key cp;
- __le16 param;
- __u8 flt_type;
-
- /* Read Buffer Size (ACL mtu, max pkt, etc.) */
- hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
-
- /* Read Class of Device */
- hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
-
- /* Read Local Name */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
- /* Read Voice Setting */
- hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
-
- /* Clear Event Filters */
- flt_type = HCI_FLT_CLEAR_ALL;
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
-
- /* Connection accept timeout ~20 secs */
- param = __constant_cpu_to_le16(0x7d00);
- hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
-
- bacpy(&cp.bdaddr, BDADDR_ANY);
- cp.delete_all = 1;
- hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
-}
-
-static void le_setup(struct hci_dev *hdev)
-{
- /* Read LE Buffer Size */
- hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
-
- /* Read LE Local Supported Features */
- hci_send_cmd(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
-
- /* Read LE Advertising Channel TX Power */
- hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
-
- /* Read LE White List Size */
- hci_send_cmd(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
-
- /* Read LE Supported States */
- hci_send_cmd(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
-}
-
-static void hci_setup(struct hci_dev *hdev)
-{
- if (hdev->dev_type != HCI_BREDR)
- return;
-
- /* Read BD Address */
- hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
-
- if (lmp_bredr_capable(hdev))
- bredr_setup(hdev);
-
- if (lmp_le_capable(hdev))
- le_setup(hdev);
-
- hci_setup_event_mask(hdev);
-
- if (hdev->hci_ver > BLUETOOTH_VER_1_1)
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
-
- if (lmp_ssp_capable(hdev)) {
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
- u8 mode = 0x01;
- hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
- sizeof(mode), &mode);
- } else {
- struct hci_cp_write_eir cp;
-
- memset(hdev->eir, 0, sizeof(hdev->eir));
- memset(&cp, 0, sizeof(cp));
-
- hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
- }
- }
-
- if (lmp_inq_rssi_capable(hdev))
- hci_setup_inquiry_mode(hdev);
-
- if (lmp_inq_tx_pwr_capable(hdev))
- hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
-
- if (lmp_ext_feat_capable(hdev)) {
- struct hci_cp_read_local_ext_features cp;
-
- cp.page = 0x01;
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp),
- &cp);
- }
-
- if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
- u8 enable = 1;
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
- &enable);
- }
-}
-
static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_local_version *rp = (void *) skb->data;
@@ -684,7 +455,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
- goto done;
+ return;
hdev->hci_ver = rp->hci_ver;
hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
@@ -694,30 +465,6 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s manufacturer 0x%4.4x hci ver %d:%d", hdev->name,
hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
-
- if (test_bit(HCI_INIT, &hdev->flags))
- hci_setup(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status);
-}
-
-static void hci_setup_link_policy(struct hci_dev *hdev)
-{
- struct hci_cp_write_def_link_policy cp;
- u16 link_policy = 0;
-
- if (lmp_rswitch_capable(hdev))
- link_policy |= HCI_LP_RSWITCH;
- if (lmp_hold_capable(hdev))
- link_policy |= HCI_LP_HOLD;
- if (lmp_sniff_capable(hdev))
- link_policy |= HCI_LP_SNIFF;
- if (lmp_park_capable(hdev))
- link_policy |= HCI_LP_PARK;
-
- cp.policy = cpu_to_le16(link_policy);
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
}
static void hci_cc_read_local_commands(struct hci_dev *hdev,
@@ -727,16 +474,8 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- goto done;
-
- memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
-
- if (test_bit(HCI_INIT, &hdev->flags) && (hdev->commands[5] & 0x10))
- hci_setup_link_policy(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
+ if (!rp->status)
+ memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
}
static void hci_cc_read_local_features(struct hci_dev *hdev,
@@ -795,22 +534,6 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
hdev->features[6], hdev->features[7]);
}
-static void hci_set_le_support(struct hci_dev *hdev)
-{
- struct hci_cp_write_le_host_supported cp;
-
- memset(&cp, 0, sizeof(cp));
-
- if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
- cp.le = 1;
- cp.simul = lmp_le_br_capable(hdev);
- }
-
- if (cp.le != lmp_host_le_capable(hdev))
- hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
- &cp);
-}
-
static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -819,7 +542,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
- goto done;
+ return;
switch (rp->page) {
case 0:
@@ -829,12 +552,6 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
memcpy(hdev->host_features, rp->features, 8);
break;
}
-
- if (test_bit(HCI_INIT, &hdev->flags) && lmp_le_capable(hdev))
- hci_set_le_support(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
}
static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
@@ -844,12 +561,8 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
-
- hdev->flow_ctl_mode = rp->mode;
-
- hci_req_complete(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, rp->status);
+ if (!rp->status)
+ hdev->flow_ctl_mode = rp->mode;
}
static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
@@ -886,8 +599,65 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
if (!rp->status)
bacpy(&hdev->bdaddr, &rp->bdaddr);
+}
+
+static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_read_page_scan_activity *rp = (void *) skb->data;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (test_bit(HCI_INIT, &hdev->flags) && !rp->status) {
+ hdev->page_scan_interval = __le16_to_cpu(rp->interval);
+ hdev->page_scan_window = __le16_to_cpu(rp->window);
+ }
+}
+
+static void hci_cc_write_page_scan_activity(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ u8 status = *((u8 *) skb->data);
+ struct hci_cp_write_page_scan_activity *sent;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ if (status)
+ return;
+
+ sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY);
+ if (!sent)
+ return;
+
+ hdev->page_scan_interval = __le16_to_cpu(sent->interval);
+ hdev->page_scan_window = __le16_to_cpu(sent->window);
+}
+
+static void hci_cc_read_page_scan_type(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_read_page_scan_type *rp = (void *) skb->data;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (test_bit(HCI_INIT, &hdev->flags) && !rp->status)
+ hdev->page_scan_type = rp->type;
+}
+
+static void hci_cc_write_page_scan_type(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ u8 status = *((u8 *) skb->data);
+ u8 *type;
- hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ if (status)
+ return;
+
+ type = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE);
+ if (type)
+ hdev->page_scan_type = *type;
}
static void hci_cc_read_data_block_size(struct hci_dev *hdev,
@@ -908,17 +678,6 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev,
BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
hdev->block_cnt, hdev->block_len);
-
- hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
-}
-
-static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
}
static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
@@ -942,8 +701,6 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
-
a2mp_rsp:
a2mp_send_getinfo_rsp(hdev);
}
@@ -985,35 +742,6 @@ a2mp_rsp:
a2mp_send_create_phy_link_req(hdev, rp->status);
}
-static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status);
-}
-
-static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_MASK, status);
-}
-
-static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_INQUIRY_MODE, status);
-}
-
static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -1023,17 +751,6 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
if (!rp->status)
hdev->inq_tx_power = rp->tx_power;
-
- hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, rp->status);
-}
-
-static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status);
}
static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1095,8 +812,6 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
hdev->le_cnt = hdev->le_pkts;
BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
-
- hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
}
static void hci_cc_le_read_local_features(struct hci_dev *hdev,
@@ -1108,8 +823,6 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev,
if (!rp->status)
memcpy(hdev->le_features, rp->features, 8);
-
- hci_req_complete(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, rp->status);
}
static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
@@ -1119,22 +832,8 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (!rp->status) {
+ if (!rp->status)
hdev->adv_tx_power = rp->tx_power;
- if (!test_bit(HCI_INIT, &hdev->flags))
- hci_update_ad(hdev);
- }
-
- hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
-}
-
-static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_LE_SET_EVENT_MASK, status);
}
static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1231,12 +930,15 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
}
- hci_dev_unlock(hdev);
+ if (!test_bit(HCI_INIT, &hdev->flags)) {
+ struct hci_request req;
- if (!test_bit(HCI_INIT, &hdev->flags))
- hci_update_ad(hdev);
+ hci_req_init(&req, hdev);
+ hci_update_ad(&req);
+ hci_req_run(&req, NULL);
+ }
- hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status);
+ hci_dev_unlock(hdev);
}
static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1245,8 +947,6 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
- hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status);
-
if (status) {
hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status);
@@ -1269,8 +969,6 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
switch (cp->enable) {
case LE_SCANNING_ENABLED:
- hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status);
-
if (status) {
hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status);
@@ -1321,32 +1019,6 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
if (!rp->status)
hdev->le_white_list_size = rp->size;
-
- hci_req_complete(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, rp->status);
-}
-
-static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status);
-}
-
-static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
}
static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
@@ -1358,8 +1030,6 @@ static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
if (!rp->status)
memcpy(hdev->le_states, rp->le_states, 8);
-
- hci_req_complete(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, rp->status);
}
static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
@@ -1389,8 +1059,6 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
!test_bit(HCI_INIT, &hdev->flags))
mgmt_le_enable_complete(hdev, sent->le, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
}
static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
@@ -1412,7 +1080,6 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status) {
- hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->dev_flags))
@@ -1884,11 +1551,6 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
}
}
-static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
-{
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-}
-
static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
{
struct hci_cp_create_phy_link *cp;
@@ -1930,11 +1592,6 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
amp_write_remote_assoc(hdev, cp->phy_handle);
}
-static void hci_cs_create_logical_link(struct hci_dev *hdev, u8 status)
-{
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-}
-
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -1943,7 +1600,7 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
- hci_req_complete(hdev, HCI_OP_INQUIRY, status);
+ hci_req_cmd_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev);
@@ -2399,7 +2056,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
if (ev->status && conn->state == BT_CONNECTED) {
- hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE);
+ hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
hci_conn_put(conn);
goto unlock;
}
@@ -2491,20 +2148,10 @@ unlock:
hci_dev_unlock(hdev);
}
-static void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static void hci_qos_setup_complete_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_cmd_complete *ev = (void *) skb->data;
+ u8 status = skb->data[sizeof(*ev)];
__u16 opcode;
skb_pull(skb, sizeof(*ev));
@@ -2588,10 +2235,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_write_voice_setting(hdev, skb);
break;
- case HCI_OP_HOST_BUFFER_SIZE:
- hci_cc_host_buffer_size(hdev, skb);
- break;
-
case HCI_OP_WRITE_SSP_MODE:
hci_cc_write_ssp_mode(hdev, skb);
break;
@@ -2620,46 +2263,42 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_read_bd_addr(hdev, skb);
break;
- case HCI_OP_READ_DATA_BLOCK_SIZE:
- hci_cc_read_data_block_size(hdev, skb);
+ case HCI_OP_READ_PAGE_SCAN_ACTIVITY:
+ hci_cc_read_page_scan_activity(hdev, skb);
break;
- case HCI_OP_WRITE_CA_TIMEOUT:
- hci_cc_write_ca_timeout(hdev, skb);
+ case HCI_OP_WRITE_PAGE_SCAN_ACTIVITY:
+ hci_cc_write_page_scan_activity(hdev, skb);
break;
- case HCI_OP_READ_FLOW_CONTROL_MODE:
- hci_cc_read_flow_control_mode(hdev, skb);
+ case HCI_OP_READ_PAGE_SCAN_TYPE:
+ hci_cc_read_page_scan_type(hdev, skb);
break;
- case HCI_OP_READ_LOCAL_AMP_INFO:
- hci_cc_read_local_amp_info(hdev, skb);
+ case HCI_OP_WRITE_PAGE_SCAN_TYPE:
+ hci_cc_write_page_scan_type(hdev, skb);
break;
- case HCI_OP_READ_LOCAL_AMP_ASSOC:
- hci_cc_read_local_amp_assoc(hdev, skb);
+ case HCI_OP_READ_DATA_BLOCK_SIZE:
+ hci_cc_read_data_block_size(hdev, skb);
break;
- case HCI_OP_DELETE_STORED_LINK_KEY:
- hci_cc_delete_stored_link_key(hdev, skb);
+ case HCI_OP_READ_FLOW_CONTROL_MODE:
+ hci_cc_read_flow_control_mode(hdev, skb);
break;
- case HCI_OP_SET_EVENT_MASK:
- hci_cc_set_event_mask(hdev, skb);
+ case HCI_OP_READ_LOCAL_AMP_INFO:
+ hci_cc_read_local_amp_info(hdev, skb);
break;
- case HCI_OP_WRITE_INQUIRY_MODE:
- hci_cc_write_inquiry_mode(hdev, skb);
+ case HCI_OP_READ_LOCAL_AMP_ASSOC:
+ hci_cc_read_local_amp_assoc(hdev, skb);
break;
case HCI_OP_READ_INQ_RSP_TX_POWER:
hci_cc_read_inq_rsp_tx_power(hdev, skb);
break;
- case HCI_OP_SET_EVENT_FLT:
- hci_cc_set_event_flt(hdev, skb);
- break;
-
case HCI_OP_PIN_CODE_REPLY:
hci_cc_pin_code_reply(hdev, skb);
break;
@@ -2684,10 +2323,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_le_read_adv_tx_power(hdev, skb);
break;
- case HCI_OP_LE_SET_EVENT_MASK:
- hci_cc_le_set_event_mask(hdev, skb);
- break;
-
case HCI_OP_USER_CONFIRM_REPLY:
hci_cc_user_confirm_reply(hdev, skb);
break;
@@ -2720,14 +2355,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_le_read_white_list_size(hdev, skb);
break;
- case HCI_OP_LE_LTK_REPLY:
- hci_cc_le_ltk_reply(hdev, skb);
- break;
-
- case HCI_OP_LE_LTK_NEG_REPLY:
- hci_cc_le_ltk_neg_reply(hdev, skb);
- break;
-
case HCI_OP_LE_READ_SUPPORTED_STATES:
hci_cc_le_read_supported_states(hdev, skb);
break;
@@ -2745,9 +2372,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
break;
}
- if (ev->opcode != HCI_OP_NOP)
+ if (opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer);
+ hci_req_cmd_complete(hdev, opcode, status);
+
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
@@ -2817,10 +2446,6 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_le_create_conn(hdev, ev->status);
break;
- case HCI_OP_LE_START_ENC:
- hci_cs_le_start_enc(hdev, ev->status);
- break;
-
case HCI_OP_CREATE_PHY_LINK:
hci_cs_create_phylink(hdev, ev->status);
break;
@@ -2829,18 +2454,16 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_accept_phylink(hdev, ev->status);
break;
- case HCI_OP_CREATE_LOGICAL_LINK:
- hci_cs_create_logical_link(hdev, ev->status);
- break;
-
default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
break;
}
- if (ev->opcode != HCI_OP_NOP)
+ if (opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer);
+ hci_req_cmd_status(hdev, opcode, ev->status);
+
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
@@ -3391,18 +3014,6 @@ unlock:
hci_dev_unlock(hdev);
}
-static void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_sniff_subrate *ev = (void *) skb->data;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
-}
-
static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -3472,7 +3083,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
if (ev->status && conn->state == BT_CONNECTED) {
- hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE);
+ hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
hci_conn_put(conn);
goto unlock;
}
@@ -4130,14 +3741,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_remote_features_evt(hdev, skb);
break;
- case HCI_EV_REMOTE_VERSION:
- hci_remote_version_evt(hdev, skb);
- break;
-
- case HCI_EV_QOS_SETUP_COMPLETE:
- hci_qos_setup_complete_evt(hdev, skb);
- break;
-
case HCI_EV_CMD_COMPLETE:
hci_cmd_complete_evt(hdev, skb);
break;
@@ -4194,14 +3797,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_sync_conn_complete_evt(hdev, skb);
break;
- case HCI_EV_SYNC_CONN_CHANGED:
- hci_sync_conn_changed_evt(hdev, skb);
- break;
-
- case HCI_EV_SNIFF_SUBRATE:
- hci_sniff_subrate_evt(hdev, skb);
- break;
-
case HCI_EV_EXTENDED_INQUIRY_RESULT:
hci_extended_inquiry_result_evt(hdev, skb);
break;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 6a93614f2c49..aa4354fca77c 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -854,6 +854,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
} else {
+ /* Stand-alone HCI commands must be flaged as
+ * single-command requests.
+ */
+ bt_cb(skb)->req.start = true;
+
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
}
@@ -1121,8 +1126,6 @@ error:
void hci_sock_cleanup(void)
{
bt_procfs_cleanup(&init_net, "hci");
- if (bt_sock_unregister(BTPROTO_HCI) < 0)
- BT_ERR("HCI socket unregistration failed");
-
+ bt_sock_unregister(BTPROTO_HCI);
proto_unregister(&hci_sk_proto);
}
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 23b4e242a31a..ff38561385de 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -590,10 +590,8 @@ int __init bt_sysfs_init(void)
bt_debugfs = debugfs_create_dir("bluetooth", NULL);
bt_class = class_create(THIS_MODULE, "bluetooth");
- if (IS_ERR(bt_class))
- return PTR_ERR(bt_class);
- return 0;
+ return PTR_RET(bt_class);
}
void bt_sysfs_cleanup(void)
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index a7352ff3fd1e..2342327f3335 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -311,6 +311,9 @@ static int hidp_get_raw_report(struct hid_device *hid,
int numbered_reports = hid->report_enum[report_type].numbered;
int ret;
+ if (atomic_read(&session->terminate))
+ return -EIO;
+
switch (report_type) {
case HID_FEATURE_REPORT:
report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
@@ -722,6 +725,7 @@ static int hidp_session(void *arg)
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
+ atomic_inc(&session->terminate);
remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 82a829d90b0f..5d0f1ca0a314 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -304,8 +304,6 @@ error:
void __exit hidp_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "hidp");
- if (bt_sock_unregister(BTPROTO_HIDP) < 0)
- BT_ERR("Can't unregister HIDP socket");
-
+ bt_sock_unregister(BTPROTO_HIDP);
proto_unregister(&hidp_proto);
}
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 1bcfb8422fdc..7f9704993b74 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1312,8 +1312,6 @@ error:
void l2cap_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "l2cap");
- if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
- BT_ERR("L2CAP socket unregistration failed");
-
+ bt_sock_unregister(BTPROTO_L2CAP);
proto_unregister(&l2cap_proto);
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 39395c7144aa..03e7e732215f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -384,7 +384,8 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (lmp_bredr_capable(hdev)) {
settings |= MGMT_SETTING_CONNECTABLE;
- settings |= MGMT_SETTING_FAST_CONNECTABLE;
+ if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
+ settings |= MGMT_SETTING_FAST_CONNECTABLE;
settings |= MGMT_SETTING_DISCOVERABLE;
settings |= MGMT_SETTING_BREDR;
settings |= MGMT_SETTING_LINK_SECURITY;
@@ -409,6 +410,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_CONNECTABLE;
+ if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
+ settings |= MGMT_SETTING_FAST_CONNECTABLE;
+
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_DISCOVERABLE;
@@ -591,32 +595,33 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
}
-static int update_eir(struct hci_dev *hdev)
+static void update_eir(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_write_eir cp;
if (!hdev_is_powered(hdev))
- return 0;
+ return;
if (!lmp_ext_inq_capable(hdev))
- return 0;
+ return;
if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- return 0;
+ return;
if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- return 0;
+ return;
memset(&cp, 0, sizeof(cp));
create_eir(hdev, cp.data);
if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
- return 0;
+ return;
memcpy(hdev->eir, cp.data, sizeof(cp.data));
- return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
static u8 get_service_classes(struct hci_dev *hdev)
@@ -630,47 +635,48 @@ static u8 get_service_classes(struct hci_dev *hdev)
return val;
}
-static int update_class(struct hci_dev *hdev)
+static void update_class(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
u8 cod[3];
- int err;
BT_DBG("%s", hdev->name);
if (!hdev_is_powered(hdev))
- return 0;
+ return;
if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- return 0;
+ return;
cod[0] = hdev->minor_class;
cod[1] = hdev->major_class;
cod[2] = get_service_classes(hdev);
if (memcmp(cod, hdev->dev_class, 3) == 0)
- return 0;
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
- if (err == 0)
- set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
+ return;
- return err;
+ hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
}
static void service_cache_off(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev,
service_cache.work);
+ struct hci_request req;
if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
return;
+ hci_req_init(&req, hdev);
+
hci_dev_lock(hdev);
- update_eir(hdev);
- update_class(hdev);
+ update_eir(&req);
+ update_class(&req);
hci_dev_unlock(hdev);
+
+ hci_req_run(&req, NULL);
}
static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
@@ -994,11 +1000,64 @@ failed:
return err;
}
+static void write_fast_connectable(struct hci_request *req, bool enable)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_write_page_scan_activity acp;
+ u8 type;
+
+ if (hdev->hci_ver < BLUETOOTH_VER_1_2)
+ return;
+
+ if (enable) {
+ type = PAGE_SCAN_TYPE_INTERLACED;
+
+ /* 160 msec page scan interval */
+ acp.interval = __constant_cpu_to_le16(0x0100);
+ } else {
+ type = PAGE_SCAN_TYPE_STANDARD; /* default */
+
+ /* default 1.28 sec page scan */
+ acp.interval = __constant_cpu_to_le16(0x0800);
+ }
+
+ acp.window = __constant_cpu_to_le16(0x0012);
+
+ if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
+ __cpu_to_le16(hdev->page_scan_window) != acp.window)
+ hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
+ sizeof(acp), &acp);
+
+ if (hdev->page_scan_type != type)
+ hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
+}
+
+static void set_connectable_complete(struct hci_dev *hdev, u8 status)
+{
+ struct pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
+ if (!cmd)
+ goto unlock;
+
+ send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_mode *cp = data;
struct pending_cmd *cmd;
+ struct hci_request req;
u8 scan;
int err;
@@ -1065,7 +1124,20 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
cancel_delayed_work(&hdev->discov_off);
}
- err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+ hci_req_init(&req, hdev);
+
+ hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+
+ /* If we're going from non-connectable to connectable or
+ * vice-versa when fast connectable is enabled ensure that fast
+ * connectable gets disabled. write_fast_connectable won't do
+ * anything if the page scan parameters are already what they
+ * should be.
+ */
+ if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
+ write_fast_connectable(&req, false);
+
+ err = hci_req_run(&req, set_connectable_complete);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -1332,6 +1404,29 @@ unlock:
return err;
}
+/* This is a helper function to test for pending mgmt commands that can
+ * cause CoD or EIR HCI commands. We can only allow one such pending
+ * mgmt command at a time since otherwise we cannot easily track what
+ * the current values are, will be, and based on that calculate if a new
+ * HCI command needs to be sent and if yes with what value.
+ */
+static bool pending_eir_or_class(struct hci_dev *hdev)
+{
+ struct pending_cmd *cmd;
+
+ list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
+ switch (cmd->opcode) {
+ case MGMT_OP_ADD_UUID:
+ case MGMT_OP_REMOVE_UUID:
+ case MGMT_OP_SET_DEV_CLASS:
+ case MGMT_OP_SET_POWERED:
+ return true;
+ }
+ }
+
+ return false;
+}
+
static const u8 bluetooth_base_uuid[] = {
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1351,10 +1446,37 @@ static u8 get_uuid_size(const u8 *uuid)
return 16;
}
+static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
+{
+ struct pending_cmd *cmd;
+
+ hci_dev_lock(hdev);
+
+ cmd = mgmt_pending_find(mgmt_op, hdev);
+ if (!cmd)
+ goto unlock;
+
+ cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
+ hdev->dev_class, 3);
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
+static void add_uuid_complete(struct hci_dev *hdev, u8 status)
+{
+ BT_DBG("status 0x%02x", status);
+
+ mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
+}
+
static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
{
struct mgmt_cp_add_uuid *cp = data;
struct pending_cmd *cmd;
+ struct hci_request req;
struct bt_uuid *uuid;
int err;
@@ -1362,7 +1484,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
hci_dev_lock(hdev);
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+ if (pending_eir_or_class(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
MGMT_STATUS_BUSY);
goto failed;
@@ -1380,23 +1502,28 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
list_add_tail(&uuid->list, &hdev->uuids);
- err = update_class(hdev);
- if (err < 0)
- goto failed;
+ hci_req_init(&req, hdev);
- err = update_eir(hdev);
- if (err < 0)
- goto failed;
+ update_class(&req);
+ update_eir(&req);
+
+ err = hci_req_run(&req, add_uuid_complete);
+ if (err < 0) {
+ if (err != -ENODATA)
+ goto failed;
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
hdev->dev_class, 3);
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
- if (!cmd)
+ if (!cmd) {
err = -ENOMEM;
+ goto failed;
+ }
+
+ err = 0;
failed:
hci_dev_unlock(hdev);
@@ -1417,6 +1544,13 @@ static bool enable_service_cache(struct hci_dev *hdev)
return false;
}
+static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
+{
+ BT_DBG("status 0x%02x", status);
+
+ mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
+}
+
static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
@@ -1424,13 +1558,14 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
struct pending_cmd *cmd;
struct bt_uuid *match, *tmp;
u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ struct hci_request req;
int err, found;
BT_DBG("request for %s", hdev->name);
hci_dev_lock(hdev);
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+ if (pending_eir_or_class(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
MGMT_STATUS_BUSY);
goto unlock;
@@ -1466,34 +1601,47 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
}
update_class:
- err = update_class(hdev);
- if (err < 0)
- goto unlock;
+ hci_req_init(&req, hdev);
- err = update_eir(hdev);
- if (err < 0)
- goto unlock;
+ update_class(&req);
+ update_eir(&req);
+
+ err = hci_req_run(&req, remove_uuid_complete);
+ if (err < 0) {
+ if (err != -ENODATA)
+ goto unlock;
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
hdev->dev_class, 3);
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
- if (!cmd)
+ if (!cmd) {
err = -ENOMEM;
+ goto unlock;
+ }
+
+ err = 0;
unlock:
hci_dev_unlock(hdev);
return err;
}
+static void set_class_complete(struct hci_dev *hdev, u8 status)
+{
+ BT_DBG("status 0x%02x", status);
+
+ mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
+}
+
static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_cp_set_dev_class *cp = data;
struct pending_cmd *cmd;
+ struct hci_request req;
int err;
BT_DBG("request for %s", hdev->name);
@@ -1502,15 +1650,19 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
MGMT_STATUS_NOT_SUPPORTED);
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
- MGMT_STATUS_BUSY);
+ hci_dev_lock(hdev);
- if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0)
- return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
- MGMT_STATUS_INVALID_PARAMS);
+ if (pending_eir_or_class(hdev)) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
+ MGMT_STATUS_BUSY);
+ goto unlock;
+ }
- hci_dev_lock(hdev);
+ if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
hdev->major_class = cp->major;
hdev->minor_class = cp->minor;
@@ -1521,26 +1673,34 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock;
}
+ hci_req_init(&req, hdev);
+
if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
hci_dev_unlock(hdev);
cancel_delayed_work_sync(&hdev->service_cache);
hci_dev_lock(hdev);
- update_eir(hdev);
+ update_eir(&req);
}
- err = update_class(hdev);
- if (err < 0)
- goto unlock;
+ update_class(&req);
+
+ err = hci_req_run(&req, set_class_complete);
+ if (err < 0) {
+ if (err != -ENODATA)
+ goto unlock;
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
hdev->dev_class, 3);
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
- if (!cmd)
+ if (!cmd) {
err = -ENOMEM;
+ goto unlock;
+ }
+
+ err = 0;
unlock:
hci_dev_unlock(hdev);
@@ -2140,7 +2300,7 @@ unlock:
}
static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
- bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
+ struct mgmt_addr_info *addr, u16 mgmt_op,
u16 hci_op, __le32 passkey)
{
struct pending_cmd *cmd;
@@ -2150,37 +2310,41 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_NOT_POWERED);
+ err = cmd_complete(sk, hdev->id, mgmt_op,
+ MGMT_STATUS_NOT_POWERED, addr,
+ sizeof(*addr));
goto done;
}
- if (type == BDADDR_BREDR)
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
+ if (addr->type == BDADDR_BREDR)
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
else
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
if (!conn) {
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_NOT_CONNECTED);
+ err = cmd_complete(sk, hdev->id, mgmt_op,
+ MGMT_STATUS_NOT_CONNECTED, addr,
+ sizeof(*addr));
goto done;
}
- if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
+ if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
/* Continue with pairing via SMP */
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
if (!err)
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_SUCCESS);
+ err = cmd_complete(sk, hdev->id, mgmt_op,
+ MGMT_STATUS_SUCCESS, addr,
+ sizeof(*addr));
else
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_FAILED);
+ err = cmd_complete(sk, hdev->id, mgmt_op,
+ MGMT_STATUS_FAILED, addr,
+ sizeof(*addr));
goto done;
}
- cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
+ cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
if (!cmd) {
err = -ENOMEM;
goto done;
@@ -2190,11 +2354,12 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
struct hci_cp_user_passkey_reply cp;
- bacpy(&cp.bdaddr, bdaddr);
+ bacpy(&cp.bdaddr, &addr->bdaddr);
cp.passkey = passkey;
err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
} else
- err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
+ err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
+ &addr->bdaddr);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -2211,7 +2376,7 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG("");
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_PIN_CODE_NEG_REPLY,
HCI_OP_PIN_CODE_NEG_REPLY, 0);
}
@@ -2227,7 +2392,7 @@ static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
MGMT_STATUS_INVALID_PARAMS);
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_CONFIRM_REPLY,
HCI_OP_USER_CONFIRM_REPLY, 0);
}
@@ -2239,7 +2404,7 @@ static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG("");
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_CONFIRM_NEG_REPLY,
HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
}
@@ -2251,7 +2416,7 @@ static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("");
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_PASSKEY_REPLY,
HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
}
@@ -2263,18 +2428,47 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG("");
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_PASSKEY_NEG_REPLY,
HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
}
-static int update_name(struct hci_dev *hdev, const char *name)
+static void update_name(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_write_local_name cp;
- memcpy(cp.name, name, sizeof(cp.name));
+ memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
+
+ hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
+}
+
+static void set_name_complete(struct hci_dev *hdev, u8 status)
+{
+ struct mgmt_cp_set_local_name *cp;
+ struct pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
+ if (!cmd)
+ goto unlock;
+
+ cp = cmd->param;
- return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
+ if (status)
+ cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
+ mgmt_status(status));
+ else
+ cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
+ cp, sizeof(*cp));
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
}
static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -2282,12 +2476,24 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
{
struct mgmt_cp_set_local_name *cp = data;
struct pending_cmd *cmd;
+ struct hci_request req;
int err;
BT_DBG("");
hci_dev_lock(hdev);
+ /* If the old values are the same as the new ones just return a
+ * direct command complete event.
+ */
+ if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
+ !memcmp(hdev->short_name, cp->short_name,
+ sizeof(hdev->short_name))) {
+ err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
+ data, len);
+ goto failed;
+ }
+
memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
if (!hdev_is_powered(hdev)) {
@@ -2310,7 +2516,19 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
goto failed;
}
- err = update_name(hdev, cp->name);
+ memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
+
+ hci_req_init(&req, hdev);
+
+ if (lmp_bredr_capable(hdev)) {
+ update_name(&req);
+ update_eir(&req);
+ }
+
+ if (lmp_le_capable(hdev))
+ hci_update_ad(&req);
+
+ err = hci_req_run(&req, set_name_complete);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -2698,6 +2916,7 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_cp_set_device_id *cp = data;
+ struct hci_request req;
int err;
__u16 source;
@@ -2718,24 +2937,59 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
- update_eir(hdev);
+ hci_req_init(&req, hdev);
+ update_eir(&req);
+ hci_req_run(&req, NULL);
hci_dev_unlock(hdev);
return err;
}
+static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
+{
+ struct pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
+ if (!cmd)
+ goto unlock;
+
+ if (status) {
+ cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+ mgmt_status(status));
+ } else {
+ struct mgmt_mode *cp = cmd->param;
+
+ if (cp->val)
+ set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
+ else
+ clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
+
+ send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
+ new_settings(hdev, cmd->sk);
+ }
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_mode *cp = data;
- struct hci_cp_write_page_scan_activity acp;
- u8 type;
+ struct pending_cmd *cmd;
+ struct hci_request req;
int err;
BT_DBG("%s", hdev->name);
- if (!lmp_bredr_capable(hdev))
+ if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_NOT_SUPPORTED);
@@ -2753,40 +3007,39 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev);
- if (cp->val) {
- type = PAGE_SCAN_TYPE_INTERLACED;
+ if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+ MGMT_STATUS_BUSY);
+ goto unlock;
+ }
- /* 160 msec page scan interval */
- acp.interval = __constant_cpu_to_le16(0x0100);
- } else {
- type = PAGE_SCAN_TYPE_STANDARD; /* default */
+ if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
+ err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
+ hdev);
+ goto unlock;
+ }
- /* default 1.28 sec page scan */
- acp.interval = __constant_cpu_to_le16(0x0800);
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
+ data, len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto unlock;
}
- /* default 11.25 msec page scan window */
- acp.window = __constant_cpu_to_le16(0x0012);
+ hci_req_init(&req, hdev);
- err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
- &acp);
- if (err < 0) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
- MGMT_STATUS_FAILED);
- goto done;
- }
+ write_fast_connectable(&req, cp->val);
- err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
+ err = hci_req_run(&req, fast_connectable_complete);
if (err < 0) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_FAILED);
- goto done;
+ mgmt_pending_remove(cmd);
}
- err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
- NULL, 0);
-done:
+unlock:
hci_dev_unlock(hdev);
+
return err;
}
@@ -3043,79 +3296,115 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)
mgmt_pending_free(cmd);
}
-static int set_bredr_scan(struct hci_dev *hdev)
+static void set_bredr_scan(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
u8 scan = 0;
+ /* Ensure that fast connectable is disabled. This function will
+ * not do anything if the page scan parameters are already what
+ * they should be.
+ */
+ write_fast_connectable(req, false);
+
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
scan |= SCAN_PAGE;
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
scan |= SCAN_INQUIRY;
- if (!scan)
- return 0;
-
- return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+ if (scan)
+ hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}
-int mgmt_powered(struct hci_dev *hdev, u8 powered)
+static void powered_complete(struct hci_dev *hdev, u8 status)
{
struct cmd_lookup match = { NULL, hdev };
- int err;
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- return 0;
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
- if (powered) {
- u8 link_sec;
+ new_settings(hdev, match.sk);
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
- !lmp_host_ssp_capable(hdev)) {
- u8 ssp = 1;
+ hci_dev_unlock(hdev);
- hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
- }
+ if (match.sk)
+ sock_put(match.sk);
+}
- if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
- struct hci_cp_write_le_host_supported cp;
+static int powered_update_hci(struct hci_dev *hdev)
+{
+ struct hci_request req;
+ u8 link_sec;
- cp.le = 1;
- cp.simul = lmp_le_br_capable(hdev);
+ hci_req_init(&req, hdev);
- /* Check first if we already have the right
- * host state (host features set)
- */
- if (cp.le != lmp_host_le_capable(hdev) ||
- cp.simul != lmp_host_le_br_capable(hdev))
- hci_send_cmd(hdev,
- HCI_OP_WRITE_LE_HOST_SUPPORTED,
- sizeof(cp), &cp);
- }
+ if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
+ !lmp_host_ssp_capable(hdev)) {
+ u8 ssp = 1;
- link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
- if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE,
- sizeof(link_sec), &link_sec);
+ hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
+ }
- if (lmp_bredr_capable(hdev)) {
- set_bredr_scan(hdev);
- update_class(hdev);
- update_name(hdev, hdev->dev_name);
- update_eir(hdev);
- }
- } else {
- u8 status = MGMT_STATUS_NOT_POWERED;
- u8 zero_cod[] = { 0, 0, 0 };
+ if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+ struct hci_cp_write_le_host_supported cp;
- mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+ cp.le = 1;
+ cp.simul = lmp_le_br_capable(hdev);
- if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
- mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
- zero_cod, sizeof(zero_cod), NULL);
+ /* Check first if we already have the right
+ * host state (host features set)
+ */
+ if (cp.le != lmp_host_le_capable(hdev) ||
+ cp.simul != lmp_host_le_br_capable(hdev))
+ hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
+ sizeof(cp), &cp);
}
+ link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
+ if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
+ hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
+ sizeof(link_sec), &link_sec);
+
+ if (lmp_bredr_capable(hdev)) {
+ set_bredr_scan(&req);
+ update_class(&req);
+ update_name(&req);
+ update_eir(&req);
+ }
+
+ return hci_req_run(&req, powered_complete);
+}
+
+int mgmt_powered(struct hci_dev *hdev, u8 powered)
+{
+ struct cmd_lookup match = { NULL, hdev };
+ u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
+ u8 zero_cod[] = { 0, 0, 0 };
+ int err;
+
+ if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+ return 0;
+
+ if (powered) {
+ if (powered_update_hci(hdev) == 0)
+ return 0;
+
+ mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
+ &match);
+ goto new_settings;
+ }
+
+ mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
+ mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
+
+ if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
+ mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
+ zero_cod, sizeof(zero_cod), NULL);
+
+new_settings:
err = new_settings(hdev, match.sk);
if (match.sk)
@@ -3152,7 +3441,7 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
{
- struct cmd_lookup match = { NULL, hdev };
+ struct pending_cmd *cmd;
bool changed = false;
int err = 0;
@@ -3164,14 +3453,10 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
changed = true;
}
- mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
- &match);
+ cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
if (changed)
- err = new_settings(hdev, match.sk);
-
- if (match.sk)
- sock_put(match.sk);
+ err = new_settings(hdev, cmd ? cmd->sk : NULL);
return err;
}
@@ -3555,23 +3840,25 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
return err;
}
-static int clear_eir(struct hci_dev *hdev)
+static void clear_eir(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_write_eir cp;
if (!lmp_ext_inq_capable(hdev))
- return 0;
+ return;
memset(hdev->eir, 0, sizeof(hdev->eir));
memset(&cp, 0, sizeof(cp));
- return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
{
struct cmd_lookup match = { NULL, hdev };
+ struct hci_request req;
bool changed = false;
int err = 0;
@@ -3604,29 +3891,26 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
if (match.sk)
sock_put(match.sk);
+ hci_req_init(&req, hdev);
+
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- update_eir(hdev);
+ update_eir(&req);
else
- clear_eir(hdev);
+ clear_eir(&req);
+
+ hci_req_run(&req, NULL);
return err;
}
-static void class_rsp(struct pending_cmd *cmd, void *data)
+static void sk_lookup(struct pending_cmd *cmd, void *data)
{
struct cmd_lookup *match = data;
- cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
- match->hdev->dev_class, 3);
-
- list_del(&cmd->list);
-
if (match->sk == NULL) {
match->sk = cmd->sk;
sock_hold(match->sk);
}
-
- mgmt_pending_free(cmd);
}
int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
@@ -3635,11 +3919,9 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
int err = 0;
- clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
-
- mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
- mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
- mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
+ mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
+ mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
+ mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
if (!status)
err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
@@ -3653,55 +3935,29 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
{
- struct pending_cmd *cmd;
struct mgmt_cp_set_local_name ev;
- bool changed = false;
- int err = 0;
+ struct pending_cmd *cmd;
- if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
- memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
- changed = true;
- }
+ if (status)
+ return 0;
memset(&ev, 0, sizeof(ev));
memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
- if (!cmd)
- goto send_event;
-
- /* Always assume that either the short or the complete name has
- * changed if there was a pending mgmt command */
- changed = true;
+ if (!cmd) {
+ memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
- if (status) {
- err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
- mgmt_status(status));
- goto failed;
+ /* If this is a HCI command related to powering on the
+ * HCI dev don't send any mgmt signals.
+ */
+ if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
+ return 0;
}
- err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
- sizeof(ev));
- if (err < 0)
- goto failed;
-
-send_event:
- if (changed)
- err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
- sizeof(ev), cmd ? cmd->sk : NULL);
-
- /* EIR is taken care of separately when powering on the
- * adapter so only update them here if this is a name change
- * unrelated to power on.
- */
- if (!test_bit(HCI_INIT, &hdev->flags))
- update_eir(hdev);
-
-failed:
- if (cmd)
- mgmt_pending_remove(cmd);
- return err;
+ return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
+ cmd ? cmd->sk : NULL);
}
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index b23e2713fea8..ca957d34b0c8 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -69,7 +69,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
u8 sec_level,
int *err);
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
-static void rfcomm_session_del(struct rfcomm_session *s);
+static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
/* ---- RFCOMM frame parsing macros ---- */
#define __get_dlci(b) ((b & 0xfc) >> 2)
@@ -108,12 +108,6 @@ static void rfcomm_schedule(void)
wake_up_process(rfcomm_thread);
}
-static void rfcomm_session_put(struct rfcomm_session *s)
-{
- if (atomic_dec_and_test(&s->refcnt))
- rfcomm_session_del(s);
-}
-
/* ---- RFCOMM FCS computation ---- */
/* reversed, 8-bit, poly=0x07 */
@@ -249,16 +243,14 @@ static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
{
BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout);
- if (!mod_timer(&s->timer, jiffies + timeout))
- rfcomm_session_hold(s);
+ mod_timer(&s->timer, jiffies + timeout);
}
static void rfcomm_session_clear_timer(struct rfcomm_session *s)
{
BT_DBG("session %p state %ld", s, s->state);
- if (del_timer(&s->timer))
- rfcomm_session_put(s);
+ del_timer_sync(&s->timer);
}
/* ---- RFCOMM DLCs ---- */
@@ -336,8 +328,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
{
BT_DBG("dlc %p session %p", d, s);
- rfcomm_session_hold(s);
-
rfcomm_session_clear_timer(s);
rfcomm_dlc_hold(d);
list_add(&d->list, &s->dlcs);
@@ -356,8 +346,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
if (list_empty(&s->dlcs))
rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT);
-
- rfcomm_session_put(s);
}
static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
@@ -493,12 +481,34 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
{
- int r;
+ int r = 0;
+ struct rfcomm_dlc *d_list;
+ struct rfcomm_session *s, *s_list;
+
+ BT_DBG("dlc %p state %ld dlci %d err %d", d, d->state, d->dlci, err);
rfcomm_lock();
- r = __rfcomm_dlc_close(d, err);
+ s = d->session;
+ if (!s)
+ goto no_session;
+
+ /* after waiting on the mutex check the session still exists
+ * then check the dlc still exists
+ */
+ list_for_each_entry(s_list, &session_list, list) {
+ if (s_list == s) {
+ list_for_each_entry(d_list, &s->dlcs, list) {
+ if (d_list == d) {
+ r = __rfcomm_dlc_close(d, err);
+ break;
+ }
+ }
+ break;
+ }
+ }
+no_session:
rfcomm_unlock();
return r;
}
@@ -609,7 +619,7 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
return s;
}
-static void rfcomm_session_del(struct rfcomm_session *s)
+static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s)
{
int state = s->state;
@@ -617,15 +627,14 @@ static void rfcomm_session_del(struct rfcomm_session *s)
list_del(&s->list);
- if (state == BT_CONNECTED)
- rfcomm_send_disc(s, 0);
-
rfcomm_session_clear_timer(s);
sock_release(s->sock);
kfree(s);
if (state != BT_LISTEN)
module_put(THIS_MODULE);
+
+ return NULL;
}
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
@@ -644,17 +653,16 @@ static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
return NULL;
}
-static void rfcomm_session_close(struct rfcomm_session *s, int err)
+static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s,
+ int err)
{
struct rfcomm_dlc *d;
struct list_head *p, *n;
- BT_DBG("session %p state %ld err %d", s, s->state, err);
-
- rfcomm_session_hold(s);
-
s->state = BT_CLOSED;
+ BT_DBG("session %p state %ld err %d", s, s->state, err);
+
/* Close all dlcs */
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
@@ -663,7 +671,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
}
rfcomm_session_clear_timer(s);
- rfcomm_session_put(s);
+ return rfcomm_session_del(s);
}
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
@@ -715,8 +723,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
if (*err == 0 || *err == -EINPROGRESS)
return s;
- rfcomm_session_del(s);
- return NULL;
+ return rfcomm_session_del(s);
failed:
sock_release(sock);
@@ -1105,7 +1112,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
}
/* ---- RFCOMM frame reception ---- */
-static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
{
BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
@@ -1114,7 +1121,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
if (!d) {
rfcomm_send_dm(s, dlci);
- return 0;
+ return s;
}
switch (d->state) {
@@ -1150,25 +1157,14 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
break;
case BT_DISCONN:
- /* rfcomm_session_put is called later so don't do
- * anything here otherwise we will mess up the session
- * reference counter:
- *
- * (a) when we are the initiator dlc_unlink will drive
- * the reference counter to 0 (there is no initial put
- * after session_add)
- *
- * (b) when we are not the initiator rfcomm_rx_process
- * will explicitly call put to balance the initial hold
- * done after session add.
- */
+ s = rfcomm_session_close(s, ECONNRESET);
break;
}
}
- return 0;
+ return s;
}
-static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
{
int err = 0;
@@ -1192,13 +1188,13 @@ static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
else
err = ECONNRESET;
- s->state = BT_CLOSED;
- rfcomm_session_close(s, err);
+ s = rfcomm_session_close(s, err);
}
- return 0;
+ return s;
}
-static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_disc(struct rfcomm_session *s,
+ u8 dlci)
{
int err = 0;
@@ -1227,11 +1223,9 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
else
err = ECONNRESET;
- s->state = BT_CLOSED;
- rfcomm_session_close(s, err);
+ s = rfcomm_session_close(s, err);
}
-
- return 0;
+ return s;
}
void rfcomm_dlc_accept(struct rfcomm_dlc *d)
@@ -1652,11 +1646,18 @@ drop:
return 0;
}
-static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
+static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
+ struct sk_buff *skb)
{
struct rfcomm_hdr *hdr = (void *) skb->data;
u8 type, dlci, fcs;
+ if (!s) {
+ /* no session, so free socket data */
+ kfree_skb(skb);
+ return s;
+ }
+
dlci = __get_dlci(hdr->addr);
type = __get_type(hdr->ctrl);
@@ -1667,7 +1668,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
if (__check_fcs(skb->data, type, fcs)) {
BT_ERR("bad checksum in packet");
kfree_skb(skb);
- return -EILSEQ;
+ return s;
}
if (__test_ea(hdr->len))
@@ -1683,22 +1684,23 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
case RFCOMM_DISC:
if (__test_pf(hdr->ctrl))
- rfcomm_recv_disc(s, dlci);
+ s = rfcomm_recv_disc(s, dlci);
break;
case RFCOMM_UA:
if (__test_pf(hdr->ctrl))
- rfcomm_recv_ua(s, dlci);
+ s = rfcomm_recv_ua(s, dlci);
break;
case RFCOMM_DM:
- rfcomm_recv_dm(s, dlci);
+ s = rfcomm_recv_dm(s, dlci);
break;
case RFCOMM_UIH:
- if (dlci)
- return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
-
+ if (dlci) {
+ rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
+ return s;
+ }
rfcomm_recv_mcc(s, skb);
break;
@@ -1707,7 +1709,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
break;
}
kfree_skb(skb);
- return 0;
+ return s;
}
/* ---- Connection and data processing ---- */
@@ -1844,7 +1846,7 @@ static void rfcomm_process_dlcs(struct rfcomm_session *s)
}
}
-static void rfcomm_process_rx(struct rfcomm_session *s)
+static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s)
{
struct socket *sock = s->sock;
struct sock *sk = sock->sk;
@@ -1856,17 +1858,15 @@ static void rfcomm_process_rx(struct rfcomm_session *s)
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
if (!skb_linearize(skb))
- rfcomm_recv_frame(s, skb);
+ s = rfcomm_recv_frame(s, skb);
else
kfree_skb(skb);
}
- if (sk->sk_state == BT_CLOSED) {
- if (!s->initiator)
- rfcomm_session_put(s);
+ if (s && (sk->sk_state == BT_CLOSED))
+ s = rfcomm_session_close(s, sk->sk_err);
- rfcomm_session_close(s, sk->sk_err);
- }
+ return s;
}
static void rfcomm_accept_connection(struct rfcomm_session *s)
@@ -1891,8 +1891,6 @@ static void rfcomm_accept_connection(struct rfcomm_session *s)
s = rfcomm_session_add(nsock, BT_OPEN);
if (s) {
- rfcomm_session_hold(s);
-
/* We should adjust MTU on incoming sessions.
* L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
@@ -1903,7 +1901,7 @@ static void rfcomm_accept_connection(struct rfcomm_session *s)
sock_release(nsock);
}
-static void rfcomm_check_connection(struct rfcomm_session *s)
+static struct rfcomm_session *rfcomm_check_connection(struct rfcomm_session *s)
{
struct sock *sk = s->sock->sk;
@@ -1921,10 +1919,10 @@ static void rfcomm_check_connection(struct rfcomm_session *s)
break;
case BT_CLOSED:
- s->state = BT_CLOSED;
- rfcomm_session_close(s, sk->sk_err);
+ s = rfcomm_session_close(s, sk->sk_err);
break;
}
+ return s;
}
static void rfcomm_process_sessions(void)
@@ -1940,7 +1938,6 @@ static void rfcomm_process_sessions(void)
if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
s->state = BT_DISCONN;
rfcomm_send_disc(s, 0);
- rfcomm_session_put(s);
continue;
}
@@ -1949,21 +1946,18 @@ static void rfcomm_process_sessions(void)
continue;
}
- rfcomm_session_hold(s);
-
switch (s->state) {
case BT_BOUND:
- rfcomm_check_connection(s);
+ s = rfcomm_check_connection(s);
break;
default:
- rfcomm_process_rx(s);
+ s = rfcomm_process_rx(s);
break;
}
- rfcomm_process_dlcs(s);
-
- rfcomm_session_put(s);
+ if (s)
+ rfcomm_process_dlcs(s);
}
rfcomm_unlock();
@@ -2010,10 +2004,11 @@ static int rfcomm_add_listener(bdaddr_t *ba)
/* Add listening session */
s = rfcomm_session_add(sock, BT_LISTEN);
- if (!s)
+ if (!s) {
+ err = -ENOMEM;
goto failed;
+ }
- rfcomm_session_hold(s);
return 0;
failed:
sock_release(sock);
@@ -2071,8 +2066,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
if (!s)
return;
- rfcomm_session_hold(s);
-
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
@@ -2104,8 +2097,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
}
- rfcomm_session_put(s);
-
rfcomm_schedule();
}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 7c9224bcce17..a8638b58c4bf 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -1066,8 +1066,7 @@ void __exit rfcomm_cleanup_sockets(void)
debugfs_remove(rfcomm_sock_debugfs);
- if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
- BT_ERR("RFCOMM socket layer unregistration failed");
+ bt_sock_unregister(BTPROTO_RFCOMM);
proto_unregister(&rfcomm_proto);
}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index fb6192c9812e..2c8055350510 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1113,8 +1113,7 @@ void __exit sco_exit(void)
debugfs_remove(sco_debugfs);
- if (bt_sock_unregister(BTPROTO_SCO) < 0)
- BT_ERR("SCO socket unregistration failed");
+ bt_sock_unregister(BTPROTO_SCO);
proto_unregister(&sco_proto);
}
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c34e6d78a592..c50c19402588 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -175,7 +175,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
* add it to the device after the station.
*/
if (!sta || !test_sta_flag(sta, WLAN_STA_ASSOC)) {
- ieee80211_key_free(sdata->local, key);
+ ieee80211_key_free_unused(key);
err = -ENOENT;
goto out_unlock;
}
@@ -214,8 +214,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
}
err = ieee80211_key_link(key, sdata, sta);
- if (err)
- ieee80211_key_free(sdata->local, key);
out_unlock:
mutex_unlock(&sdata->local->sta_mtx);
@@ -254,7 +252,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
goto out_unlock;
}
- __ieee80211_key_free(key, true);
+ ieee80211_key_free(key, true);
ret = 0;
out_unlock:
@@ -445,12 +443,14 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct timespec uptime;
+ u64 packets = 0;
+ int ac;
sinfo->generation = sdata->local->sta_generation;
sinfo->filled = STATION_INFO_INACTIVE_TIME |
- STATION_INFO_RX_BYTES |
- STATION_INFO_TX_BYTES |
+ STATION_INFO_RX_BYTES64 |
+ STATION_INFO_TX_BYTES64 |
STATION_INFO_RX_PACKETS |
STATION_INFO_TX_PACKETS |
STATION_INFO_TX_RETRIES |
@@ -467,10 +467,14 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->connected_time = uptime.tv_sec - sta->last_connected;
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+ sinfo->tx_bytes = 0;
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ sinfo->tx_bytes += sta->tx_bytes[ac];
+ packets += sta->tx_packets[ac];
+ }
+ sinfo->tx_packets = packets;
sinfo->rx_bytes = sta->rx_bytes;
- sinfo->tx_bytes = sta->tx_bytes;
sinfo->rx_packets = sta->rx_packets;
- sinfo->tx_packets = sta->tx_packets;
sinfo->tx_retries = sta->tx_retry_count;
sinfo->tx_failed = sta->tx_retry_failed;
sinfo->rx_dropped_misc = sta->rx_dropped;
@@ -598,8 +602,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
data[i++] += sta->rx_fragments; \
data[i++] += sta->rx_dropped; \
\
- data[i++] += sta->tx_packets; \
- data[i++] += sta->tx_bytes; \
+ data[i++] += sinfo.tx_packets; \
+ data[i++] += sinfo.tx_bytes; \
data[i++] += sta->tx_fragments; \
data[i++] += sta->tx_filtered_count; \
data[i++] += sta->tx_retry_failed; \
@@ -621,13 +625,14 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
goto do_survey;
+ sinfo.filled = 0;
+ sta_set_sinfo(sta, &sinfo);
+
i = 0;
ADD_STA_STATS(sta);
data[i++] = sta->sta_state;
- sinfo.filled = 0;
- sta_set_sinfo(sta, &sinfo);
if (sinfo.filled & STATION_INFO_TX_BITRATE)
data[i] = 100000 *
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index c3a3082b72e5..1521cabad3d6 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -295,7 +295,7 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
char buf[50];
struct ieee80211_key *key;
- if (!sdata->debugfs.dir)
+ if (!sdata->vif.debugfs_dir)
return;
lockdep_assert_held(&sdata->local->key_mtx);
@@ -311,7 +311,7 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_unicast_key =
debugfs_create_symlink("default_unicast_key",
- sdata->debugfs.dir, buf);
+ sdata->vif.debugfs_dir, buf);
}
if (sdata->debugfs.default_multicast_key) {
@@ -325,7 +325,7 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_multicast_key =
debugfs_create_symlink("default_multicast_key",
- sdata->debugfs.dir, buf);
+ sdata->vif.debugfs_dir, buf);
}
}
@@ -334,7 +334,7 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
char buf[50];
struct ieee80211_key *key;
- if (!sdata->debugfs.dir)
+ if (!sdata->vif.debugfs_dir)
return;
key = key_mtx_dereference(sdata->local,
@@ -343,7 +343,7 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_mgmt_key =
debugfs_create_symlink("default_mgmt_key",
- sdata->debugfs.dir, buf);
+ sdata->vif.debugfs_dir, buf);
} else
ieee80211_debugfs_key_remove_mgmt_default(sdata);
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 059bbb82e84f..ddb426867904 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -521,7 +521,7 @@ IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
#endif
#define DEBUGFS_ADD_MODE(name, mode) \
- debugfs_create_file(#name, mode, sdata->debugfs.dir, \
+ debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \
sdata, &name##_ops);
#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
@@ -577,7 +577,7 @@ static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
{
struct dentry *dir = debugfs_create_dir("mesh_stats",
- sdata->debugfs.dir);
+ sdata->vif.debugfs_dir);
#define MESHSTATS_ADD(name)\
debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
@@ -594,7 +594,7 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
{
struct dentry *dir = debugfs_create_dir("mesh_config",
- sdata->debugfs.dir);
+ sdata->vif.debugfs_dir);
#define MESHPARAMS_ADD(name) \
debugfs_create_file(#name, 0600, dir, sdata, &name##_ops);
@@ -631,7 +631,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
static void add_files(struct ieee80211_sub_if_data *sdata)
{
- if (!sdata->debugfs.dir)
+ if (!sdata->vif.debugfs_dir)
return;
DEBUGFS_ADD(flags);
@@ -673,21 +673,21 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
char buf[10+IFNAMSIZ];
sprintf(buf, "netdev:%s", sdata->name);
- sdata->debugfs.dir = debugfs_create_dir(buf,
+ sdata->vif.debugfs_dir = debugfs_create_dir(buf,
sdata->local->hw.wiphy->debugfsdir);
- if (sdata->debugfs.dir)
+ if (sdata->vif.debugfs_dir)
sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
- sdata->debugfs.dir);
+ sdata->vif.debugfs_dir);
add_files(sdata);
}
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
{
- if (!sdata->debugfs.dir)
+ if (!sdata->vif.debugfs_dir)
return;
- debugfs_remove_recursive(sdata->debugfs.dir);
- sdata->debugfs.dir = NULL;
+ debugfs_remove_recursive(sdata->vif.debugfs_dir);
+ sdata->vif.debugfs_dir = NULL;
}
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
@@ -695,7 +695,7 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
struct dentry *dir;
char buf[10 + IFNAMSIZ];
- dir = sdata->debugfs.dir;
+ dir = sdata->vif.debugfs_dir;
if (!dir)
return;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 832acea4a5cb..169664c122e2 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -241,6 +241,22 @@ static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
return ret;
}
+static inline void drv_set_multicast_list(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct netdev_hw_addr_list *mc_list)
+{
+ bool allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
+
+ trace_drv_set_multicast_list(local, sdata, mc_list->count);
+
+ check_sdata_in_driver(sdata);
+
+ if (local->ops->set_multicast_list)
+ local->ops->set_multicast_list(&local->hw, &sdata->vif,
+ allmulti, mc_list);
+ trace_drv_return_void(local);
+}
+
static inline void drv_configure_filter(struct ieee80211_local *local,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -531,43 +547,6 @@ static inline void drv_sta_remove_debugfs(struct ieee80211_local *local,
local->ops->sta_remove_debugfs(&local->hw, &sdata->vif,
sta, dir);
}
-
-static inline
-void drv_add_interface_debugfs(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
-{
- might_sleep();
-
- check_sdata_in_driver(sdata);
-
- if (!local->ops->add_interface_debugfs)
- return;
-
- local->ops->add_interface_debugfs(&local->hw, &sdata->vif,
- sdata->debugfs.dir);
-}
-
-static inline
-void drv_remove_interface_debugfs(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
-{
- might_sleep();
-
- check_sdata_in_driver(sdata);
-
- if (!local->ops->remove_interface_debugfs)
- return;
-
- local->ops->remove_interface_debugfs(&local->hw, &sdata->vif,
- sdata->debugfs.dir);
-}
-#else
-static inline
-void drv_add_interface_debugfs(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata) {}
-static inline
-void drv_remove_interface_debugfs(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata) {}
#endif
static inline __must_check
@@ -741,13 +720,14 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
local->ops->rfkill_poll(&local->hw);
}
-static inline void drv_flush(struct ieee80211_local *local, bool drop)
+static inline void drv_flush(struct ieee80211_local *local,
+ u32 queues, bool drop)
{
might_sleep();
- trace_drv_flush(local, drop);
+ trace_drv_flush(local, queues, drop);
if (local->ops->flush)
- local->ops->flush(&local->hw, drop);
+ local->ops->flush(&local->hw, queues, drop);
trace_drv_return_void(local);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e140184c28ce..0b09716d22ad 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -759,7 +759,6 @@ struct ieee80211_sub_if_data {
#ifdef CONFIG_MAC80211_DEBUGFS
struct {
- struct dentry *dir;
struct dentry *subdir_stations;
struct dentry *default_unicast_key;
struct dentry *default_multicast_key;
@@ -801,11 +800,6 @@ enum sdata_queue_type {
enum {
IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2,
- IEEE80211_EOSP_MSG = 3,
-};
-
-struct skb_eosp_msg_data {
- u8 sta[ETH_ALEN], iface[ETH_ALEN];
};
enum queue_stop_reason {
@@ -816,6 +810,7 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
+ IEEE80211_QUEUE_STOP_REASON_FLUSH,
};
#ifdef CONFIG_MAC80211_LEDS
@@ -1530,8 +1525,10 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr, bool ack);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
+ unsigned long queues,
enum queue_stop_reason reason);
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
+ unsigned long queues,
enum queue_stop_reason reason);
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
@@ -1548,6 +1545,8 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
{
ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
}
+void ieee80211_flush_queues(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index a2b5e17036bb..69aaba79a9f7 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -92,7 +92,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
return 0;
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
return IEEE80211_CONF_CHANGE_IDLE;
@@ -560,8 +560,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
goto err_del_interface;
}
- drv_add_interface_debugfs(local, sdata);
-
if (sdata->vif.type == NL80211_IFTYPE_AP) {
local->fif_pspoll++;
local->fif_probe_req++;
@@ -849,8 +847,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP:
skb_queue_purge(&sdata->skb_queue);
- drv_remove_interface_debugfs(local, sdata);
-
if (going_down)
drv_remove_interface(local, sdata);
}
@@ -922,6 +918,17 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
atomic_dec(&local->iff_promiscs);
sdata->flags ^= IEEE80211_SDATA_PROMISC;
}
+
+ /*
+ * TODO: If somebody needs this on AP interfaces,
+ * it can be enabled easily but multicast
+ * addresses from VLANs need to be synced.
+ */
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP)
+ drv_set_multicast_list(local, sdata, &dev->mc);
+
spin_lock_bh(&local->filter_lock);
__hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
spin_unlock_bh(&local->filter_lock);
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 99e9f6ae6a54..67059b88fea5 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -248,11 +248,11 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
}
-static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta,
- bool pairwise,
- struct ieee80211_key *old,
- struct ieee80211_key *new)
+static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ bool pairwise,
+ struct ieee80211_key *old,
+ struct ieee80211_key *new)
{
int idx;
bool defunikey, defmultikey, defmgmtkey;
@@ -397,25 +397,21 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
return key;
}
+static void ieee80211_key_free_common(struct ieee80211_key *key)
+{
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
+ ieee80211_aes_key_free(key->u.ccmp.tfm);
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+ ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
+ kfree(key);
+}
+
static void __ieee80211_key_destroy(struct ieee80211_key *key,
bool delay_tailroom)
{
- if (!key)
- return;
-
- /*
- * Synchronize so the TX path can no longer be using
- * this key before we free/remove it.
- */
- synchronize_net();
-
if (key->local)
ieee80211_key_disable_hw_accel(key);
- if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
- ieee80211_aes_key_free(key->u.ccmp.tfm);
- if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
- ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
if (key->local) {
struct ieee80211_sub_if_data *sdata = key->sdata;
@@ -431,7 +427,28 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key,
}
}
- kfree(key);
+ ieee80211_key_free_common(key);
+}
+
+static void ieee80211_key_destroy(struct ieee80211_key *key,
+ bool delay_tailroom)
+{
+ if (!key)
+ return;
+
+ /*
+ * Synchronize so the TX path can no longer be using
+ * this key before we free/remove it.
+ */
+ synchronize_net();
+
+ __ieee80211_key_destroy(key, delay_tailroom);
+}
+
+void ieee80211_key_free_unused(struct ieee80211_key *key)
+{
+ WARN_ON(key->sdata || key->local);
+ ieee80211_key_free_common(key);
}
int ieee80211_key_link(struct ieee80211_key *key,
@@ -462,19 +479,22 @@ int ieee80211_key_link(struct ieee80211_key *key,
increment_tailroom_need_count(sdata);
- __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
- __ieee80211_key_destroy(old_key, true);
+ ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
+ ieee80211_key_destroy(old_key, true);
ieee80211_debugfs_key_add(key);
ret = ieee80211_key_enable_hw_accel(key);
+ if (ret)
+ ieee80211_key_free(key, true);
+
mutex_unlock(&sdata->local->key_mtx);
return ret;
}
-void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
+void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
{
if (!key)
return;
@@ -483,18 +503,10 @@ void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
* Replace key with nothingness if it was ever used.
*/
if (key->sdata)
- __ieee80211_key_replace(key->sdata, key->sta,
+ ieee80211_key_replace(key->sdata, key->sta,
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
key, NULL);
- __ieee80211_key_destroy(key, delay_tailroom);
-}
-
-void ieee80211_key_free(struct ieee80211_local *local,
- struct ieee80211_key *key)
-{
- mutex_lock(&local->key_mtx);
- __ieee80211_key_free(key, true);
- mutex_unlock(&local->key_mtx);
+ ieee80211_key_destroy(key, delay_tailroom);
}
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
@@ -554,6 +566,7 @@ EXPORT_SYMBOL(ieee80211_iter_keys);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_key *key, *tmp;
+ LIST_HEAD(keys);
cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
@@ -565,17 +578,65 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
ieee80211_debugfs_key_remove_mgmt_default(sdata);
- list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
- __ieee80211_key_free(key, false);
+ list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
+ ieee80211_key_replace(key->sdata, key->sta,
+ key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
+ key, NULL);
+ list_add_tail(&key->list, &keys);
+ }
ieee80211_debugfs_key_update_default(sdata);
+ if (!list_empty(&keys)) {
+ synchronize_net();
+ list_for_each_entry_safe(key, tmp, &keys, list)
+ __ieee80211_key_destroy(key, false);
+ }
+
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
sdata->crypto_tx_tailroom_pending_dec);
mutex_unlock(&sdata->local->key_mtx);
}
+void ieee80211_free_sta_keys(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_key *key, *tmp;
+ LIST_HEAD(keys);
+ int i;
+
+ mutex_lock(&local->key_mtx);
+ for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ key = key_mtx_dereference(local, sta->gtk[i]);
+ if (!key)
+ continue;
+ ieee80211_key_replace(key->sdata, key->sta,
+ key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
+ key, NULL);
+ list_add(&key->list, &keys);
+ }
+
+ key = key_mtx_dereference(local, sta->ptk);
+ if (key) {
+ ieee80211_key_replace(key->sdata, key->sta,
+ key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
+ key, NULL);
+ list_add(&key->list, &keys);
+ }
+
+ /*
+ * NB: the station code relies on this being
+ * done even if there aren't any keys
+ */
+ synchronize_net();
+
+ list_for_each_entry_safe(key, tmp, &keys, list)
+ __ieee80211_key_destroy(key, true);
+
+ mutex_unlock(&local->key_mtx);
+}
+
void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
{
struct ieee80211_sub_if_data *sdata;
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 2a682d81cee9..e8de3e6d7804 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -129,19 +129,20 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
size_t seq_len, const u8 *seq);
/*
* Insert a key into data structures (sdata, sta if necessary)
- * to make it used, free old key.
+ * to make it used, free old key. On failure, also free the new key.
*/
-int __must_check ieee80211_key_link(struct ieee80211_key *key,
- struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta);
-void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
-void ieee80211_key_free(struct ieee80211_local *local,
- struct ieee80211_key *key);
+int ieee80211_key_link(struct ieee80211_key *key,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta);
+void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
+void ieee80211_key_free_unused(struct ieee80211_key *key);
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
bool uni, bool multi);
void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
int idx);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
+void ieee80211_free_sta_keys(struct ieee80211_local *local,
+ struct sta_info *sta);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
#define key_mtx_dereference(local, ref) \
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 5a53aa5ede80..c6f81ecc36a1 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -100,7 +100,6 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
int power;
enum nl80211_channel_type channel_type;
u32 offchannel_flag;
- bool scanning = false;
offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
if (local->scan_channel) {
@@ -147,9 +146,6 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
changed |= IEEE80211_CONF_CHANGE_SMPS;
}
- scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
- test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
- test_bit(SCAN_HW_SCANNING, &local->scanning);
power = chan->max_power;
rcu_read_lock();
@@ -226,8 +222,6 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
static void ieee80211_tasklet_handler(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *) data;
- struct sta_info *sta, *tmp;
- struct skb_eosp_msg_data *eosp_data;
struct sk_buff *skb;
while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -243,18 +237,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
skb->pkt_type = 0;
ieee80211_tx_status(&local->hw, skb);
break;
- case IEEE80211_EOSP_MSG:
- eosp_data = (void *)skb->cb;
- for_each_sta_info(local, eosp_data->sta, sta, tmp) {
- /* skip wrong virtual interface */
- if (memcmp(eosp_data->iface,
- sta->sdata->vif.addr, ETH_ALEN))
- continue;
- clear_sta_flag(sta, WLAN_STA_SP);
- break;
- }
- dev_kfree_skb(skb);
- break;
default:
WARN(1, "mac80211: Packet is of unknown type %d\n",
skb->pkt_type);
@@ -295,8 +277,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
"Hardware restart was requested\n");
/* use this reason, ieee80211_reconfig will unblock it */
- ieee80211_stop_queues_by_reason(hw,
- IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+ ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/*
* Stop all Rx during the reconfig. We don't want state changes
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 77b5710db241..123a300cef57 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -699,10 +699,8 @@ out_free:
static int
ieee80211_mesh_rebuild_beacon(struct ieee80211_if_mesh *ifmsh)
{
- struct ieee80211_sub_if_data *sdata;
struct beacon_data *old_bcn;
int ret;
- sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
mutex_lock(&ifmsh->mtx);
@@ -833,9 +831,8 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *hdr;
struct ieee802_11_elems elems;
size_t baselen;
- u8 *pos, *end;
+ u8 *pos;
- end = ((u8 *) mgmt) + len;
pos = mgmt->u.probe_req.variable;
baselen = (u8 *) pos - (u8 *) mgmt;
if (baselen > len)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 167158646593..e06dbbf8cb4c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1009,6 +1009,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
/* XXX: wait for a beacon first? */
ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
out:
ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
@@ -1108,6 +1109,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (sw_elem->mode)
ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
if (sdata->local->ops->channel_switch) {
@@ -1375,6 +1377,7 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
}
ieee80211_wake_queues_by_reason(&local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_PS);
}
@@ -1436,7 +1439,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
else {
ieee80211_send_nullfunc(local, sdata, 1);
/* Flush to get the tx status of nullfunc frame */
- drv_flush(local, false);
+ ieee80211_flush_queues(local, sdata);
}
}
@@ -1767,7 +1770,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
if (tx)
- drv_flush(local, false);
+ ieee80211_flush_queues(local, sdata);
/* deauthenticate/disassociate now */
if (tx || frame_buf)
@@ -1776,7 +1779,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* flush out frame */
if (tx)
- drv_flush(local, false);
+ ieee80211_flush_queues(local, sdata);
/* clear bssid only after building the needed mgmt frames */
memset(ifmgd->bssid, 0, ETH_ALEN);
@@ -1948,7 +1951,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
run_again(ifmgd, ifmgd->probe_timeout);
if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
- drv_flush(sdata->local, false);
+ ieee80211_flush_queues(sdata->local, sdata);
}
static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
@@ -2071,6 +2074,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
true, frame_buf);
ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
mutex_unlock(&ifmgd->mtx);
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 950c95bec13d..cce795871ab1 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -118,9 +118,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
* Stop queues and transmit all frames queued by the driver
* before sending nullfunc to enable powersave at the AP.
*/
- ieee80211_stop_queues_by_reason(&local->hw,
+ ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
@@ -181,7 +181,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
}
mutex_unlock(&local->iflist_mtx);
- ieee80211_wake_queues_by_reason(&local->hw,
+ ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
}
@@ -382,7 +382,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
ieee80211_roc_notify_destroy(roc, !roc->abort);
if (started) {
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
local->tmp_channel = NULL;
ieee80211_hw_config(local, 0);
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index b471a67f224d..3d16f4e61743 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -30,12 +30,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
}
ieee80211_stop_queues_by_reason(hw,
- IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/* flush out all packets */
synchronize_net();
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
local->quiescing = true;
/* make quiescing visible to timers everywhere */
@@ -68,6 +69,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
mutex_unlock(&local->sta_mtx);
}
ieee80211_wake_queues_by_reason(hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
return err;
} else if (err > 0) {
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 749552bdcfe1..d2b264d1311d 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -202,14 +202,23 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
struct minstrel_rate_stats *mr;
unsigned int nsecs = 0;
unsigned int tp;
+ unsigned int prob;
mr = &mi->groups[group].rates[rate];
+ prob = mr->probability;
- if (mr->probability < MINSTREL_FRAC(1, 10)) {
+ if (prob < MINSTREL_FRAC(1, 10)) {
mr->cur_tp = 0;
return;
}
+ /*
+ * For the throughput calculation, limit the probability value to 90% to
+ * account for collision related packet error rate fluctuation
+ */
+ if (prob > MINSTREL_FRAC(9, 10))
+ prob = MINSTREL_FRAC(9, 10);
+
if (group != MINSTREL_CCK_GROUP)
nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
@@ -639,15 +648,18 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
/*
* Sampling might add some overhead (RTS, no aggregation)
* to the frame. Hence, don't use sampling for the currently
- * used max TP rate.
+ * used rates.
*/
- if (sample_idx == mi->max_tp_rate)
+ if (sample_idx == mi->max_tp_rate ||
+ sample_idx == mi->max_tp_rate2 ||
+ sample_idx == mi->max_prob_rate)
return -1;
+
/*
- * When not using MRR, do not sample if the probability is already
- * higher than 95% to avoid wasting airtime
+ * Do not sample if the probability is already higher than 95%
+ * to avoid wasting airtime.
*/
- if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100)))
+ if (mr->probability > MINSTREL_FRAC(95, 100))
return -1;
/*
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 43a45cf00e06..cb34cbbaa20c 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -153,7 +153,6 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
u8 *elements;
struct ieee80211_channel *channel;
size_t baselen;
- bool beacon;
struct ieee802_11_elems elems;
if (skb->len < 24 ||
@@ -175,11 +174,9 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
elements = mgmt->u.probe_resp.variable;
baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
- beacon = false;
} else {
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
elements = mgmt->u.beacon.variable;
- beacon = true;
}
if (baselen > skb->len)
@@ -335,7 +332,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
ieee80211_offchannel_stop_vifs(local);
/* ensure nullfunc is transmitted before leaving operating channel */
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
ieee80211_configure_filter(local);
@@ -671,7 +668,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local,
ieee80211_offchannel_stop_vifs(local);
if (local->ops->flush) {
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
*next_delay = 0;
} else
*next_delay = HZ / 10;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 85458a28ffa0..11216bc13b27 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -556,6 +556,15 @@ static inline void __bss_tim_clear(u8 *tim, u16 id)
tim[id / 8] &= ~(1 << (id % 8));
}
+static inline bool __bss_tim_get(u8 *tim, u16 id)
+{
+ /*
+ * This format has been mandated by the IEEE specifications,
+ * so this line may not be changed to use the test_bit() format.
+ */
+ return tim[id / 8] & (1 << (id % 8));
+}
+
static unsigned long ieee80211_tids_for_ac(int ac)
{
/* If we ever support TIDs > 7, this obviously needs to be adjusted */
@@ -636,6 +645,9 @@ void sta_info_recalc_tim(struct sta_info *sta)
done:
spin_lock_bh(&local->tim_lock);
+ if (indicate_tim == __bss_tim_get(ps->tim, id))
+ goto out_unlock;
+
if (indicate_tim)
__bss_tim_set(ps->tim, id);
else
@@ -647,6 +659,7 @@ void sta_info_recalc_tim(struct sta_info *sta)
local->tim_in_locked_section = false;
}
+out_unlock:
spin_unlock_bh(&local->tim_lock);
}
@@ -770,8 +783,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
{
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
- int ret, i;
- bool have_key = false;
+ int ret;
might_sleep();
@@ -798,22 +810,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
list_del_rcu(&sta->list);
- mutex_lock(&local->key_mtx);
- for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]),
- true);
- have_key = true;
- }
- if (sta->ptk) {
- __ieee80211_key_free(key_mtx_dereference(local, sta->ptk),
- true);
- have_key = true;
- }
-
- mutex_unlock(&local->key_mtx);
-
- if (!have_key)
- synchronize_net();
+ /* this always calls synchronize_net() */
+ ieee80211_free_sta_keys(local, sta);
sta->dead = true;
@@ -1399,30 +1397,16 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_sta_block_awake);
-void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta)
+void ieee80211_sta_eosp(struct ieee80211_sta *pubsta)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
struct ieee80211_local *local = sta->local;
- struct sk_buff *skb;
- struct skb_eosp_msg_data *data;
trace_api_eosp(local, pubsta);
- skb = alloc_skb(0, GFP_ATOMIC);
- if (!skb) {
- /* too bad ... but race is better than loss */
- clear_sta_flag(sta, WLAN_STA_SP);
- return;
- }
-
- data = (void *)skb->cb;
- memcpy(data->sta, pubsta->addr, ETH_ALEN);
- memcpy(data->iface, sta->sdata->vif.addr, ETH_ALEN);
- skb->pkt_type = IEEE80211_EOSP_MSG;
- skb_queue_tail(&local->skb_queue, skb);
- tasklet_schedule(&local->tasklet);
+ clear_sta_flag(sta, WLAN_STA_SP);
}
-EXPORT_SYMBOL(ieee80211_sta_eosp_irqsafe);
+EXPORT_SYMBOL(ieee80211_sta_eosp);
void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
u8 tid, bool buffered)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index e5868c32d1a3..adc30045f99e 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -333,7 +333,8 @@ struct sta_info {
unsigned long driver_buffered_tids;
/* Updated from RX path only, no locking requirements */
- unsigned long rx_packets, rx_bytes;
+ unsigned long rx_packets;
+ u64 rx_bytes;
unsigned long wep_weak_iv_count;
unsigned long last_rx;
long last_connected;
@@ -353,9 +354,9 @@ struct sta_info {
unsigned int fail_avg;
/* Updated from TX path only, no locking requirements */
- unsigned long tx_packets;
- unsigned long tx_bytes;
- unsigned long tx_fragments;
+ u32 tx_fragments;
+ u64 tx_packets[IEEE80211_NUM_ACS];
+ u64 tx_bytes[IEEE80211_NUM_ACS];
struct ieee80211_tx_rate last_tx_rate;
int last_rx_rate_idx;
u32 last_rx_rate_flag;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index e7db2b804e0c..c5899797a8d4 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -431,6 +431,30 @@ TRACE_EVENT(drv_prepare_multicast,
)
);
+TRACE_EVENT(drv_set_multicast_list,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata, int mc_count),
+
+ TP_ARGS(local, sdata, mc_count),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(bool, allmulti)
+ __field(int, mc_count)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
+ __entry->mc_count = mc_count;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " configure mc filter, count=%d, allmulti=%d",
+ LOCAL_PR_ARG, __entry->mc_count, __entry->allmulti
+ )
+);
+
TRACE_EVENT(drv_configure_filter,
TP_PROTO(struct ieee80211_local *local,
unsigned int changed_flags,
@@ -940,23 +964,26 @@ TRACE_EVENT(drv_get_survey,
);
TRACE_EVENT(drv_flush,
- TP_PROTO(struct ieee80211_local *local, bool drop),
+ TP_PROTO(struct ieee80211_local *local,
+ u32 queues, bool drop),
- TP_ARGS(local, drop),
+ TP_ARGS(local, queues, drop),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(bool, drop)
+ __field(u32, queues)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->drop = drop;
+ __entry->queues = queues;
),
TP_printk(
- LOCAL_PR_FMT " drop:%d",
- LOCAL_PR_ARG, __entry->drop
+ LOCAL_PR_FMT " queues:0x%x drop:%d",
+ LOCAL_PR_ARG, __entry->queues, __entry->drop
)
);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4e8a86163fc7..9e67cc97b87b 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -233,6 +233,7 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_PS);
ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
ieee80211_queue_work(&local->hw,
@@ -991,15 +992,18 @@ static ieee80211_tx_result debug_noinline
ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb;
+ int ac = -1;
if (!tx->sta)
return TX_CONTINUE;
- tx->sta->tx_packets++;
skb_queue_walk(&tx->skbs, skb) {
+ ac = skb_get_queue_mapping(skb);
tx->sta->tx_fragments++;
- tx->sta->tx_bytes += skb->len;
+ tx->sta->tx_bytes[ac] += skb->len;
}
+ if (ac >= 0)
+ tx->sta->tx_packets[ac]++;
return TX_CONTINUE;
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index b7a856e3281b..a7368870c8ee 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -453,7 +453,8 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
}
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
- enum queue_stop_reason reason)
+ unsigned long queues,
+ enum queue_stop_reason reason)
{
struct ieee80211_local *local = hw_to_local(hw);
unsigned long flags;
@@ -461,7 +462,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- for (i = 0; i < hw->queues; i++)
+ for_each_set_bit(i, &queues, hw->queues)
__ieee80211_stop_queue(hw, i, reason);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -469,7 +470,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
void ieee80211_stop_queues(struct ieee80211_hw *hw)
{
- ieee80211_stop_queues_by_reason(hw,
+ ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_DRIVER);
}
EXPORT_SYMBOL(ieee80211_stop_queues);
@@ -491,6 +492,7 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
EXPORT_SYMBOL(ieee80211_queue_stopped);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
+ unsigned long queues,
enum queue_stop_reason reason)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -499,7 +501,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- for (i = 0; i < hw->queues; i++)
+ for_each_set_bit(i, &queues, hw->queues)
__ieee80211_wake_queue(hw, i, reason);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -507,10 +509,42 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
void ieee80211_wake_queues(struct ieee80211_hw *hw)
{
- ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
+ ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_DRIVER);
}
EXPORT_SYMBOL(ieee80211_wake_queues);
+void ieee80211_flush_queues(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ u32 queues;
+
+ if (!local->ops->flush)
+ return;
+
+ if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) {
+ int ac;
+
+ queues = 0;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ queues |= BIT(sdata->vif.hw_queue[ac]);
+ if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
+ queues |= BIT(sdata->vif.cab_queue);
+ } else {
+ /* all queues */
+ queues = BIT(local->hw.queues) - 1;
+ }
+
+ ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_FLUSH);
+
+ drv_flush(local, queues, false);
+
+ ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_FLUSH);
+}
+
void ieee80211_iterate_active_interfaces(
struct ieee80211_hw *hw, u32 iter_flags,
void (*iterator)(void *data, u8 *mac,
@@ -1651,8 +1685,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_unlock(&local->sta_mtx);
}
- ieee80211_wake_queues_by_reason(hw,
- IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+ ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/*
* If this is for hw restart things are still running.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 00be55530a32..84c9ad7e1dca 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1126,8 +1126,10 @@ static int __init cfg80211_init(void)
goto out_fail_reg;
cfg80211_wq = create_singlethread_workqueue("cfg80211");
- if (!cfg80211_wq)
+ if (!cfg80211_wq) {
+ err = -ENOMEM;
goto out_fail_wq;
+ }
return 0;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b5174f65cc9a..124e5e773fbc 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -500,14 +500,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);
-
void cfg80211_leave(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
-
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index ff6f7ae35586..a9dc5c736df0 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -228,6 +228,7 @@ void cfg80211_conn_work(struct work_struct *work)
rtnl_lock();
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
+ mutex_lock(&rdev->sched_scan_mtx);
list_for_each_entry(wdev, &rdev->wdev_list, list) {
wdev_lock(wdev);
@@ -235,7 +236,7 @@ void cfg80211_conn_work(struct work_struct *work)
wdev_unlock(wdev);
continue;
}
- if (wdev->sme_state != CFG80211_SME_CONNECTING) {
+ if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) {
wdev_unlock(wdev);
continue;
}
@@ -252,6 +253,7 @@ void cfg80211_conn_work(struct work_struct *work)
wdev_unlock(wdev);
}
+ mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
rtnl_unlock();