Explorar o código

Bring in sources from endlessm at 937be30d1142c74a2b82291d63c6b3d1911b7498 - Realtek v5.5.2

Tomás Pinho %!s(int64=6) %!d(string=hai) anos
pai
achega
06052776f5
Modificáronse 100 ficheiros con 37485 adicións e 8634 borrados
  1. 495 160
      Makefile
  2. 515 209
      core/efuse/rtw_efuse.c
  3. 4097 0
      core/mesh/rtw_mesh.c
  4. 534 0
      core/mesh/rtw_mesh.h
  5. 1665 0
      core/mesh/rtw_mesh_hwmp.c
  6. 60 0
      core/mesh/rtw_mesh_hwmp.h
  7. 1185 0
      core/mesh/rtw_mesh_pathtbl.c
  8. 206 0
      core/mesh/rtw_mesh_pathtbl.h
  9. 466 187
      core/rtw_ap.c
  10. 67 64
      core/rtw_beamforming.c
  11. 4 8
      core/rtw_br_ext.c
  12. 3 8
      core/rtw_bt_mp.c
  13. 38 11
      core/rtw_btcoex.c
  14. 12 7
      core/rtw_btcoex_wifionly.c
  15. 1184 0
      core/rtw_chplan.c
  16. 179 0
      core/rtw_chplan.h
  17. 499 260
      core/rtw_cmd.c
  18. 407 213
      core/rtw_debug.c
  19. 2 7
      core/rtw_eeprom.c
  20. 314 141
      core/rtw_ieee80211.c
  21. 255 53
      core/rtw_io.c
  22. 2 7
      core/rtw_ioctl_query.c
  23. 6 9
      core/rtw_ioctl_rtl.c
  24. 94 422
      core/rtw_ioctl_set.c
  25. 20 13
      core/rtw_iol.c
  26. 14 0
      core/rtw_mem.c
  27. 412 149
      core/rtw_mi.c
  28. 424 228
      core/rtw_mlme.c
  29. 356 390
      core/rtw_mlme_ext.c
  30. 474 181
      core/rtw_mp.c
  31. 2 7
      core/rtw_mp_ioctl.c
  32. 65 91
      core/rtw_odm.c
  33. 261 114
      core/rtw_p2p.c
  34. 374 196
      core/rtw_pwrctrl.c
  35. 522 220
      core/rtw_recv.c
  36. 608 422
      core/rtw_rf.c
  37. 2470 0
      core/rtw_rm.c
  38. 998 0
      core/rtw_rm_fsm.c
  39. 595 0
      core/rtw_rson.c
  40. 52 20
      core/rtw_sdio.c
  41. 348 118
      core/rtw_security.c
  42. 29 61
      core/rtw_sreset.c
  43. 235 98
      core/rtw_sta_mgt.c
  44. 374 169
      core/rtw_tdls.c
  45. 451 119
      core/rtw_vht.c
  46. 79 7
      core/rtw_wapi.c
  47. 14 0
      core/rtw_wapi_sms4.c
  48. 407 274
      core/rtw_wlan_util.c
  49. 547 297
      core/rtw_xmit.c
  50. 32 8
      hal/HalPwrSeqCmd.c
  51. 899 932
      hal/btc/halbtc8821c1ant.c
  52. 348 366
      hal/btc/halbtc8821c1ant.h
  53. 771 298
      hal/btc/halbtc8821c2ant.c
  54. 368 384
      hal/btc/halbtc8821c2ant.h
  55. 27 0
      hal/btc/halbtc8821cwifionly.c
  56. 19 0
      hal/btc/halbtc8821cwifionly.h
  57. 264 2
      hal/btc/halbtcoutsrc.h
  58. 51 10
      hal/btc/mp_precomp.h
  59. 45 5
      hal/efuse/efuse_mask.h
  60. 13 18
      hal/efuse/rtl8821c/HalEfuseMask8821C_PCIE.c
  61. 13 18
      hal/efuse/rtl8821c/HalEfuseMask8821C_PCIE.h
  62. 13 18
      hal/efuse/rtl8821c/HalEfuseMask8821C_SDIO.c
  63. 13 18
      hal/efuse/rtl8821c/HalEfuseMask8821C_SDIO.h
  64. 13 18
      hal/efuse/rtl8821c/HalEfuseMask8821C_USB.c
  65. 13 18
      hal/efuse/rtl8821c/HalEfuseMask8821C_USB.h
  66. 503 83
      hal/hal_btcoex.c
  67. 73 5
      hal/hal_btcoex_wifionly.c
  68. 761 106
      hal/hal_com.c
  69. 11 7
      hal/hal_com_c2h.h
  70. 296 248
      hal/hal_com_phycfg.c
  71. 1127 55
      hal/hal_dm.c
  72. 81 7
      hal/hal_dm.h
  73. 554 0
      hal/hal_dm_acs.c
  74. 167 0
      hal/hal_dm_acs.h
  75. 1694 226
      hal/hal_halmac.c
  76. 142 25
      hal/hal_halmac.h
  77. 2 7
      hal/hal_hci/hal_pci.c
  78. 422 198
      hal/hal_intf.c
  79. 699 150
      hal/hal_mcc.c
  80. 286 205
      hal/hal_mp.c
  81. 21 24
      hal/hal_phy.c
  82. 20 15
      hal/halmac/halmac_2_platform.h
  83. 50 70
      hal/halmac/halmac_88xx/halmac_8821c/halmac_8821c_cfg.h
  84. 145 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_cfg_wmac_8821c.c
  85. 40 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_cfg_wmac_8821c.h
  86. 182 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_common_8821c.c
  87. 36 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_common_8821c.h
  88. 846 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_gpio_8821c.c
  89. 37 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_gpio_8821c.h
  90. 890 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_init_8821c.c
  91. 43 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_init_8821c.h
  92. 356 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_pcie_8821c.c
  93. 45 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_pcie_8821c.h
  94. 76 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_phy_8821c.c
  95. 905 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_pwr_seq_8821c.c
  96. 37 0
      hal/halmac/halmac_88xx/halmac_8821c/halmac_pwr_seq_8821c.h
  97. 31 150
      hal/halmac/halmac_88xx/halmac_88xx_cfg.h
  98. 395 0
      hal/halmac/halmac_88xx/halmac_bb_rf_88xx.c
  99. 57 0
      hal/halmac/halmac_88xx/halmac_bb_rf_88xx.h
  100. 1133 0
      hal/halmac/halmac_88xx/halmac_cfg_wmac_88xx.c

+ 495 - 160
Makefile

@@ -20,8 +20,7 @@ ifeq ($(GCC_VER_49),1)
 EXTRA_CFLAGS += -Wno-date-time	# Fix compile error && warning on gcc 4.9 and later
 endif
 
-EXTRA_CFLAGS += -I$(src)/include
-EXTRA_CFLAGS += -I$(src)/hal/phydm
+EXTRA_CFLAGS += -I$(srctree)/$(src)/include
 
 EXTRA_LDFLAGS += --strip-debug
 
@@ -37,9 +36,12 @@ CONFIG_RTL8723B = n
 CONFIG_RTL8814A = n
 CONFIG_RTL8723C = n
 CONFIG_RTL8188F = n
+CONFIG_RTL8188GTV = n
 CONFIG_RTL8822B = n
 CONFIG_RTL8723D = n
 CONFIG_RTL8821C = y
+CONFIG_RTL8710B = n
+CONFIG_RTL8192F = n
 ######################### Interface ###########################
 CONFIG_USB_HCI = n
 CONFIG_PCI_HCI = y
@@ -56,10 +58,11 @@ CONFIG_INTEL_WIDI = n
 CONFIG_WAPI_SUPPORT = n
 CONFIG_EFUSE_CONFIG_FILE = y
 CONFIG_EXT_CLK = n
-CONFIG_TRAFFIC_PROTECT = y
+CONFIG_TRAFFIC_PROTECT = n
 CONFIG_LOAD_PHY_PARA_FROM_FILE = y
 CONFIG_TXPWR_BY_RATE_EN = auto
 CONFIG_TXPWR_LIMIT_EN = auto
+CONFIG_RTW_CHPLAN = 0xFF
 CONFIG_RTW_ADAPTIVITY_EN = disable
 CONFIG_RTW_ADAPTIVITY_MODE = normal
 CONFIG_SIGNAL_SCALE_MAPPING = n
@@ -72,17 +75,27 @@ CONFIG_MCC_MODE = n
 CONFIG_APPEND_VENDOR_IE_ENABLE = n
 CONFIG_RTW_NAPI = y
 CONFIG_RTW_GRO = y
+CONFIG_RTW_NETIF_SG = y
+CONFIG_TX_CSUM_OFFLOAD = n
+CONFIG_RTW_IPCAM_APPLICATION = n
+CONFIG_RTW_REPEATER_SON = n
+CONFIG_RTW_WIFI_HAL = n
+CONFIG_ICMP_VOQ = n
 ########################## Debug ###########################
 CONFIG_RTW_DEBUG = y
 # default log level is _DRV_INFO_ = 4,
 # please refer to "How_to_set_driver_debug_log_level.doc" to set the available level.
-CONFIG_RTW_LOG_LEVEL = 3
+CONFIG_RTW_LOG_LEVEL = 4
 ######################## Wake On Lan ##########################
 CONFIG_WOWLAN = n
+#bit2: deauth, bit1: unicast, bit0: magic pkt.
+CONFIG_WAKEUP_TYPE = 0x7
 CONFIG_GPIO_WAKEUP = n
-CONFIG_DEFAULT_PATTERNS_EN = n
 CONFIG_WAKEUP_GPIO_IDX = default
-CONFIG_HIGH_ACTIVE = n
+CONFIG_HIGH_ACTIVE_DEV2HST = n
+######### only for USB #########
+CONFIG_ONE_PIN_GPIO = n
+CONFIG_HIGH_ACTIVE_HST2DEV = n
 CONFIG_PNO_SUPPORT = n
 CONFIG_PNO_SET_DEBUG = n
 CONFIG_AP_WOWLAN = n
@@ -134,22 +147,30 @@ CONFIG_PLATFORM_ACTIONS_ATV5201 = n
 CONFIG_PLATFORM_ACTIONS_ATM705X = n
 CONFIG_PLATFORM_ARM_SUN50IW1P1 = n
 CONFIG_PLATFORM_ARM_RTD299X = n
+CONFIG_PLATFORM_ARM_LGE = n
 CONFIG_PLATFORM_ARM_SPREADTRUM_6820 = n
 CONFIG_PLATFORM_ARM_SPREADTRUM_8810 = n
 CONFIG_PLATFORM_ARM_WMT = n
 CONFIG_PLATFORM_TI_DM365 = n
 CONFIG_PLATFORM_MOZART = n
 CONFIG_PLATFORM_RTK119X = n
+CONFIG_PLATFORM_RTK119X_AM = n
 CONFIG_PLATFORM_RTK129X = n
+CONFIG_PLATFORM_RTK390X = n
 CONFIG_PLATFORM_NOVATEK_NT72668 = n
 CONFIG_PLATFORM_HISILICON = n
+CONFIG_PLATFORM_HISILICON_HI3798 = n
 CONFIG_PLATFORM_NV_TK1 = n
+CONFIG_PLATFORM_NV_TK1_UBUNTU = n
 CONFIG_PLATFORM_RTL8197D = n
-###############################################################
+CONFIG_PLATFORM_AML_S905 = n
+CONFIG_PLATFORM_ZTE_ZX296716 = n
+########### CUSTOMER ################################
+CONFIG_CUSTOMER_HUAWEI_GENERAL = n
 
 CONFIG_DRVEXT_MODULE = n
 
-export TopDIR ?= $(shell pwd)
+export TopDIR ?= $(srctree)/$(src)
 
 ########### COMMON  #################################
 ifeq ($(CONFIG_GSPI_HCI), y)
@@ -181,7 +202,8 @@ _OS_INTFS_FILES :=	os_dep/osdep_service.o \
 			os_dep/linux/rtw_cfgvendor.o \
 			os_dep/linux/wifi_regd.o \
 			os_dep/linux/rtw_android.o \
-			os_dep/linux/rtw_proc.o
+			os_dep/linux/rtw_proc.o \
+			os_dep/linux/rtw_rhashtable.o
 
 ifeq ($(CONFIG_MP_INCLUDED), y)
 _OS_INTFS_FILES += os_dep/linux/ioctl_mp.o
@@ -203,66 +225,20 @@ _HAL_INTFS_FILES :=	hal/hal_intf.o \
 			hal/hal_com_phycfg.o \
 			hal/hal_phy.o \
 			hal/hal_dm.o \
+			hal/hal_dm_acs.o \
 			hal/hal_btcoex_wifionly.o \
 			hal/hal_btcoex.o \
 			hal/hal_mp.o \
 			hal/hal_mcc.o \
 			hal/hal_hci/hal_$(HCI_NAME).o \
+			hal/led/hal_led.o \
 			hal/led/hal_$(HCI_NAME)_led.o
 
-			
-_OUTSRC_FILES := hal/phydm/phydm_debug.o	\
-		hal/phydm/phydm_antdiv.o\
-		hal/phydm/phydm_antdect.o\
-		hal/phydm/phydm_interface.o\
-		hal/phydm/phydm_hwconfig.o\
-		hal/phydm/phydm.o\
-		hal/phydm/halphyrf_ce.o\
-		hal/phydm/phydm_dig.o\
-		hal/phydm/phydm_pathdiv.o\
-		hal/phydm/phydm_rainfo.o\
-		hal/phydm/phydm_dynamicbbpowersaving.o\
-		hal/phydm/phydm_powertracking_ce.o\
-		hal/phydm/phydm_dynamictxpower.o\
-		hal/phydm/phydm_adaptivity.o\
-		hal/phydm/phydm_cfotracking.o\
-		hal/phydm/phydm_noisemonitor.o\
-		hal/phydm/phydm_acs.o\
-		hal/phydm/phydm_beamforming.o\
-		hal/phydm/phydm_dfs.o\
-		hal/phydm/txbf/halcomtxbf.o\
-		hal/phydm/txbf/haltxbfinterface.o\
-		hal/phydm/txbf/phydm_hal_txbf_api.o\
-		hal/phydm/phydm_adc_sampling.o\
-		hal/phydm/phydm_kfree.o\
-		hal/phydm/phydm_ccx.o\
-		hal/phydm/phydm_psd.o
-
-EXTRA_CFLAGS += -I$(src)/platform
-_PLATFORM_FILES := platform/platform_ops.o
 
-EXTRA_CFLAGS += -I$(src)/hal/btc
-_OUTSRC_FILES += hal/btc/halbtc8723bwifionly.o \
-				hal/btc/halbtc8822bwifionly.o \
-				hal/btc/halbtc8821cwifionly.o
-ifeq ($(CONFIG_BT_COEXIST), y)
-_OUTSRC_FILES += hal/btc/halbtc8192e1ant.o \
-				hal/btc/halbtc8192e2ant.o \
-				hal/btc/halbtc8723b1ant.o \
-				hal/btc/halbtc8723b2ant.o \
-				hal/btc/halbtc8812a1ant.o \
-				hal/btc/halbtc8812a2ant.o \
-				hal/btc/halbtc8821a1ant.o \
-				hal/btc/halbtc8821a2ant.o \
-				hal/btc/halbtc8703b1ant.o \
-				hal/btc/halbtc8723d1ant.o \
-				hal/btc/halbtc8723d2ant.o \
-				hal/btc/halbtc8822b1ant.o \
-				hal/btc/halbtc8822b2ant.o \
-				hal/btc/halbtc8821c1ant.o \
-				hal/btc/halbtc8821c2ant.o
-endif
+EXTRA_CFLAGS += -I$(srctree)/$(src)/platform
+_PLATFORM_FILES := platform/platform_ops.o
 
+EXTRA_CFLAGS += -I$(srctree)/$(src)/hal/btc
 
 ########### HAL_RTL8188E #################################
 ifeq ($(CONFIG_RTL8188E), y)
@@ -323,15 +299,6 @@ ifeq ($(CONFIG_SDIO_HCI), y)
 _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_SDIO.o
 endif
 
-#hal/OUTSRC/$(RTL871X)/Hal8188EFWImg_CE.o
-_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8188e_mac.o\
-		hal/phydm/$(RTL871X)/halhwimg8188e_bb.o\
-		hal/phydm/$(RTL871X)/halhwimg8188e_rf.o\
-		hal/phydm/$(RTL871X)/halphyrf_8188e_ce.o\
-		hal/phydm/$(RTL871X)/phydm_regconfig8188e.o\
-		hal/phydm/$(RTL871X)/hal8188erateadaptive.o\
-		hal/phydm/$(RTL871X)/phydm_rtl8188e.o
-
 endif
 
 ########### HAL_RTL8192E #################################
@@ -387,13 +354,10 @@ ifeq ($(CONFIG_SDIO_HCI), y)
 _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_SDIO.o
 endif
 
-#hal/OUTSRC/$(RTL871X)/HalHWImg8188E_FW.o
-_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8192e_mac.o\
-		hal/phydm/$(RTL871X)/halhwimg8192e_bb.o\
-		hal/phydm/$(RTL871X)/halhwimg8192e_rf.o\
-		hal/phydm/$(RTL871X)/halphyrf_8192e_ce.o\
-		hal/phydm/$(RTL871X)/phydm_regconfig8192e.o\
-		hal/phydm/$(RTL871X)/phydm_rtl8192e.o
+ifeq ($(CONFIG_BT_COEXIST), y)
+_BTC_FILES += hal/btc/halbtc8192e1ant.o \
+				hal/btc/halbtc8192e2ant.o
+endif
 
 endif
 
@@ -462,14 +426,6 @@ endif
 ifeq ($(CONFIG_RTL8812A), y)
 EXTRA_CFLAGS += -DCONFIG_RTL8812A
 _HAL_INTFS_FILES +=	hal/rtl8812a/hal8812a_fw.o
-
-_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8812a_mac.o\
-		hal/phydm/$(RTL871X)/halhwimg8812a_bb.o\
-		hal/phydm/$(RTL871X)/halhwimg8812a_rf.o\
-		hal/phydm/$(RTL871X)/halphyrf_8812a_ce.o\
-		hal/phydm/$(RTL871X)/phydm_regconfig8812a.o\
-		hal/phydm/$(RTL871X)/phydm_rtl8812a.o\
-		hal/phydm/txbf/haltxbfjaguar.o
 endif
 
 ifeq ($(CONFIG_RTL8821A), y)
@@ -496,18 +452,20 @@ endif
 EXTRA_CFLAGS += -DCONFIG_RTL8821A
 
 _HAL_INTFS_FILES +=	hal/rtl8812a/hal8821a_fw.o
-_OUTSRC_FILES += hal/phydm/rtl8821a/halhwimg8821a_mac.o\
-		hal/phydm/rtl8821a/halhwimg8821a_bb.o\
-		hal/phydm/rtl8821a/halhwimg8821a_rf.o\
-		hal/phydm/rtl8812a/halphyrf_8812a_ce.o\
-		hal/phydm/rtl8821a/halphyrf_8821a_ce.o\
-		hal/phydm/rtl8821a/phydm_regconfig8821a.o\
-		hal/phydm/rtl8821a/phydm_rtl8821a.o\
-		hal/phydm/rtl8821a/phydm_iqk_8821a_ce.o\
-		hal/phydm/txbf/haltxbfjaguar.o
 		
 endif
 
+ifeq ($(CONFIG_BT_COEXIST), y)
+ifeq ($(CONFIG_RTL8812A), y)
+_BTC_FILES += hal/btc/halbtc8812a1ant.o \
+				hal/btc/halbtc8812a2ant.o
+endif
+ifeq ($(CONFIG_RTL8821A), y)
+_BTC_FILES += hal/btc/halbtc8821a1ant.o \
+				hal/btc/halbtc8821a2ant.o
+endif
+endif
+
 endif
 
 ########### HAL_RTL8723B #################################
@@ -560,13 +518,11 @@ ifeq ($(CONFIG_SDIO_HCI), y)
 _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_SDIO.o
 endif
 
-_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8723b_bb.o\
-								hal/phydm/$(RTL871X)/halhwimg8723b_mac.o\
-								hal/phydm/$(RTL871X)/halhwimg8723b_rf.o\
-								hal/phydm/$(RTL871X)/halhwimg8723b_mp.o\
-								hal/phydm/$(RTL871X)/phydm_regconfig8723b.o\
-								hal/phydm/$(RTL871X)/halphyrf_8723b_ce.o\
-								hal/phydm/$(RTL871X)/phydm_rtl8723b.o
+_BTC_FILES += hal/btc/halbtc8723bwifionly.o
+ifeq ($(CONFIG_BT_COEXIST), y)
+_BTC_FILES += hal/btc/halbtc8723b1ant.o \
+				hal/btc/halbtc8723b2ant.o
+endif
 
 endif
 
@@ -626,15 +582,6 @@ ifeq ($(CONFIG_PCI_HCI), y)
 _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_PCIE.o
 endif
 
-_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8814a_bb.o\
-								hal/phydm/$(RTL871X)/halhwimg8814a_mac.o\
-								hal/phydm/$(RTL871X)/halhwimg8814a_rf.o\
-								hal/phydm/$(RTL871X)/phydm_iqk_8814a.o\
-								hal/phydm/$(RTL871X)/phydm_regconfig8814a.o\
-								hal/phydm/$(RTL871X)/halphyrf_8814a_ce.o\
-								hal/phydm/$(RTL871X)/phydm_rtl8814a.o\
-								hal/phydm/txbf/haltxbf8814a.o
-
 endif
 
 ########### HAL_RTL8723C #################################
@@ -687,11 +634,10 @@ ifeq ($(CONFIG_PCI_HCI), y)
 _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_PCIE.o
 endif
 
-_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8703b_bb.o\
-								hal/phydm/$(RTL871X)/halhwimg8703b_mac.o\
-								hal/phydm/$(RTL871X)/halhwimg8703b_rf.o\
-								hal/phydm/$(RTL871X)/phydm_regconfig8703b.o\
-								hal/phydm/$(RTL871X)/halphyrf_8703b.o
+ifeq ($(CONFIG_BT_COEXIST), y)
+_BTC_FILES += hal/btc/halbtc8703b1ant.o
+endif
+
 endif
 
 ########### HAL_RTL8723D #################################
@@ -746,12 +692,11 @@ ifeq ($(CONFIG_PCI_HCI), y)
 _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_PCIE.o
 endif
 
-_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8723d_bb.o\
-								hal/phydm/$(RTL871X)/halhwimg8723d_mac.o\
-								hal/phydm/$(RTL871X)/halhwimg8723d_rf.o\
-								hal/phydm/$(RTL871X)/phydm_regconfig8723d.o\
-								hal/phydm/$(RTL871X)/phydm_rtl8723d.o\
-								hal/phydm/$(RTL871X)/halphyrf_8723d.o
+ifeq ($(CONFIG_BT_COEXIST), y)
+_BTC_FILES += hal/btc/halbtc8723d1ant.o \
+				hal/btc/halbtc8723d2ant.o
+endif
+
 endif
 
 ########### HAL_RTL8188F #################################
@@ -802,25 +747,185 @@ ifeq ($(CONFIG_SDIO_HCI), y)
 _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_SDIO.o
 endif
 
-_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8188f_bb.o\
-								hal/phydm/$(RTL871X)/halhwimg8188f_mac.o\
-								hal/phydm/$(RTL871X)/halhwimg8188f_rf.o\
-								hal/phydm/$(RTL871X)/phydm_regconfig8188f.o\
-								hal/phydm/$(RTL871X)/halphyrf_8188f.o \
-								hal/phydm/$(RTL871X)/phydm_rtl8188f.o
+endif
+
+########### HAL_RTL8188GTV #################################
+ifeq ($(CONFIG_RTL8188GTV), y)
+
+RTL871X = rtl8188gtv
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8188gtvu
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8189gtvs
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8188GTV
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8188GTVPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8188gtv_fw.o
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188GTV_USB.o
+endif
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188GTV_SDIO.o
+endif
 
 endif
 
 ########### HAL_RTL8822B #################################
 ifeq ($(CONFIG_RTL8822B), y)
-include $(TopDIR)/rtl8822b.mk
+RTL871X := rtl8822b
+ifeq ($(CONFIG_USB_HCI), y)
+ifeq ($(CONFIG_BT_COEXIST), n)
+MODULE_NAME = 8812bu
+else
+MODULE_NAME = 88x2bu
+endif
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 88x2be
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 88x2bs
 endif
 
+endif
 ########### HAL_RTL8821C #################################
 ifeq ($(CONFIG_RTL8821C), y)
-include $(TopDIR)/rtl8821c.mk
+RTL871X := rtl8821c
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8821cu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8821ce
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8821cs
+endif
+
+endif
+
+########### HAL_RTL8710B #################################
+ifeq ($(CONFIG_RTL8710B), y)
+
+RTL871X = rtl8710b
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8710bu
+MODULE_SUB_NAME = 8710bu
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8710B
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8710BPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8710b_fw.o \
+			hal/$(RTL871X)/$(RTL871X)_lps_poff.o
+
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o
+
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8710B_USB.o
+endif
+
+endif
+
+########### HAL_RTL8192F #################################
+ifeq ($(CONFIG_RTL8192F), y)
+
+RTL871X = rtl8192f
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8192fu
+MODULE_SUB_NAME = 8192fu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8192fe
+MODULE_SUB_NAME = 8192fe
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8192fs
+MODULE_SUB_NAME = 8192fs
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8192F
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8192FPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8192f_fw.o \
+			hal/$(RTL871X)/$(RTL871X)_lps_poff.o
+
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o
+			
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_SDIO.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_USB.o
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/efuse/$(RTL871X)/HalEfuseMask8192F_PCIE.o
 endif
 
+endif
 ########### AUTO_CFG  #################################
 
 ifeq ($(CONFIG_AUTOCFG_CP), y)
@@ -915,8 +1020,7 @@ endif
 ifeq ($(CONFIG_LOAD_PHY_PARA_FROM_FILE), y)
 EXTRA_CFLAGS += -DCONFIG_LOAD_PHY_PARA_FROM_FILE
 #EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER
-#EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"/lib/firmware/\"
-EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"\"
+EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"/lib/firmware/\"
 endif
 
 ifeq ($(CONFIG_TXPWR_BY_RATE_EN), n)
@@ -935,6 +1039,10 @@ else ifeq ($(CONFIG_TXPWR_LIMIT_EN), auto)
 EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=2
 endif
 
+ifneq ($(CONFIG_RTW_CHPLAN), 0xFF)
+EXTRA_CFLAGS += -DCONFIG_RTW_CHPLAN=$(CONFIG_RTW_CHPLAN)
+endif
+
 ifeq ($(CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY), y)
 EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_BY_REGULATORY
 endif
@@ -964,13 +1072,10 @@ EXTRA_CFLAGS += -DCONFIG_IEEE80211W
 endif
 
 ifeq ($(CONFIG_WOWLAN), y)
-EXTRA_CFLAGS += -DCONFIG_WOWLAN
+EXTRA_CFLAGS += -DCONFIG_WOWLAN -DRTW_WAKEUP_EVENT=$(CONFIG_WAKEUP_TYPE)
 ifeq ($(CONFIG_SDIO_HCI), y)
 EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER
 endif
-ifeq ($(CONFIG_DEFAULT_PATTERNS_EN), y)
-EXTRA_CFLAGS += -DCONFIG_DEFAULT_PATTERNS_EN
-endif
 endif
 
 ifeq ($(CONFIG_AP_WOWLAN), y)
@@ -989,11 +1094,20 @@ endif
 
 ifeq ($(CONFIG_GPIO_WAKEUP), y)
 EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP
-ifeq ($(CONFIG_HIGH_ACTIVE), y)
-EXTRA_CFLAGS += -DHIGH_ACTIVE=1
+ifeq ($(CONFIG_ONE_PIN_GPIO), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_ONE_PIN_GPIO
+endif
+ifeq ($(CONFIG_HIGH_ACTIVE_DEV2HST), y)
+EXTRA_CFLAGS += -DHIGH_ACTIVE_DEV2HST=1
 else
-EXTRA_CFLAGS += -DHIGH_ACTIVE=0
+EXTRA_CFLAGS += -DHIGH_ACTIVE_DEV2HST=0
+endif
 endif
+
+ifeq ($(CONFIG_HIGH_ACTIVE_HST2DEV), y)
+EXTRA_CFLAGS += -DHIGH_ACTIVE_HST2DEV=1
+else
+EXTRA_CFLAGS += -DHIGH_ACTIVE_HST2DEV=0
 endif
 
 ifneq ($(CONFIG_WAKEUP_GPIO_IDX), default)
@@ -1037,6 +1151,38 @@ ifeq ($(CONFIG_RTW_GRO), y)
 EXTRA_CFLAGS += -DCONFIG_RTW_GRO
 endif
 
+ifeq ($(CONFIG_RTW_REPEATER_SON), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_REPEATER_SON
+endif
+
+ifeq ($(CONFIG_RTW_IPCAM_APPLICATION), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_IPCAM_APPLICATION
+ifeq ($(CONFIG_WIFI_MONITOR), n)
+EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR
+endif
+endif
+
+ifeq ($(CONFIG_RTW_NETIF_SG), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_NETIF_SG
+endif
+
+ifeq ($(CONFIG_TX_CSUM_OFFLOAD), y)
+EXTRA_CFLAGS += -DCONFIG_TX_CSUM_OFFLOAD
+endif
+
+ifeq ($(CONFIG_ICMP_VOQ), y)
+EXTRA_CFLAGS += -DCONFIG_ICMP_VOQ
+endif
+
+ifeq ($(CONFIG_RTW_WIFI_HAL), y)
+#EXTRA_CFLAGS += -DCONFIG_RTW_WIFI_HAL_DEBUG
+EXTRA_CFLAGS += -DCONFIG_RTW_WIFI_HAL
+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVEDNOR_LLSTATS
+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUI
+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVEDNOR_RSSIMONITOR
+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVENDOR_WIFI_LOGGER
+endif
+
 ifeq ($(CONFIG_MP_VHT_HW_TX_MODE), y)
 EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE
 ifeq ($(CONFIG_PLATFORM_I386_PC), y)
@@ -1084,17 +1230,26 @@ EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
 EXTRA_CFLAGS += -DRTW_VENDOR_EXT_SUPPORT
 EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
 ARCH ?= arm
-# for ubuntu environment
-#CROSS_COMPILE ?=
-#KVER := $(shell uname -r)
-#KSRC := /lib/modules/$(KVER)/build
-#MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/
-#INSTALL_PREFIX :=
+
 CROSS_COMPILE := /mnt/newdisk/android_sdk/nvidia_tk1/android_L/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
 KSRC :=/mnt/newdisk/android_sdk/nvidia_tk1/android_L/out/target/product/shieldtablet/obj/KERNEL/
 MODULE_NAME = wlan
 endif
 
+ifeq ($(CONFIG_PLATFORM_NV_TK1_UBUNTU), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_NV_TK1
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+
+ARCH ?= arm
+
+CROSS_COMPILE ?=
+KVER := $(shell uname -r)
+KSRC := /lib/modules/$(KVER)/build
+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/
+INSTALL_PREFIX :=
+endif
+
 ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM702X), y)
 EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ACTIONS_ATM702X
 #ARCH := arm
@@ -1174,8 +1329,12 @@ endif
 ifeq ($(CONFIG_PLATFORM_MSTAR), y)
 EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
 EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
-EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_USE_USB_BUFFER_ALLOC_TX -DCONFIG_FIX_NR_BULKIN_BUFFER
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR
 EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR_HIGH
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -DCONFIG_FIX_NR_BULKIN_BUFFER
+endif
 ARCH:=arm
 CROSS_COMPILE:= /usr/src/bin/arm-none-linux-gnueabi-
 KVER:= 3.1.10
@@ -1476,17 +1635,6 @@ KVER:= 2.6.31.6
 KSRC:= ../code/linux-2.6.31.6-2020/
 endif
 
-#Add setting for MN10300
-ifeq ($(CONFIG_PLATFORM_MN10300), y)
-EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MN10300
-ARCH := mn10300
-CROSS_COMPILE := mn10300-linux-
-KVER := 2.6.32.2
-KSRC := /home/winuser/work/Plat_sLD2T_V3010/usr/src/linux-2.6.32.2
-INSTALL_PREFIX :=
-endif
-
-
 ifeq ($(CONFIG_PLATFORM_ARM_SUNxI), y)
 EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
 EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUNxI
@@ -1640,10 +1788,9 @@ endif
 
 ifeq ($(CONFIG_PLATFORM_ARM_RTD299X), y)
 EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
-EXTRA_CFLAGS += -DUSB_XMITBUF_ALIGN_SZ=1024 -DUSB_PACKET_OFFSET_SZ=0
 EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
-ifeq ($(CONFIG_ANDROID), y)
 EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+ifeq ($(CONFIG_ANDROID), y)
 # Enable this for Android 5.0
 EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
 endif
@@ -1651,6 +1798,32 @@ endif
 INSTALL_PREFIX :=
 endif
 
+ifeq ($(CONFIG_PLATFORM_ARM_RTD299X_LG), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DRTW_P2P_GROUP_INTERFACE=1
+EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3
+#EXTRA_CFLAGS += -DCONFIG_FIX_HWPORT
+EXTRA_CFLAGS += -DLGE_PRIVATE
+EXTRA_CFLAGS += -DPURE_SUPPLICANT
+EXTRA_CFLAGS += -DCONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP -DCONFIG_RTW_IOCTL_SET_COUNTRY
+EXTRA_CFLAGS += -DDBG_RX_DFRAME_RAW_DATA
+EXTRA_CFLAGS += -DRTW_REDUCE_SCAN_SWITCH_CH_TIME
+ARCH ?= arm
+KVER ?=
+
+ifneq ($(PLATFORM), WEBOS)
+$(info PLATFORM is empty)
+CROSS_COMPILE ?= /mnt/newdisk/LGE/arm-lg115x-linux-gnueabi-4.8-2016.03-x86_64/bin/arm-lg115x-linux-gnueabi-
+KSRC ?= /mnt/newdisk/LGE/linux-rockhopper_k3lp_drd4tv_423
+endif
+
+CROSS_COMPILE ?=
+KSRC ?= $(LINUX_SRC)
+INSTALL_PREFIX ?=
+endif
+
 ifeq ($(CONFIG_PLATFORM_HISILICON), y)
 EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_HISILICON
 ifeq ($(SUPPORT_CONCURRENT),y)
@@ -1667,6 +1840,41 @@ ifeq ($(KSRC),)
 endif
 endif
 
+ifeq ($(CONFIG_PLATFORM_HISILICON_HI3798), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON_HI3798
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211
+EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT
+# default setting for Android 5.x and later
+#EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+# If system could power on and recognize Wi-Fi SDIO automatically,
+# platfrom operations are not necessary.
+#ifeq ($(CONFIG_SDIO_HCI), y)
+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+#_PLATFORM_FILES += platform/platform_hisilicon_hi3798_sdio.o
+#EXTRA_CFLAGS += -DCONFIG_HISI_SDIO_ID=1
+#endif
+
+ARCH ?= arm
+CROSS_COMPILE ?= /HiSTBAndroidV600R003C00SPC021_git_0512/device/hisilicon/bigfish/sdk/tools/linux/toolchains/arm-histbv310-linux/bin/arm-histbv310-linux-
+ifndef KSRC
+KSRC := /HiSTBAndroidV600R003C00SPC021_git_0512/device/hisilicon/bigfish/sdk/source/kernel/linux-3.18.y
+KSRC += O=/HiSTBAndroidV600R003C00SPC021_git_0512/out/target/product/Hi3798MV200/obj/KERNEL_OBJ
+endif
+
+ifeq ($(CONFIG_RTL8822B), y)
+ifeq ($(CONFIG_SDIO_HCI), y)
+CONFIG_RTL8822BS ?= m
+USER_MODULE_NAME := rtl8822bs
+endif
+endif
+
+endif
+
 # Platform setting
 ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_6820), y)
 ifeq ($(CONFIG_ANDROID_2X), y)
@@ -1720,7 +1928,6 @@ EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
 EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
 # default setting for Android 4.1, 4.2
 EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
-EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3
 EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
 #EXTRA_CFLAGS +=  -DCONFIG_QOS_OPTIMIZATION
 EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION
@@ -1746,6 +1953,26 @@ MODULE_NAME := 8192eu
 
 endif
 
+ifeq ($(CONFIG_PLATFORM_RTK119X_AM), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_RTK119X_AM
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE -DCONFIG_FULL_CH_IN_P2P_HANDSHAKE
+EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+endif
+
+ARCH := arm
+
+#CROSS_COMPILE := arm-linux-gnueabihf-
+KVER  := 3.10.24
+#KSRC :=
+CROSS_COMPILE :=
+endif
+
 ifeq ($(CONFIG_PLATFORM_RTK129X), y)
 EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
 EXTRA_CFLAGS += -DRTK_129X_PLATFORM
@@ -1782,6 +2009,22 @@ CROSS_COMPILE := /home/android_sdk/DHC/trunk-6.0.0_r1-QA160627/phoenix/toolchain
 KSRC := /home/android_sdk/DHC/trunk-6.0.0_r1-QA160627/linux-kernel
 endif
 
+ifeq ($(CONFIG_PLATFORM_RTK390X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_RTK390X
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_RTW_NETIF_SG
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+endif
+
+ARCH:=rlx
+
+CROSS_COMPILE:=mips-linux-
+KSRC:= /home/realtek/share/Develop/IPCAM_SDK/RealSil/rts3901_sdk_v1.2_vanilla/linux-3.10
+
+endif
+
 ifeq ($(CONFIG_PLATFORM_NOVATEK_NT72668), y)
 EXTRA_CFLAGS += -DCONFIG_PLATFORM_NOVATEK_NT72668
 EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
@@ -1815,6 +2058,77 @@ CROSS_COMPILE:= $(DIR_LINUX)/../toolchain/rsdk-1.5.5-5281-EB-2.6.30-0.9.30.3-110
 KSRC := $(DIR_LINUX)
 endif
 
+ifeq ($(CONFIG_PLATFORM_AML_S905), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_AML_S905
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -fno-pic
+# default setting for Android
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211
+EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT
+# default setting for Android 5.x and later
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_aml_s905_sdio.o
+endif
+
+ARCH ?= arm64
+CROSS_COMPILE ?= /4.4_S905L_8822bs_compile/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux/bin/aarch64-linux-gnu-
+ifndef KSRC
+KSRC := /4.4_S905L_8822bs_compile/common
+# To locate output files in a separate directory.
+KSRC += O=/4.4_S905L_8822bs_compile/KERNEL_OBJ
+endif
+
+ifeq ($(CONFIG_RTL8822B), y)
+ifeq ($(CONFIG_SDIO_HCI), y)
+CONFIG_RTL8822BS ?= m
+USER_MODULE_NAME := 8822bs
+endif
+endif
+
+endif
+
+ifeq ($(CONFIG_PLATFORM_ZTE_ZX296716), y)
+EXTRA_CFLAGS += -Wno-error=date-time
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ZTE_ZX296716
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211
+EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT
+# default setting for Android 5.x and later
+#EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+# mark this temporarily
+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+#_PLATFORM_FILES += platform/platform_zte_zx296716_sdio.o
+endif
+
+ARCH ?= arm64
+CROSS_COMPILE ?=
+KSRC ?=
+
+ifeq ($(CONFIG_RTL8822B), y)
+ifeq ($(CONFIG_SDIO_HCI), y)
+CONFIG_RTL8822BS ?= m
+USER_MODULE_NAME := 8822bs
+endif
+endif
+
+endif
+
+########### CUSTOMER ################################
+ifeq ($(CONFIG_CUSTOMER_HUAWEI_GENERAL), y)
+CONFIG_CUSTOMER_HUAWEI = y
+endif
+
+ifeq ($(CONFIG_CUSTOMER_HUAWEI), y)
+EXTRA_CFLAGS += -DCONFIG_HUAWEI_PROC
+endif
+
 ifeq ($(CONFIG_MULTIDRV), y)
 
 ifeq ($(CONFIG_SDIO_HCI), y)
@@ -1839,6 +2153,19 @@ endif
 
 ifneq ($(KERNELRELEASE),)
 
+########### this part for *.mk ############################
+include $(srctree)/$(src)/hal/phydm/phydm.mk
+
+########### HAL_RTL8822B #################################
+ifeq ($(CONFIG_RTL8822B), y)
+include $(srctree)/$(src)/rtl8822b.mk
+endif
+
+########### HAL_RTL8821C #################################
+ifeq ($(CONFIG_RTL8821C), y)
+include $(srctree)/$(src)/rtl8821c.mk
+endif
+
 rtk_core :=	core/rtw_cmd.o \
 		core/rtw_security.o \
 		core/rtw_debug.o \
@@ -1853,11 +2180,16 @@ rtk_core :=	core/rtw_cmd.o \
 		core/rtw_vht.o \
 		core/rtw_pwrctrl.o \
 		core/rtw_rf.o \
+		core/rtw_chplan.o \
 		core/rtw_recv.o \
 		core/rtw_sta_mgt.o \
 		core/rtw_ap.o \
+		core/mesh/rtw_mesh.o \
+		core/mesh/rtw_mesh_pathtbl.o \
+		core/mesh/rtw_mesh_hwmp.o \
 		core/rtw_xmit.o	\
 		core/rtw_p2p.o \
+		core/rtw_rson.o \
 		core/rtw_tdls.o \
 		core/rtw_br_ext.o \
 		core/rtw_iol.o \
@@ -1866,6 +2198,8 @@ rtk_core :=	core/rtw_cmd.o \
 		core/rtw_btcoex.o \
 		core/rtw_beamforming.o \
 		core/rtw_odm.o \
+		core/rtw_rm.o \
+		core/rtw_rm_fsm.o \
 		core/efuse/rtw_efuse.o 
 
 ifeq ($(CONFIG_SDIO_HCI), y)
@@ -1881,7 +2215,8 @@ $(MODULE_NAME)-$(CONFIG_WAPI_SUPPORT) += core/rtw_wapi.o	\
 
 $(MODULE_NAME)-y += $(_OS_INTFS_FILES)
 $(MODULE_NAME)-y += $(_HAL_INTFS_FILES)
-$(MODULE_NAME)-y += $(_OUTSRC_FILES)
+$(MODULE_NAME)-y += $(_PHYDM_FILES)
+$(MODULE_NAME)-y += $(_BTC_FILES)
 $(MODULE_NAME)-y += $(_PLATFORM_FILES)
 
 $(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o
@@ -1959,7 +2294,7 @@ clean:
 	cd hal ; rm -fr */*/*.mod.c */*/*.mod */*/*.o */*/.*.cmd */*/*.ko
 	cd hal ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko
 	cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
-	cd core/efuse ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd core ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko
 	cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
 	cd os_dep/linux ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
 	cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 515 - 209
core/efuse/rtw_efuse.c


+ 4097 - 0
core/mesh/rtw_mesh.c

@@ -0,0 +1,4097 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+#define _RTW_MESH_C_
+
+#ifdef CONFIG_RTW_MESH
+#include <drv_types.h>
+
+const char *_rtw_mesh_plink_str[] = {
+	"UNKNOWN",
+	"LISTEN",
+	"OPN_SNT",
+	"OPN_RCVD",
+	"CNF_RCVD",
+	"ESTAB",
+	"HOLDING",
+	"BLOCKED",
+};
+
+const char *_rtw_mesh_ps_str[] = {
+	"UNKNOWN",
+	"ACTIVE",
+	"LSLEEP",
+	"DSLEEP",
+};
+
+const char *_action_self_protected_str[] = {
+	"ACT_SELF_PROTECTED_RSVD",
+	"MESH_OPEN",
+	"MESH_CONF",
+	"MESH_CLOSE",
+	"MESH_GK_INFORM",
+	"MESH_GK_ACK",
+};
+
+inline u8 *rtw_set_ie_mesh_id(u8 *buf, u32 *buf_len, const char *mesh_id, u8 id_len)
+{
+	return rtw_set_ie(buf, WLAN_EID_MESH_ID, id_len, mesh_id, buf_len);
+}
+
+inline u8 *rtw_set_ie_mesh_config(u8 *buf, u32 *buf_len
+	, u8 path_sel_proto, u8 path_sel_metric, u8 congest_ctl_mode, u8 sync_method, u8 auth_proto
+	, u8 num_of_peerings, bool cto_mgate, bool cto_as
+	, bool accept_peerings, bool mcca_sup, bool mcca_en, bool forwarding
+	, bool mbca_en, bool tbtt_adj, bool ps_level)
+{
+
+	u8 conf[7] = {0};
+
+	SET_MESH_CONF_ELE_PATH_SEL_PROTO_ID(conf, path_sel_proto);
+	SET_MESH_CONF_ELE_PATH_SEL_METRIC_ID(conf, path_sel_metric);
+	SET_MESH_CONF_ELE_CONGEST_CTRL_MODE_ID(conf, congest_ctl_mode);
+	SET_MESH_CONF_ELE_SYNC_METHOD_ID(conf, sync_method);
+	SET_MESH_CONF_ELE_AUTH_PROTO_ID(conf, auth_proto);
+
+	SET_MESH_CONF_ELE_CTO_MGATE(conf, cto_mgate);
+	SET_MESH_CONF_ELE_NUM_OF_PEERINGS(conf, num_of_peerings);
+	SET_MESH_CONF_ELE_CTO_AS(conf, cto_as);
+
+	SET_MESH_CONF_ELE_ACCEPT_PEERINGS(conf, accept_peerings);
+	SET_MESH_CONF_ELE_MCCA_SUP(conf, mcca_sup);
+	SET_MESH_CONF_ELE_MCCA_EN(conf, mcca_en);
+	SET_MESH_CONF_ELE_FORWARDING(conf, forwarding);
+	SET_MESH_CONF_ELE_MBCA_EN(conf, mbca_en);
+	SET_MESH_CONF_ELE_TBTT_ADJ(conf, tbtt_adj);
+	SET_MESH_CONF_ELE_PS_LEVEL(conf, ps_level);
+
+	return rtw_set_ie(buf, WLAN_EID_MESH_CONFIG, 7, conf, buf_len);
+}
+
+inline u8 *rtw_set_ie_mpm(u8 *buf, u32 *buf_len
+	, u8 proto_id, u16 llid, u16 *plid, u16 *reason, u8 *chosen_pmk)
+{
+	u8 data[24] = {0};
+	u8 *pos = data;
+
+	RTW_PUT_LE16(pos, proto_id);
+	pos += 2;
+
+	RTW_PUT_LE16(pos, llid);
+	pos += 2;
+
+	if (plid) {
+		RTW_PUT_LE16(pos, *plid);
+		pos += 2;
+	}
+
+	if (reason) {
+		RTW_PUT_LE16(pos, *reason);
+		pos += 2;
+	}
+
+	if (chosen_pmk) {
+		_rtw_memcpy(pos, chosen_pmk, 16);
+		pos += 16;
+	}
+
+	return rtw_set_ie(buf, WLAN_EID_MPM, pos - data, data, buf_len);
+}
+
+bool rtw_bss_is_forwarding(WLAN_BSSID_EX *bss)
+{
+	u8 *ie;
+	int ie_len;
+	bool ret = 0;
+
+	ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,
+			BSS_EX_TLV_IES_LEN(bss));
+	if (!ie || ie_len != 7)
+		goto exit;
+
+	ret = GET_MESH_CONF_ELE_FORWARDING(ie + 2);
+
+exit:
+	return ret;
+}
+
+bool rtw_bss_is_cto_mgate(WLAN_BSSID_EX *bss)
+{
+	u8 *ie;
+	int ie_len;
+	bool ret = 0;
+
+	ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,
+			BSS_EX_TLV_IES_LEN(bss));
+	if (!ie || ie_len != 7)
+		goto exit;
+
+	ret = GET_MESH_CONF_ELE_CTO_MGATE(ie + 2);
+
+exit:
+	return ret;
+}
+
+int rtw_bss_is_same_mbss(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b)
+{
+	int ret = 0;
+	u8 *a_mconf_ie, *b_mconf_ie;
+	sint a_mconf_ie_len, b_mconf_ie_len;
+
+	if (a->InfrastructureMode != Ndis802_11_mesh)
+		goto exit;
+	a_mconf_ie = rtw_get_ie(BSS_EX_TLV_IES(a), WLAN_EID_MESH_CONFIG, &a_mconf_ie_len, BSS_EX_TLV_IES_LEN(a));
+	if (!a_mconf_ie || a_mconf_ie_len != 7)
+		goto exit;
+	if (b->InfrastructureMode != Ndis802_11_mesh)
+		goto exit;
+	b_mconf_ie = rtw_get_ie(BSS_EX_TLV_IES(b), WLAN_EID_MESH_CONFIG, &b_mconf_ie_len, BSS_EX_TLV_IES_LEN(b));
+	if (!b_mconf_ie || b_mconf_ie_len != 7)
+		goto exit;
+
+	if (a->mesh_id.SsidLength != b->mesh_id.SsidLength
+		|| _rtw_memcmp(a->mesh_id.Ssid, b->mesh_id.Ssid, a->mesh_id.SsidLength) == _FALSE)
+		goto exit;
+
+	if (_rtw_memcmp(a_mconf_ie + 2, b_mconf_ie + 2, 5) == _FALSE)
+		goto exit;
+
+	ret = 1;
+
+exit:
+	return ret;
+}
+
+int rtw_bss_is_candidate_mesh_peer(WLAN_BSSID_EX *self, WLAN_BSSID_EX *target, u8 ch, u8 add_peer)
+{
+	int ret = 0;
+	u8 *mconf_ie;
+	sint mconf_ie_len;
+	int i, j;
+
+	if (!rtw_bss_is_same_mbss(self, target))
+		goto exit;
+
+	if (ch && self->Configuration.DSConfig != target->Configuration.DSConfig)
+		goto exit;
+
+	if (add_peer) {
+		/* Accept additional mesh peerings */
+		mconf_ie = rtw_get_ie(BSS_EX_TLV_IES(target), WLAN_EID_MESH_CONFIG, &mconf_ie_len, BSS_EX_TLV_IES_LEN(target));
+		if (!mconf_ie || mconf_ie_len != 7)
+			goto exit;
+		if (GET_MESH_CONF_ELE_ACCEPT_PEERINGS(mconf_ie + 2) == 0)
+			goto exit;
+	}
+
+	/* BSSBasicRateSet */
+	for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+		if (target->SupportedRates[i] == 0)
+			break;	
+		if (target->SupportedRates[i] & 0x80) {
+			u8 match = 0;
+
+			if (!ch) {
+				/* off-channel, check target with our hardcode capability */
+				if (target->Configuration.DSConfig > 14)
+					match = rtw_is_basic_rate_ofdm(target->SupportedRates[i]);
+				else
+					match = rtw_is_basic_rate_mix(target->SupportedRates[i]);
+			} else { 
+				for (j = 0; j < NDIS_802_11_LENGTH_RATES_EX; j++) {
+					if (self->SupportedRates[j] == 0)
+						break;
+					if (self->SupportedRates[j] == target->SupportedRates[i]) {
+						match = 1;
+						break;
+					}
+				}
+			}
+			if (!match)
+				goto exit;
+		}
+	}
+
+
+	/* BSSBasicMCSSet */
+
+	/* 802.1X connected to AS ? */
+
+	ret = 1;
+
+exit:
+	return ret;
+}
+
+void rtw_mesh_bss_peering_status(WLAN_BSSID_EX *bss, u8 *nop, u8 *accept)
+{
+	u8 *ie;
+	int ie_len;
+
+	if (nop)
+		*nop = 0;
+	if (accept)
+		*accept = 0;
+
+	ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,
+			BSS_EX_TLV_IES_LEN(bss));
+	if (!ie || ie_len != 7)
+		goto exit;
+
+	if (nop)
+		*nop = GET_MESH_CONF_ELE_NUM_OF_PEERINGS(ie + 2);
+	if (accept)
+		*accept = GET_MESH_CONF_ELE_ACCEPT_PEERINGS(ie + 2);
+
+exit:
+	return;
+}
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+void rtw_mesh_update_scanned_acnode_status(_adapter *adapter, struct wlan_network *scanned)
+{
+	bool acnode;
+	u8 nop, accept;
+
+	rtw_mesh_bss_peering_status(&scanned->network, &nop, &accept);
+
+	acnode = !nop && accept;
+
+	if (acnode && scanned->acnode_stime == 0) {
+		scanned->acnode_stime = rtw_get_current_time();
+		if (scanned->acnode_stime == 0)
+			scanned->acnode_stime++;
+	} else if (!acnode) {
+		scanned->acnode_stime = 0;
+		scanned->acnode_notify_etime = 0;
+	}
+}
+
+bool rtw_mesh_scanned_is_acnode_confirmed(_adapter *adapter, struct wlan_network *scanned)
+{
+	return scanned->acnode_stime
+			&& rtw_get_passing_time_ms(scanned->acnode_stime)
+				> adapter->mesh_cfg.peer_sel_policy.acnode_conf_timeout_ms;
+}
+
+static bool rtw_mesh_scanned_is_acnode_allow_notify(_adapter *adapter, struct wlan_network *scanned)
+{
+	return scanned->acnode_notify_etime
+			&& rtw_time_after(scanned->acnode_notify_etime, rtw_get_current_time());
+}
+
+bool rtw_mesh_acnode_prevent_allow_sacrifice(_adapter *adapter)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	bool allow = 0;
+
+	if (!mcfg->peer_sel_policy.acnode_prevent
+		|| mcfg->max_peer_links <= 1
+		|| stapriv->asoc_list_cnt < mcfg->max_peer_links)
+		goto exit;
+
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	if (rtw_mesh_cto_mgate_required(adapter))
+		goto exit;
+#endif
+
+	allow = 1;
+
+exit:
+	return allow;
+}
+
+static bool rtw_mesh_acnode_candidate_exist(_adapter *adapter)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	_queue *queue = &(mlme->scanned_queue);
+	_list *head, *list;
+	_irqL irqL;
+	struct wlan_network *scanned = NULL;
+	struct sta_info *sta = NULL;
+	bool need = 0;
+
+	_enter_critical_bh(&(mlme->scanned_queue.lock), &irqL);
+
+	head = get_list_head(queue);
+	list = get_next(head);
+	while (!rtw_end_of_queue_search(head, list)) {
+		scanned = LIST_CONTAINOR(list, struct wlan_network, list);
+		list = get_next(list);
+
+		if (rtw_get_passing_time_ms(scanned->last_scanned) < mcfg->peer_sel_policy.scanr_exp_ms
+			&& rtw_mesh_scanned_is_acnode_confirmed(adapter, scanned)
+			&& (!mcfg->rssi_threshold || mcfg->rssi_threshold <= scanned->network.Rssi)
+			#if CONFIG_RTW_MACADDR_ACL
+			&& rtw_access_ctrl(adapter, scanned->network.MacAddress) == _TRUE
+			#endif
+			&& rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &scanned->network, 1, 1)
+			#if CONFIG_RTW_MESH_PEER_BLACKLIST
+			&& !rtw_mesh_peer_blacklist_search(adapter, scanned->network.MacAddress)
+			#endif
+			#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+			&& rtw_mesh_cto_mgate_network_filter(adapter, scanned)
+			#endif
+		) {
+			need = 1;
+			break;
+		}
+	}
+
+	_exit_critical_bh(&(mlme->scanned_queue.lock), &irqL);
+
+exit:
+	return need;
+}
+
+static int rtw_mesh_acnode_prevent_sacrifice_chk(_adapter *adapter, struct sta_info **sac, struct sta_info *com)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	int updated = 0;
+
+	/*
+	* TODO: compare next_hop reference cnt of forwarding info
+	* don't sacrifice working next_hop or choose sta with least cnt
+	*/
+
+	if (*sac == NULL) {
+		updated = 1;
+		goto exit;
+	}
+
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	if (mcfg->peer_sel_policy.cto_mgate_require
+		&& !mcfg->dot11MeshGateAnnouncementProtocol
+	) {
+		if (IS_CTO_MGATE_CONF_TIMEOUT(com->plink)) {
+			if (!IS_CTO_MGATE_CONF_TIMEOUT((*sac)->plink)) {
+				/* blacklist > not blacklist */
+				updated = 1;
+				goto exit;
+			}
+		} else if (!IS_CTO_MGATE_CONF_DISABLED(com->plink)) {
+			if (IS_CTO_MGATE_CONF_DISABLED((*sac)->plink)) {
+				/* confirming > disabled */
+				updated = 1;
+				goto exit;
+			}
+		}
+	}
+#endif
+
+exit:
+	if (updated)
+		*sac = com;
+
+	return updated;
+}
+
+struct sta_info *_rtw_mesh_acnode_prevent_pick_sacrifice(_adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	_list *head, *list;
+	struct sta_info *sta, *sacrifice = NULL;
+	u8 nop;
+
+	head = &stapriv->asoc_list;
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		sta = LIST_CONTAINOR(list, struct sta_info, asoc_list);
+		list = get_next(list);
+
+		if (!sta->plink || !sta->plink->scanned) {
+			rtw_warn_on(1);
+			continue;
+		}
+
+		rtw_mesh_bss_peering_status(&sta->plink->scanned->network, &nop, NULL);
+		if (nop < 2)
+			continue;
+
+		rtw_mesh_acnode_prevent_sacrifice_chk(adapter, &sacrifice, sta);
+	}
+
+	return sacrifice;
+}
+
+struct sta_info *rtw_mesh_acnode_prevent_pick_sacrifice(_adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct sta_info *sacrifice = NULL;
+
+	enter_critical_bh(&stapriv->asoc_list_lock);
+
+	sacrifice = _rtw_mesh_acnode_prevent_pick_sacrifice(adapter);
+
+	exit_critical_bh(&stapriv->asoc_list_lock);
+
+	return sacrifice;
+}
+
+static void rtw_mesh_acnode_rsvd_chk(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	u8 acnode_rsvd = 0;
+
+	if (rtw_mesh_acnode_prevent_allow_sacrifice(adapter)
+		&& rtw_mesh_acnode_prevent_pick_sacrifice(adapter)
+		&& rtw_mesh_acnode_candidate_exist(adapter))
+		acnode_rsvd = 1;
+
+	if (plink_ctl->acnode_rsvd != acnode_rsvd) {
+		plink_ctl->acnode_rsvd = acnode_rsvd;
+		RTW_INFO(FUNC_ADPT_FMT" acnode_rsvd = %d\n", FUNC_ADPT_ARG(adapter), plink_ctl->acnode_rsvd);
+		update_beacon(adapter, WLAN_EID_MESH_CONFIG, NULL, 1);
+	}
+}
+
+static void rtw_mesh_acnode_set_notify_etime(_adapter *adapter, u8 *rframe_whdr)
+{
+	if (adapter->mesh_info.plink_ctl.acnode_rsvd) {
+		struct wlan_network *scanned = rtw_find_network(&adapter->mlmepriv.scanned_queue, get_addr2_ptr(rframe_whdr));
+
+		if (rtw_mesh_scanned_is_acnode_confirmed(adapter, scanned)) {
+			scanned->acnode_notify_etime = rtw_get_current_time()
+				+ rtw_ms_to_systime(adapter->mesh_cfg.peer_sel_policy.acnode_notify_timeout_ms);
+			if (scanned->acnode_notify_etime == 0)
+				scanned->acnode_notify_etime++;
+		}
+	}
+}
+
+void dump_mesh_acnode_prevent_settings(void *sel, _adapter *adapter)
+{
+	struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;
+
+	RTW_PRINT_SEL(sel, "%-6s %-12s %-14s\n"
+		, "enable", "conf_timeout", "nofity_timeout");
+	RTW_PRINT_SEL(sel, "%6u %12u %14u\n"
+		, peer_sel_policy->acnode_prevent
+		, peer_sel_policy->acnode_conf_timeout_ms
+		, peer_sel_policy->acnode_notify_timeout_ms);
+}
+#endif /* CONFIG_RTW_MESH_ACNODE_PREVENT */
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+int rtw_mesh_peer_blacklist_add(_adapter *adapter, const u8 *addr)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	return rtw_blacklist_add(&plink_ctl->peer_blacklist, addr
+		, mcfg->peer_sel_policy.peer_blacklist_timeout_ms);
+}
+
+int rtw_mesh_peer_blacklist_del(_adapter *adapter, const u8 *addr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	return rtw_blacklist_del(&plink_ctl->peer_blacklist, addr);
+}
+
+int rtw_mesh_peer_blacklist_search(_adapter *adapter, const u8 *addr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	return rtw_blacklist_search(&plink_ctl->peer_blacklist, addr);
+}
+
+void rtw_mesh_peer_blacklist_flush(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	rtw_blacklist_flush(&plink_ctl->peer_blacklist);
+}
+
+void dump_mesh_peer_blacklist(void *sel, _adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	dump_blacklist(sel, &plink_ctl->peer_blacklist, "blacklist");
+}
+
+void dump_mesh_peer_blacklist_settings(void *sel, _adapter *adapter)
+{
+	struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;
+
+	RTW_PRINT_SEL(sel, "%-12s %-17s\n"
+		, "conf_timeout", "blacklist_timeout");
+	RTW_PRINT_SEL(sel, "%12u %17u\n"
+		, peer_sel_policy->peer_conf_timeout_ms
+		, peer_sel_policy->peer_blacklist_timeout_ms);
+}
+#endif /* CONFIG_RTW_MESH_PEER_BLACKLIST */
+
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+u8 rtw_mesh_cto_mgate_required(_adapter *adapter)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+
+	return mcfg->peer_sel_policy.cto_mgate_require
+		&& !rtw_bss_is_cto_mgate(&(mlmeext->mlmext_info.network));
+}
+
+u8 rtw_mesh_cto_mgate_network_filter(_adapter *adapter, struct wlan_network *scanned)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+
+	return !rtw_mesh_cto_mgate_required(adapter)
+			|| (rtw_bss_is_cto_mgate(&scanned->network)
+				&& !rtw_mesh_cto_mgate_blacklist_search(adapter, scanned->network.MacAddress));
+}
+
+int rtw_mesh_cto_mgate_blacklist_add(_adapter *adapter, const u8 *addr)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	return rtw_blacklist_add(&plink_ctl->cto_mgate_blacklist, addr
+		, mcfg->peer_sel_policy.cto_mgate_blacklist_timeout_ms);
+}
+
+int rtw_mesh_cto_mgate_blacklist_del(_adapter *adapter, const u8 *addr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	return rtw_blacklist_del(&plink_ctl->cto_mgate_blacklist, addr);
+}
+
+int rtw_mesh_cto_mgate_blacklist_search(_adapter *adapter, const u8 *addr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	return rtw_blacklist_search(&plink_ctl->cto_mgate_blacklist, addr);
+}
+
+void rtw_mesh_cto_mgate_blacklist_flush(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	rtw_blacklist_flush(&plink_ctl->cto_mgate_blacklist);
+}
+
+void dump_mesh_cto_mgate_blacklist(void *sel, _adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	dump_blacklist(sel, &plink_ctl->cto_mgate_blacklist, "blacklist");
+}
+
+void dump_mesh_cto_mgate_blacklist_settings(void *sel, _adapter *adapter)
+{
+	struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;
+
+	RTW_PRINT_SEL(sel, "%-12s %-17s\n"
+		, "conf_timeout", "blacklist_timeout");
+	RTW_PRINT_SEL(sel, "%12u %17u\n"
+		, peer_sel_policy->cto_mgate_conf_timeout_ms
+		, peer_sel_policy->cto_mgate_blacklist_timeout_ms);
+}
+
+static void rtw_mesh_cto_mgate_blacklist_chk(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	_queue *blist = &plink_ctl->cto_mgate_blacklist;
+	_list *list, *head;
+	struct blacklist_ent *ent = NULL;
+	struct wlan_network *scanned = NULL;
+
+	enter_critical_bh(&blist->lock);
+	head = &blist->queue;
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		ent = LIST_CONTAINOR(list, struct blacklist_ent, list);
+		list = get_next(list);
+
+		if (rtw_time_after(rtw_get_current_time(), ent->exp_time)) {
+			rtw_list_delete(&ent->list);
+			rtw_mfree(ent, sizeof(struct blacklist_ent));
+			continue;
+		}
+
+		scanned = rtw_find_network(&adapter->mlmepriv.scanned_queue, ent->addr);
+		if (!scanned)
+			continue;
+
+		if (rtw_bss_is_forwarding(&scanned->network)) {
+			rtw_list_delete(&ent->list);
+			rtw_mfree(ent, sizeof(struct blacklist_ent));
+		}
+	}
+
+	exit_critical_bh(&blist->lock);
+}
+#endif /* CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST */
+
+void rtw_chk_candidate_peer_notify(_adapter *adapter, struct wlan_network *scanned)
+{
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	bool acnode = 0;
+
+	if (IS_CH_WAITING(rfctl) && !IS_UNDER_CAC(rfctl))
+		goto exit;
+
+	if (plink_ctl->num >= RTW_MESH_MAX_PEER_CANDIDATES)
+		goto exit;
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	if (plink_ctl->acnode_rsvd) {
+		acnode = rtw_mesh_scanned_is_acnode_confirmed(adapter, scanned);
+		if (acnode && !rtw_mesh_scanned_is_acnode_allow_notify(adapter, scanned))
+			goto exit;
+	}
+#endif
+
+	/* wpa_supplicant's auto peer will initiate peering when candidate peer is reported without max_peer_links consideration */
+	if (plink_ctl->num >= mcfg->max_peer_links + acnode ? 1 : 0)
+		goto exit;
+
+	if (rtw_get_passing_time_ms(scanned->last_scanned) >= mcfg->peer_sel_policy.scanr_exp_ms
+		|| (mcfg->rssi_threshold && mcfg->rssi_threshold > scanned->network.Rssi)
+		|| !rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &scanned->network, 1, 1)
+		#if CONFIG_RTW_MACADDR_ACL
+		|| rtw_access_ctrl(adapter, scanned->network.MacAddress) == _FALSE
+		#endif
+		|| rtw_mesh_plink_get(adapter, scanned->network.MacAddress)
+		#if CONFIG_RTW_MESH_PEER_BLACKLIST
+		|| rtw_mesh_peer_blacklist_search(adapter, scanned->network.MacAddress)
+		#endif
+		#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+		|| !rtw_mesh_cto_mgate_network_filter(adapter, scanned)
+		#endif
+	)
+		goto exit;
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	if (acnode) {
+		scanned->acnode_notify_etime = 0;
+		RTW_INFO(FUNC_ADPT_FMT" acnode "MAC_FMT"\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(scanned->network.MacAddress));
+	}
+#endif
+
+#ifdef CONFIG_IOCTL_CFG80211
+	rtw_cfg80211_notify_new_peer_candidate(adapter->rtw_wdev
+		, scanned->network.MacAddress
+		, BSS_EX_TLV_IES(&scanned->network)
+		, BSS_EX_TLV_IES_LEN(&scanned->network)
+		, GFP_ATOMIC
+	);
+#endif
+
+exit:
+	return;
+}
+
+void rtw_mesh_peer_status_chk(_adapter *adapter)
+{
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *plink;
+	_list *head, *list;
+	struct sta_info *sta = NULL;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	int stainfo_offset;
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	u8 cto_mgate, forwarding, mgate;
+#endif
+	u8 flush;
+	s8 flush_list[NUM_STA];
+	u8 flush_num = 0;
+	int i;
+
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	if (rtw_mesh_cto_mgate_required(adapter)) {
+		/* active scan on operating channel */
+		issue_probereq_ex(adapter, &adapter->mlmepriv.cur_network.network.mesh_id, NULL, 0, 0, 0, 0);
+	}
+#endif
+
+	enter_critical_bh(&(plink_ctl->lock));
+
+	/* check established peers */
+	enter_critical_bh(&stapriv->asoc_list_lock);
+
+	head = &stapriv->asoc_list;
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		sta = LIST_CONTAINOR(list, struct sta_info, asoc_list);
+		list = get_next(list);
+
+		if (!sta->plink || !sta->plink->scanned) {
+			rtw_warn_on(1);
+			continue;
+		}
+		plink = sta->plink;
+		flush = 0;
+
+		/* remove unsuitable peer */
+		if (!rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &plink->scanned->network, 1, 0)
+			#if CONFIG_RTW_MACADDR_ACL
+			|| rtw_access_ctrl(adapter, plink->addr) == _FALSE
+			#endif
+		) {
+			flush = 1;
+			goto flush_add;
+		}
+
+		#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+		cto_mgate = rtw_bss_is_cto_mgate(&(plink->scanned->network));
+		forwarding = rtw_bss_is_forwarding(&(plink->scanned->network));
+		mgate = rtw_mesh_gate_search(minfo->mesh_paths, sta->cmn.mac_addr);
+
+		/* CTO_MGATE required, remove peer without CTO_MGATE */
+		if (rtw_mesh_cto_mgate_required(adapter) && !cto_mgate) {
+			flush = 1;
+			goto flush_add;
+		}
+
+		/* cto_mgate_conf status update */
+		if (IS_CTO_MGATE_CONF_DISABLED(plink)) {
+			if (cto_mgate && !forwarding && !mgate)
+				SET_CTO_MGATE_CONF_END_TIME(plink, mcfg->peer_sel_policy.cto_mgate_conf_timeout_ms);
+			else
+				rtw_mesh_cto_mgate_blacklist_del(adapter, sta->cmn.mac_addr);
+		} else {
+			/* cto_mgate_conf ongoing */
+			if (cto_mgate && !forwarding && !mgate) {
+				if (IS_CTO_MGATE_CONF_TIMEOUT(plink)) {
+					rtw_mesh_cto_mgate_blacklist_add(adapter, sta->cmn.mac_addr);
+
+					/* CTO_MGATE required, remove peering can't achieve CTO_MGATE */
+					if (rtw_mesh_cto_mgate_required(adapter)) {
+						flush = 1;
+						goto flush_add;
+					}	
+				}
+			} else {
+				SET_CTO_MGATE_CONF_DISABLED(plink);
+				rtw_mesh_cto_mgate_blacklist_del(adapter, sta->cmn.mac_addr);
+			}
+		}
+		#endif /* CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST */
+
+flush_add:
+		if (flush) {
+			rtw_list_delete(&sta->asoc_list);
+			stapriv->asoc_list_cnt--;
+			STA_SET_MESH_PLINK(sta, NULL);
+
+			stainfo_offset = rtw_stainfo_offset(stapriv, sta);
+			if (stainfo_offset_valid(stainfo_offset))
+				flush_list[flush_num++] = stainfo_offset;
+			else
+				rtw_warn_on(1);
+		}
+	}
+
+	exit_critical_bh(&stapriv->asoc_list_lock);
+
+	/* check non-established peers */
+	for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {
+		plink = &plink_ctl->ent[i];
+		if (plink->valid != _TRUE || plink->plink_state == RTW_MESH_PLINK_ESTAB)
+			continue;
+
+		/* remove unsuitable peer */
+		if (!rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &plink->scanned->network, 1, 1)
+			#if CONFIG_RTW_MACADDR_ACL
+			|| rtw_access_ctrl(adapter, plink->addr) == _FALSE
+			#endif
+		) {
+			_rtw_mesh_expire_peer_ent(adapter, plink);
+			continue;
+		}
+
+		#if CONFIG_RTW_MESH_PEER_BLACKLIST
+		/* peer confirm check timeout, add to black list */
+		if (IS_PEER_CONF_TIMEOUT(plink)) {
+			rtw_mesh_peer_blacklist_add(adapter, plink->addr);
+			_rtw_mesh_expire_peer_ent(adapter, plink);
+		}
+		#endif
+	}
+
+	exit_critical_bh(&(plink_ctl->lock));
+
+	if (flush_num) {
+		u8 sta_addr[ETH_ALEN];
+		u8 updated = _FALSE;
+
+		for (i = 0; i < flush_num; i++) {
+			sta = rtw_get_stainfo_by_offset(stapriv, flush_list[i]);
+			_rtw_memcpy(sta_addr, sta->cmn.mac_addr, ETH_ALEN);
+
+			updated |= ap_free_sta(adapter, sta, _TRUE, WLAN_REASON_DEAUTH_LEAVING, _FALSE);
+			rtw_mesh_expire_peer(adapter, sta_addr);
+		}
+
+		associated_clients_update(adapter, updated, STA_INFO_UPDATE_ALL);
+	}
+
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	/* loop cto_mgate_blacklist to remove ent according to scan_r */
+	rtw_mesh_cto_mgate_blacklist_chk(adapter);
+#endif
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	rtw_mesh_acnode_rsvd_chk(adapter);
+#endif
+
+	return;
+}
+
+#if CONFIG_RTW_MESH_OFFCH_CAND
+static u8 rtw_mesh_offch_cto_mgate_required(_adapter *adapter)
+{
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	_queue *queue = &(mlme->scanned_queue);
+	_list *head, *pos;
+	struct wlan_network *scanned = NULL;
+	u8 ret = 0;
+
+	if (!rtw_mesh_cto_mgate_required(adapter))
+		goto exit;
+
+	enter_critical_bh(&(mlme->scanned_queue.lock));
+
+	head = get_list_head(queue);
+	pos = get_next(head);
+	while (!rtw_end_of_queue_search(head, pos)) {
+		scanned = LIST_CONTAINOR(pos, struct wlan_network, list);
+
+		if (rtw_get_passing_time_ms(scanned->last_scanned) < mcfg->peer_sel_policy.scanr_exp_ms
+			&& (!mcfg->rssi_threshold || mcfg->rssi_threshold <= scanned->network.Rssi)
+			#if CONFIG_RTW_MACADDR_ACL
+			&& rtw_access_ctrl(adapter, scanned->network.MacAddress) == _TRUE
+			#endif
+			&& rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &scanned->network, 1, 1)
+			&& rtw_bss_is_cto_mgate(&scanned->network)
+			#if CONFIG_RTW_MESH_PEER_BLACKLIST
+			&& !rtw_mesh_peer_blacklist_search(adapter, scanned->network.MacAddress)
+			#endif
+			&& !rtw_mesh_cto_mgate_blacklist_search(adapter, scanned->network.MacAddress)
+		)
+			break;
+
+		pos = get_next(pos);
+	}
+
+	if (rtw_end_of_queue_search(head, pos))
+		ret = 1;
+
+	exit_critical_bh(&(mlme->scanned_queue.lock));
+
+exit:
+	return ret;
+#else
+	return 0;
+#endif /* CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST */
+}
+
+u8 rtw_mesh_offch_candidate_accepted(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	u8 ret = 0;
+
+	if (!adapter->mesh_cfg.peer_sel_policy.offch_cand)
+		goto exit;
+
+	ret = MLME_IS_MESH(adapter) && MLME_IS_ASOC(adapter)
+		&& (!plink_ctl->num || rtw_mesh_offch_cto_mgate_required(adapter))
+		;
+
+#ifdef CONFIG_CONCURRENT_MODE
+	if (ret) {
+		struct mi_state mstate_no_self;
+
+		rtw_mi_status_no_self(adapter, &mstate_no_self);
+		if (MSTATE_STA_LD_NUM(&mstate_no_self))
+			ret = 0;
+	}
+#endif
+
+exit:
+	return ret;
+}
+
+/*
+ * this function is called under off channel candidate is required 
+ * the channel with maximum candidate count is selected
+*/
+u8 rtw_mesh_select_operating_ch(_adapter *adapter)
+{
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	_queue *queue = &(mlme->scanned_queue);
+	_list *head, *pos;
+	_irqL irqL;
+	struct wlan_network *scanned = NULL;
+	int i;
+	/* statistics for candidate accept peering */
+	u8 cand_ap_cnt[MAX_CHANNEL_NUM] = {0};
+	u8 max_cand_ap_ch = 0;
+	u8 max_cand_ap_cnt = 0;
+	/* statistics for candidate including not accept peering */
+	u8 cand_cnt[MAX_CHANNEL_NUM] = {0};
+	u8 max_cand_ch = 0;
+	u8 max_cand_cnt = 0;
+
+	_enter_critical_bh(&(mlme->scanned_queue.lock), &irqL);
+
+	head = get_list_head(queue);
+	pos = get_next(head);
+	while (!rtw_end_of_queue_search(head, pos)) {
+		scanned = LIST_CONTAINOR(pos, struct wlan_network, list);
+		pos = get_next(pos);
+
+		if (rtw_get_passing_time_ms(scanned->last_scanned) < mcfg->peer_sel_policy.scanr_exp_ms
+			&& (!mcfg->rssi_threshold || mcfg->rssi_threshold <= scanned->network.Rssi)
+			#if CONFIG_RTW_MACADDR_ACL
+			&& rtw_access_ctrl(adapter, scanned->network.MacAddress) == _TRUE
+			#endif
+			&& rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &scanned->network, 0, 0)
+			#if CONFIG_RTW_MESH_PEER_BLACKLIST
+			&& !rtw_mesh_peer_blacklist_search(adapter, scanned->network.MacAddress)
+			#endif
+			#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+			&& rtw_mesh_cto_mgate_network_filter(adapter, scanned)
+			#endif
+		) {
+			int ch_set_idx = rtw_chset_search_ch(rfctl->channel_set, scanned->network.Configuration.DSConfig);
+
+			if (ch_set_idx >= 0
+				&& !CH_IS_NON_OCP(&rfctl->channel_set[ch_set_idx])
+			) {
+				u8 nop, accept;
+
+				rtw_mesh_bss_peering_status(&scanned->network, &nop, &accept);
+				cand_cnt[ch_set_idx]++;
+				if (max_cand_cnt < cand_cnt[ch_set_idx]) {
+					max_cand_cnt = cand_cnt[ch_set_idx];
+					max_cand_ch = rfctl->channel_set[ch_set_idx].ChannelNum;
+				}
+				if (accept) {
+					cand_ap_cnt[ch_set_idx]++;
+					if (max_cand_ap_cnt < cand_ap_cnt[ch_set_idx]) {
+						max_cand_ap_cnt = cand_ap_cnt[ch_set_idx];
+						max_cand_ap_ch = rfctl->channel_set[ch_set_idx].ChannelNum;
+					}
+				}
+			}
+		}
+	}
+
+	_exit_critical_bh(&(mlme->scanned_queue.lock), &irqL);
+
+	return max_cand_ap_ch ? max_cand_ap_ch : max_cand_ch;
+}
+
+void dump_mesh_offch_cand_settings(void *sel, _adapter *adapter)
+{
+	struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;
+
+	RTW_PRINT_SEL(sel, "%-6s %-11s\n"
+		, "enable", "find_int_ms");
+	RTW_PRINT_SEL(sel, "%6u %11u\n"
+		, peer_sel_policy->offch_cand, peer_sel_policy->offch_find_int_ms);
+}
+#endif /* CONFIG_RTW_MESH_OFFCH_CAND */
+
+void dump_mesh_peer_sel_policy(void *sel, _adapter *adapter)
+{
+	struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;
+
+	RTW_PRINT_SEL(sel, "%-12s\n", "scanr_exp_ms");
+	RTW_PRINT_SEL(sel, "%12u\n", peer_sel_policy->scanr_exp_ms);
+}
+
+void dump_mesh_networks(void *sel, _adapter *adapter)
+{
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+#define NSTATE_TITLE_FMT_ACN " %-5s"
+#define NSTATE_VALUE_FMT_ACN " %5d"
+#define NSTATE_TITLE_ARG_ACN , "acn"
+#define NSTATE_VALUE_ARG_ACN , (acn_ms < 99999 ? acn_ms : 99999)
+#else
+#define NSTATE_TITLE_FMT_ACN ""
+#define NSTATE_VALUE_FMT_ACN ""
+#define NSTATE_TITLE_ARG_ACN
+#define NSTATE_VALUE_ARG_ACN
+#endif
+
+	struct mlme_priv *mlme = &(adapter->mlmepriv);
+	_queue *queue = &(mlme->scanned_queue);
+	struct wlan_network	*network;
+	_list *list, *head;
+	u8 same_mbss;
+	u8 candidate;
+	struct mesh_plink_ent *plink;
+	u8 blocked;
+	u8 established;
+	s32 age_ms;
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	s32 acn_ms;
+#endif
+	u8 *mesh_conf_ie;
+	sint mesh_conf_ie_len;
+	struct wlan_network **mesh_networks;
+	u8 mesh_network_cnt = 0;
+	int i;
+
+	mesh_networks = rtw_zvmalloc(mlme->max_bss_cnt * sizeof(struct wlan_network *));
+	if (!mesh_networks)
+		return;
+
+	enter_critical_bh(&queue->lock);
+	head = get_list_head(queue);
+	list = get_next(head);
+
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		network = LIST_CONTAINOR(list, struct wlan_network, list);
+		list = get_next(list);
+
+		if (network->network.InfrastructureMode != Ndis802_11_mesh)
+			continue;
+
+		mesh_conf_ie = rtw_get_ie(BSS_EX_TLV_IES(&network->network), WLAN_EID_MESH_CONFIG
+			, &mesh_conf_ie_len, BSS_EX_TLV_IES_LEN(&network->network));
+		if (!mesh_conf_ie || mesh_conf_ie_len != 7)
+			continue;
+
+		mesh_networks[mesh_network_cnt++] = network;
+	}
+
+	exit_critical_bh(&queue->lock);
+
+	RTW_PRINT_SEL(sel, "  %-17s %-3s %-4s %-5s %-32s %-3s %-3s %-3s"
+		NSTATE_TITLE_FMT_ACN
+		"\n"
+		, "bssid", "ch", "rssi", "age", "mesh_id", "nop", "fwd", "cto"
+		NSTATE_TITLE_ARG_ACN
+	);
+
+	for (i = 0; i < mesh_network_cnt; i++) {
+		network = mesh_networks[i];
+
+		if (network->network.InfrastructureMode != Ndis802_11_mesh)
+			continue;
+
+		mesh_conf_ie = rtw_get_ie(BSS_EX_TLV_IES(&network->network), WLAN_EID_MESH_CONFIG
+			, &mesh_conf_ie_len, BSS_EX_TLV_IES_LEN(&network->network));
+		if (!mesh_conf_ie || mesh_conf_ie_len != 7)
+			continue;
+
+		age_ms = rtw_get_passing_time_ms(network->last_scanned);
+		#if CONFIG_RTW_MESH_ACNODE_PREVENT
+		if (network->acnode_stime == 0)
+			acn_ms = 0;
+		else
+			acn_ms = rtw_get_passing_time_ms(network->acnode_stime);
+		#endif
+		same_mbss = 0;
+		candidate = 0;
+		plink = NULL;
+		blocked = 0;
+		established = 0;
+
+		if (MLME_IS_MESH(adapter) && MLME_IS_ASOC(adapter)) {
+			plink = rtw_mesh_plink_get(adapter, network->network.MacAddress);
+			if (plink && plink->plink_state == RTW_MESH_PLINK_ESTAB)
+				established = 1;
+			else if (plink && plink->plink_state == RTW_MESH_PLINK_BLOCKED)
+				blocked = 1;
+			else if (plink)
+				;
+			else if (rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &network->network, 0, 1))
+				candidate = 1;
+			else if (rtw_bss_is_same_mbss(&mlme->cur_network.network, &network->network))
+				same_mbss = 1;
+		}
+
+		RTW_PRINT_SEL(sel, "%c "MAC_FMT" %3d %4ld %5d %-32s %c%2u %3u %c%c "
+			NSTATE_VALUE_FMT_ACN
+			"\n"
+			, established ? 'E' : (blocked ? 'B' : (plink ? 'N' : (candidate ? 'C' : (same_mbss ? 'S' : ' '))))
+			, MAC_ARG(network->network.MacAddress)
+			, network->network.Configuration.DSConfig
+			, network->network.Rssi
+			, age_ms < 99999 ? age_ms : 99999
+			, network->network.mesh_id.Ssid
+			, GET_MESH_CONF_ELE_ACCEPT_PEERINGS(mesh_conf_ie + 2) ? '+' : ' '
+			, GET_MESH_CONF_ELE_NUM_OF_PEERINGS(mesh_conf_ie + 2)
+			, GET_MESH_CONF_ELE_FORWARDING(mesh_conf_ie + 2)
+			, GET_MESH_CONF_ELE_CTO_MGATE(mesh_conf_ie + 2) ? 'G' : ' '
+			, GET_MESH_CONF_ELE_CTO_AS(mesh_conf_ie + 2) ? 'A' : ' '
+			NSTATE_VALUE_ARG_ACN
+		);
+	}
+
+	rtw_vmfree(mesh_networks, mlme->max_bss_cnt * sizeof(struct wlan_network *));
+}
+
+void rtw_mesh_adjust_chbw(u8 req_ch, u8 *req_bw, u8 *req_offset)
+{
+	if (req_ch >= 5 && req_ch <= 9) {
+		/* prevent secondary channel offset mismatch */
+		if (*req_bw > CHANNEL_WIDTH_20) {
+			*req_bw = CHANNEL_WIDTH_20;
+			*req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+		}
+	}
+}
+
+int rtw_sae_check_frames(_adapter *adapter, const u8 *buf, u32 len, u8 tx)
+{
+	const u8 *frame_body = buf + sizeof(struct rtw_ieee80211_hdr_3addr);
+	u16 alg;
+	u16 seq;
+	u16 status;
+	int ret = 0;
+
+	alg = RTW_GET_LE16(frame_body);
+	if (alg != 3)
+		goto exit;
+
+	seq = RTW_GET_LE16(frame_body + 2);
+	status = RTW_GET_LE16(frame_body + 4);
+
+	RTW_INFO("RTW_%s:AUTH alg:0x%04x, seq:0x%04x, status:0x%04x\n"
+		, (tx == _TRUE) ? "Tx" : "Rx", alg, seq, status);
+
+	ret = 1;
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+	if (tx && seq == 1)
+		rtw_mesh_plink_set_peer_conf_timeout(adapter, GetAddr1Ptr(buf));
+#endif
+
+exit:
+	return ret;
+}
+
+#if CONFIG_RTW_MPM_TX_IES_SYNC_BSS
+#ifdef CONFIG_RTW_MESH_AEK
+static int rtw_mpm_ampe_dec(_adapter *adapter, struct mesh_plink_ent *plink
+	, u8 *fhead, size_t flen, u8* fbody, u8 *mic_ie, u8 *ampe_buf)
+{	
+	int ret = _FAIL, verify_ret;
+	const u8 *aad[] = {adapter_mac_addr(adapter), plink->addr, fbody};
+	const size_t aad_len[] = {ETH_ALEN, ETH_ALEN, mic_ie - fbody};
+	u8 *iv_crypt;
+	size_t iv_crypt_len = flen - (mic_ie + 2 - fhead);
+
+	iv_crypt = rtw_malloc(iv_crypt_len);
+	if (!iv_crypt)
+		goto exit;
+
+	_rtw_memcpy(iv_crypt, mic_ie + 2, iv_crypt_len);
+
+	verify_ret = aes_siv_decrypt(plink->aek, iv_crypt, iv_crypt_len
+		, 3, aad, aad_len, ampe_buf);
+
+	rtw_mfree(iv_crypt, iv_crypt_len);
+
+	if (verify_ret) {
+		RTW_WARN("verify error, aek_valid=%u\n", plink->aek_valid);
+		goto exit;
+	} else if (*ampe_buf != WLAN_EID_AMPE) {
+		RTW_WARN("plaintext is not AMPE IE\n");
+		goto exit;
+	} else if (AES_BLOCK_SIZE + 2 + *(ampe_buf + 1) > iv_crypt_len) {
+		RTW_WARN("plaintext AMPE IE length is not valid\n");
+		goto exit;
+	}
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+
+static int rtw_mpm_ampe_enc(_adapter *adapter, struct mesh_plink_ent *plink
+	, u8* fbody, u8 *mic_ie, u8 *ampe_buf, bool inverse)
+{
+	int ret = _FAIL, protect_ret;
+	const u8 *aad[3];
+	const size_t aad_len[3] = {ETH_ALEN, ETH_ALEN, mic_ie - fbody};
+	u8 *ampe_ie;
+	size_t ampe_ie_len = *(ampe_buf + 1) + 2; /* including id & len */
+
+	if (inverse) {
+		aad[0] = plink->addr;
+		aad[1] = adapter_mac_addr(adapter);
+	} else {
+		aad[0] = adapter_mac_addr(adapter);
+		aad[1] = plink->addr;
+	}
+	aad[2] = fbody;
+
+	ampe_ie = rtw_malloc(ampe_ie_len);
+	if (!ampe_ie)
+		goto exit;
+
+	_rtw_memcpy(ampe_ie, ampe_buf, ampe_ie_len);
+
+	protect_ret = aes_siv_encrypt(plink->aek, ampe_ie, ampe_ie_len
+		, 3, aad, aad_len, mic_ie + 2);
+
+	rtw_mfree(ampe_ie, ampe_ie_len);
+
+	if (protect_ret) {
+		RTW_WARN("protect error, aek_valid=%u\n", plink->aek_valid);
+		goto exit;
+	}
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+#endif /* CONFIG_RTW_MESH_AEK */
+
+static int rtw_mpm_tx_ies_sync_bss(_adapter *adapter, struct mesh_plink_ent *plink
+	, u8 *fhead, size_t flen, u8* fbody, u8 tlv_ies_offset, u8 *mpm_ie, u8 *mic_ie
+	, u8 **nbuf, size_t *nlen)
+{
+	int ret = _FAIL;
+	struct mlme_priv *mlme = &(adapter->mlmepriv);
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+	struct mlme_ext_info *mlmeinfo = &(mlmeext->mlmext_info);
+	WLAN_BSSID_EX *network = &(mlmeinfo->network);
+	uint left;
+	u8 *pos;
+
+	uint mpm_ielen = *(mpm_ie + 1);
+	u8 *fpos;
+	u8 *new_buf = NULL;
+	size_t new_len = 0;
+
+	u8 *new_fhead;
+	size_t new_flen;
+	u8 *new_fbody;
+	u8 *new_mic_ie;
+
+#ifdef CONFIG_RTW_MESH_AEK
+	u8 *ampe_buf = NULL;
+	size_t ampe_buf_len = 0;
+
+	/* decode */
+	if (mic_ie) {
+		ampe_buf_len = flen - (mic_ie + 2 + AES_BLOCK_SIZE - fhead);
+		ampe_buf = rtw_malloc(ampe_buf_len);
+		if (!ampe_buf)
+			goto exit;
+
+		if (rtw_mpm_ampe_dec(adapter, plink, fhead, flen, fbody, mic_ie, ampe_buf) != _SUCCESS)
+			goto exit;
+
+		if (*(ampe_buf + 1) >= 68) {
+			_rtw_memcpy(plink->sel_pcs, ampe_buf + 2, 4);
+			_rtw_memcpy(plink->l_nonce, ampe_buf + 6, 32);
+			_rtw_memcpy(plink->p_nonce, ampe_buf + 38, 32);
+		}
+	}
+#endif
+
+	/* count for new frame length  */
+	new_len = sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset;
+	left = BSS_EX_TLV_IES_LEN(network);
+	pos = BSS_EX_TLV_IES(network);
+	while (left >= 2) {
+		u8 id, elen;
+	
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left)
+			break;
+
+		switch (id) {
+		case WLAN_EID_SSID:
+		case WLAN_EID_DS_PARAMS:
+		case WLAN_EID_TIM:
+			break;
+		default:
+			new_len += 2 + elen;
+		}
+
+		left -= elen;
+		pos += elen;
+	}
+	new_len += mpm_ielen + 2;
+	if (mic_ie)
+		new_len += AES_BLOCK_SIZE + 2 + ampe_buf_len;
+
+	/* alloc new frame */
+	new_buf = rtw_malloc(new_len);
+	if (!new_buf) {
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	/* build new frame  */
+	_rtw_memcpy(new_buf, fhead, sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset);
+	new_fhead = new_buf;
+	new_flen = new_len;
+	new_fbody = new_fhead + sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	fpos = new_fbody + tlv_ies_offset;
+	left = BSS_EX_TLV_IES_LEN(network);
+	pos = BSS_EX_TLV_IES(network);
+	while (left >= 2) {
+		u8 id, elen;
+	
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left)
+			break;
+
+		switch (id) {
+		case WLAN_EID_SSID:
+		case WLAN_EID_DS_PARAMS:
+		case WLAN_EID_TIM:
+			break;
+		default:
+			fpos = rtw_set_ie(fpos, id, elen, pos, NULL);
+			if (id == WLAN_EID_MESH_CONFIG)
+				fpos = rtw_set_ie(fpos, WLAN_EID_MPM, mpm_ielen, mpm_ie + 2, NULL);
+		}
+
+		left -= elen;
+		pos += elen;
+	}
+	if (mic_ie) {
+		new_mic_ie = fpos;
+		*fpos++ = WLAN_EID_MIC;
+		*fpos++ = AES_BLOCK_SIZE;
+	}
+
+#ifdef CONFIG_RTW_MESH_AEK
+	/* encode */
+	if (mic_ie) {
+		int enc_ret = rtw_mpm_ampe_enc(adapter, plink, new_fbody, new_mic_ie, ampe_buf, 0);
+		if (enc_ret != _SUCCESS)
+			goto exit;
+	}
+#endif
+
+	*nlen = new_len;
+	*nbuf = new_buf;
+
+	ret = _SUCCESS;
+
+exit:
+	if (ret != _SUCCESS && new_buf)
+		rtw_mfree(new_buf, new_len);
+
+#ifdef CONFIG_RTW_MESH_AEK
+	if (ampe_buf)
+		rtw_mfree(ampe_buf, ampe_buf_len);
+#endif
+
+	return ret;
+}
+#endif /* CONFIG_RTW_MPM_TX_IES_SYNC_BSS */
+
+struct mpm_frame_info {
+	u8 *aid;
+	u16 aid_v;
+	u8 *pid;
+	u16 pid_v;
+	u8 *llid;
+	u16 llid_v;
+	u8 *plid;
+	u16 plid_v;
+	u8 *reason;
+	u16 reason_v;
+	u8 *chosen_pmk;
+};
+
+/*
+* pid:00000 llid:00000 chosen_pmk:0x00000000000000000000000000000000
+* aid:00000 pid:00000 llid:00000 plid:00000 chosen_pmk:0x00000000000000000000000000000000
+* pid:00000 llid:00000 plid:00000 reason:00000 chosen_pmk:0x00000000000000000000000000000000
+*/
+#define MPM_LOG_BUF_LEN 92 /* this length is limited for legal combination */
+static void rtw_mpm_info_msg(struct mpm_frame_info *mpm_info, u8 *mpm_log_buf)
+{
+	int cnt = 0;
+
+	if (mpm_info->aid) {
+		cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "aid:%u ", mpm_info->aid_v);
+		if (cnt >= MPM_LOG_BUF_LEN - 1)
+			goto exit;
+	}
+	if (mpm_info->pid) {
+		cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "pid:%u ", mpm_info->pid_v);
+		if (cnt >= MPM_LOG_BUF_LEN - 1)
+			goto exit;
+	}
+	if (mpm_info->llid) {
+		cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "llid:%u ", mpm_info->llid_v);
+		if (cnt >= MPM_LOG_BUF_LEN - 1)
+			goto exit;
+	}
+	if (mpm_info->plid) {
+		cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "plid:%u ", mpm_info->plid_v);
+		if (cnt >= MPM_LOG_BUF_LEN - 1)
+			goto exit;
+	}
+	if (mpm_info->reason) {
+		cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "reason:%u ", mpm_info->reason_v);
+		if (cnt >= MPM_LOG_BUF_LEN - 1)
+			goto exit;
+	}
+	if (mpm_info->chosen_pmk) {
+		cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "chosen_pmk:0x"KEY_FMT, KEY_ARG(mpm_info->chosen_pmk));
+		if (cnt >= MPM_LOG_BUF_LEN - 1)
+			goto exit;
+	}
+
+exit:
+	return;
+}
+
+static int rtw_mpm_check_frames(_adapter *adapter, u8 action, const u8 **buf, size_t *len, u8 tx)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *plink = NULL;
+	u8 *nbuf = NULL;
+	size_t nlen = 0;
+	u8 *fhead = (u8 *)*buf;
+	size_t flen = *len;
+	u8 *peer_addr = tx ? GetAddr1Ptr(fhead) : get_addr2_ptr(fhead);
+	u8 *frame_body = fhead + sizeof(struct rtw_ieee80211_hdr_3addr);
+	struct mpm_frame_info mpm_info;
+	u8 tlv_ies_offset;
+	u8 *mpm_ie = NULL;
+	uint mpm_ielen = 0;
+	u8 *mic_ie = NULL;
+	uint mic_ielen = 0;
+	int ret = 0;
+	u8 mpm_log_buf[MPM_LOG_BUF_LEN] = {0};
+
+	if (action == RTW_ACT_SELF_PROTECTED_MESH_OPEN)
+		tlv_ies_offset = 4;
+	else if (action == RTW_ACT_SELF_PROTECTED_MESH_CONF)
+		tlv_ies_offset = 6;
+	else if (action == RTW_ACT_SELF_PROTECTED_MESH_CLOSE)
+		tlv_ies_offset = 2;
+	else {
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	plink = rtw_mesh_plink_get(adapter, peer_addr);
+	if (!plink && (tx == _TRUE || action == RTW_ACT_SELF_PROTECTED_MESH_CONF)) {
+		/* warning message if no plink when: 1.TX all MPM or 2.RX CONF */
+		RTW_WARN("RTW_%s:%s without plink of "MAC_FMT"\n"
+			, (tx == _TRUE) ? "Tx" : "Rx", action_self_protected_str(action), MAC_ARG(peer_addr));
+		goto exit;
+	}
+
+	_rtw_memset(&mpm_info, 0, sizeof(struct mpm_frame_info));
+
+	if (action == RTW_ACT_SELF_PROTECTED_MESH_CONF) {
+		mpm_info.aid = (u8 *)frame_body + 4;
+		mpm_info.aid_v = RTW_GET_LE16(mpm_info.aid);
+	}
+
+	mpm_ie = rtw_get_ie(fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset
+		, WLAN_EID_MPM, &mpm_ielen
+		, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);
+	if (!mpm_ie || mpm_ielen < 2 + 2)
+		goto exit;
+
+	mpm_info.pid = mpm_ie + 2;
+	mpm_info.pid_v = RTW_GET_LE16(mpm_info.pid);
+	mpm_info.llid = mpm_info.pid + 2;
+	mpm_info.llid_v = RTW_GET_LE16(mpm_info.llid);
+
+	switch (action) {
+	case RTW_ACT_SELF_PROTECTED_MESH_OPEN:
+		/* pid:2, llid:2, (chosen_pmk:16) */
+		if (mpm_info.pid_v == 0 && mpm_ielen == 4)
+			;
+		else if (mpm_info.pid_v == 1 && mpm_ielen == 20)
+			mpm_info.chosen_pmk = mpm_info.llid + 2;
+		else
+			goto exit;
+		break;
+	case RTW_ACT_SELF_PROTECTED_MESH_CONF:
+		/* pid:2, llid:2, plid:2, (chosen_pmk:16) */
+		mpm_info.plid = mpm_info.llid + 2;
+		mpm_info.plid_v = RTW_GET_LE16(mpm_info.plid);
+		if (mpm_info.pid_v == 0 && mpm_ielen == 6)
+			;
+		else if (mpm_info.pid_v == 1 && mpm_ielen == 22)
+			mpm_info.chosen_pmk = mpm_info.plid + 2;
+		else
+			goto exit;
+		break;
+	case RTW_ACT_SELF_PROTECTED_MESH_CLOSE:
+		/* pid:2, llid:2, (plid:2), reason:2, (chosen_pmk:16) */
+		if (mpm_info.pid_v == 0 && mpm_ielen == 6) {
+			/* MPM, without plid */
+			mpm_info.reason = mpm_info.llid + 2;
+			mpm_info.reason_v = RTW_GET_LE16(mpm_info.reason);
+		} else if (mpm_info.pid_v == 0 && mpm_ielen == 8) {
+			/* MPM, with plid */
+			mpm_info.plid = mpm_info.llid + 2;
+			mpm_info.plid_v = RTW_GET_LE16(mpm_info.plid);
+			mpm_info.reason = mpm_info.plid + 2;
+			mpm_info.reason_v = RTW_GET_LE16(mpm_info.reason);
+		} else if (mpm_info.pid_v == 1 && mpm_ielen == 22) {
+			/* AMPE, without plid */
+			mpm_info.reason = mpm_info.llid + 2;
+			mpm_info.reason_v = RTW_GET_LE16(mpm_info.reason);
+			mpm_info.chosen_pmk = mpm_info.reason + 2;
+		} else if (mpm_info.pid_v == 1 && mpm_ielen == 24) {
+			/* AMPE, with plid */
+			mpm_info.plid = mpm_info.llid + 2;
+			mpm_info.plid_v = RTW_GET_LE16(mpm_info.plid);
+			mpm_info.reason = mpm_info.plid + 2;
+			mpm_info.reason_v = RTW_GET_LE16(mpm_info.reason);
+			mpm_info.chosen_pmk = mpm_info.reason + 2;
+		} else
+			goto exit;
+		break;
+	};
+
+	if (mpm_info.pid_v == 1) {
+		mic_ie = rtw_get_ie(fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset
+			, WLAN_EID_MIC, &mic_ielen
+			, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);
+		if (!mic_ie || mic_ielen != AES_BLOCK_SIZE)
+			goto exit;
+	}
+
+#if CONFIG_RTW_MPM_TX_IES_SYNC_BSS
+	if ((action == RTW_ACT_SELF_PROTECTED_MESH_OPEN || action == RTW_ACT_SELF_PROTECTED_MESH_CONF)
+		&& tx == _TRUE
+	) {
+#define DBG_RTW_MPM_TX_IES_SYNC_BSS 0
+
+		if (mpm_info.pid_v == 1 && (!plink || !MESH_PLINK_AEK_VALID(plink))) {
+			RTW_WARN("AEK not ready, IEs can't sync with BSS\n");
+			goto bypass_sync_bss;
+		}
+
+		if (DBG_RTW_MPM_TX_IES_SYNC_BSS) {
+			RTW_INFO(FUNC_ADPT_FMT" before:\n", FUNC_ADPT_ARG(adapter));
+			dump_ies(RTW_DBGDUMP
+				, fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset
+				, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);
+		}
+
+		rtw_mpm_tx_ies_sync_bss(adapter, plink
+			, fhead, flen, frame_body, tlv_ies_offset, mpm_ie, mic_ie
+			, &nbuf, &nlen);
+		if (!nbuf)
+			goto exit;
+
+		/* update pointer & len for new frame */
+		fhead = nbuf;
+		flen = nlen;
+		frame_body = fhead + sizeof(struct rtw_ieee80211_hdr_3addr);
+		if (mpm_info.pid_v == 1) {
+			mic_ie = rtw_get_ie(fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset
+				, WLAN_EID_MIC, &mic_ielen
+				, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);
+		}
+
+		if (DBG_RTW_MPM_TX_IES_SYNC_BSS) {
+			RTW_INFO(FUNC_ADPT_FMT" after:\n", FUNC_ADPT_ARG(adapter));
+			dump_ies(RTW_DBGDUMP
+				, fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset
+				, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);
+		}
+	}
+bypass_sync_bss:
+#endif /* CONFIG_RTW_MPM_TX_IES_SYNC_BSS */
+
+	if (!plink)
+		goto mpm_log;
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+	if (action == RTW_ACT_SELF_PROTECTED_MESH_OPEN) {
+		if (tx)
+			rtw_mesh_plink_set_peer_conf_timeout(adapter, peer_addr);
+
+	} else
+#endif
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	if (action == RTW_ACT_SELF_PROTECTED_MESH_CLOSE) {
+		if (tx && mpm_info.reason && mpm_info.reason_v == WLAN_REASON_MESH_MAX_PEERS) {
+			if (rtw_mesh_scanned_is_acnode_confirmed(adapter, plink->scanned)
+				&& rtw_mesh_acnode_prevent_allow_sacrifice(adapter)
+			) {
+				struct sta_info *sac = rtw_mesh_acnode_prevent_pick_sacrifice(adapter);
+
+				if (sac) {
+					struct sta_priv *stapriv = &adapter->stapriv;
+					_irqL irqL;
+					u8 sta_addr[ETH_ALEN];
+					u8 updated = _FALSE;
+
+					_enter_critical_bh(&stapriv->asoc_list_lock, &irqL);
+					if (!rtw_is_list_empty(&sac->asoc_list)) {
+						rtw_list_delete(&sac->asoc_list);
+						stapriv->asoc_list_cnt--;
+						STA_SET_MESH_PLINK(sac, NULL);
+					}
+					_exit_critical_bh(&stapriv->asoc_list_lock, &irqL);
+					RTW_INFO(FUNC_ADPT_FMT" sacrifice "MAC_FMT" for acnode\n"
+						, FUNC_ADPT_ARG(adapter), MAC_ARG(sac->cmn.mac_addr));
+
+					_rtw_memcpy(sta_addr, sac->cmn.mac_addr, ETH_ALEN);
+					updated = ap_free_sta(adapter, sac, 0, 0, 1);
+					rtw_mesh_expire_peer(stapriv->padapter, sta_addr);
+
+					associated_clients_update(adapter, updated, STA_INFO_UPDATE_ALL);
+				}
+			}
+		}
+	} else
+#endif
+	if (action == RTW_ACT_SELF_PROTECTED_MESH_CONF) {
+		_irqL irqL;
+		u8 *ies = NULL;
+		u16 ies_len = 0;
+
+		_enter_critical_bh(&(plink_ctl->lock), &irqL);
+
+		plink = _rtw_mesh_plink_get(adapter, peer_addr);
+		if (!plink)
+			goto release_plink_ctl;
+
+		if (tx == _FALSE) {
+			ies = plink->rx_conf_ies;
+			ies_len = plink->rx_conf_ies_len;
+			plink->rx_conf_ies = NULL;
+			plink->rx_conf_ies_len = 0;
+
+			plink->llid = mpm_info.plid_v;
+			plink->plid = mpm_info.llid_v;
+			plink->peer_aid = mpm_info.aid_v;
+			if (mpm_info.pid_v == 1)
+				_rtw_memcpy(plink->chosen_pmk, mpm_info.chosen_pmk, 16);
+		}
+		#ifdef CONFIG_RTW_MESH_DRIVER_AID
+		else {
+			ies = plink->tx_conf_ies;
+			ies_len = plink->tx_conf_ies_len;
+			plink->tx_conf_ies = NULL;
+			plink->tx_conf_ies_len = 0;
+		}
+		#endif
+
+		if (ies && ies_len)
+			rtw_mfree(ies, ies_len);
+
+		#ifndef CONFIG_RTW_MESH_DRIVER_AID
+		if (tx == _TRUE)
+			goto release_plink_ctl; /* no need to copy tx conf ies */
+		#endif
+
+		/* copy mesh confirm IEs */
+		if (mpm_info.pid_v == 1) /* not include MIC & encrypted AMPE */
+			ies_len = (mic_ie - fhead) - sizeof(struct rtw_ieee80211_hdr_3addr) - 2;
+		else
+			ies_len = flen - sizeof(struct rtw_ieee80211_hdr_3addr) - 2;
+
+		ies = rtw_zmalloc(ies_len);
+		if (ies) {
+			_rtw_memcpy(ies, fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + 2, ies_len);
+			if (tx == _FALSE) {
+				plink->rx_conf_ies = ies;
+				plink->rx_conf_ies_len = ies_len;
+			}
+			#ifdef CONFIG_RTW_MESH_DRIVER_AID	
+			else {
+				plink->tx_conf_ies = ies;
+				plink->tx_conf_ies_len = ies_len;
+			}
+			#endif
+		}
+
+release_plink_ctl:
+		_exit_critical_bh(&(plink_ctl->lock), &irqL);
+	}
+
+mpm_log:
+	rtw_mpm_info_msg(&mpm_info, mpm_log_buf);
+	RTW_INFO("RTW_%s:%s %s\n"
+		, (tx == _TRUE) ? "Tx" : "Rx"
+		, action_self_protected_str(action)
+		, mpm_log_buf
+	);
+
+	ret = 1;
+
+exit:
+	if (nbuf) {
+		if (ret == 1) {
+			*buf = nbuf;
+			*len = nlen;
+		} else
+			rtw_mfree(nbuf, nlen);
+	}
+
+	return ret;
+}
+
+static int rtw_mesh_check_frames(_adapter *adapter, const u8 **buf, size_t *len, u8 tx)
+{
+	int is_mesh_frame = -1;
+	const u8 *frame_body;
+	u8 category, action;
+
+	frame_body = *buf + sizeof(struct rtw_ieee80211_hdr_3addr);
+	category = frame_body[0];
+
+	if (category == RTW_WLAN_CATEGORY_SELF_PROTECTED) {
+		action = frame_body[1];
+		switch (action) {
+		case RTW_ACT_SELF_PROTECTED_MESH_OPEN:
+		case RTW_ACT_SELF_PROTECTED_MESH_CONF:
+		case RTW_ACT_SELF_PROTECTED_MESH_CLOSE:
+			rtw_mpm_check_frames(adapter, action, buf, len, tx);
+			is_mesh_frame = action;
+			break;
+		case RTW_ACT_SELF_PROTECTED_MESH_GK_INFORM:
+		case RTW_ACT_SELF_PROTECTED_MESH_GK_ACK:
+			RTW_INFO("RTW_%s:%s\n", (tx == _TRUE) ? "Tx" : "Rx", action_self_protected_str(action));
+			is_mesh_frame = action;
+			break;
+		default:
+			break;
+		};
+	}
+
+exit:
+	return is_mesh_frame;
+}
+
+int rtw_mesh_check_frames_tx(_adapter *adapter, const u8 **buf, size_t *len)
+{
+	return rtw_mesh_check_frames(adapter, buf, len, _TRUE);
+}
+
+int rtw_mesh_check_frames_rx(_adapter *adapter, const u8 *buf, size_t len)
+{
+	return rtw_mesh_check_frames(adapter, &buf, &len, _FALSE);
+}
+
+int rtw_mesh_on_auth(_adapter *adapter, union recv_frame *rframe)
+{
+	u8 *whdr = rframe->u.hdr.rx_data;
+
+#if CONFIG_RTW_MACADDR_ACL
+	if (rtw_access_ctrl(adapter, get_addr2_ptr(whdr)) == _FALSE)
+		return _SUCCESS;
+#endif
+
+	if (!rtw_mesh_plink_get(adapter, get_addr2_ptr(whdr))) {
+		#if CONFIG_RTW_MESH_ACNODE_PREVENT
+		rtw_mesh_acnode_set_notify_etime(adapter, whdr);
+		#endif
+
+		if (adapter_to_rfctl(adapter)->offch_state == OFFCHS_NONE)
+			issue_probereq(adapter, &adapter->mlmepriv.cur_network.network.mesh_id, get_addr2_ptr(whdr));
+
+		/* only peer being added (checked by notify conditions) is allowed */
+		return _SUCCESS;
+	}
+
+	rtw_cfg80211_rx_mframe(adapter, rframe, NULL);
+	return _SUCCESS;
+}
+
+unsigned int on_action_self_protected(_adapter *adapter, union recv_frame *rframe)
+{
+	unsigned int ret = _FAIL;
+	struct sta_info *sta = NULL;
+	u8 *pframe = rframe->u.hdr.rx_data;
+	uint frame_len = rframe->u.hdr.len;
+	u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+	u8 category;
+	u8 action;
+
+	/* check RA matches or not */
+	if (!_rtw_memcmp(adapter_mac_addr(adapter), GetAddr1Ptr(pframe), ETH_ALEN))
+		goto exit;
+
+	category = frame_body[0];
+	if (category != RTW_WLAN_CATEGORY_SELF_PROTECTED)
+		goto exit;
+
+	action = frame_body[1];
+	switch (action) {
+	case RTW_ACT_SELF_PROTECTED_MESH_OPEN:
+	case RTW_ACT_SELF_PROTECTED_MESH_CONF:
+	case RTW_ACT_SELF_PROTECTED_MESH_CLOSE:
+	case RTW_ACT_SELF_PROTECTED_MESH_GK_INFORM:
+	case RTW_ACT_SELF_PROTECTED_MESH_GK_ACK:
+		if (!(MLME_IS_MESH(adapter) && MLME_IS_ASOC(adapter)))
+			goto exit;
+#ifdef CONFIG_IOCTL_CFG80211
+		#if CONFIG_RTW_MACADDR_ACL
+		if (rtw_access_ctrl(adapter, get_addr2_ptr(pframe)) == _FALSE)
+			goto exit;
+		#endif
+		#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+		if (rtw_mesh_cto_mgate_required(adapter)
+			/* only peer being added (checked by notify conditions) is allowed */
+			&& !rtw_mesh_plink_get(adapter, get_addr2_ptr(pframe)))
+			goto exit;
+		#endif
+		rtw_cfg80211_rx_action(adapter, rframe, NULL);
+		ret = _SUCCESS;
+#endif /* CONFIG_IOCTL_CFG80211 */
+		break;
+	default:
+		break;
+	}
+
+exit:
+	return ret;
+}
+
+const u8 ae_to_mesh_ctrl_len[] = {
+	6,
+	12, /* MESH_FLAGS_AE_A4 */
+	18, /* MESH_FLAGS_AE_A5_A6 */
+	0,
+};
+
+unsigned int on_action_mesh(_adapter *adapter, union recv_frame *rframe)
+{
+	unsigned int ret = _FAIL;
+	struct sta_info *sta = NULL;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	u8 *pframe = rframe->u.hdr.rx_data;
+	uint frame_len = rframe->u.hdr.len;
+	u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+	u8 category;
+	u8 action;
+
+	if (!MLME_IS_MESH(adapter))
+		goto exit;
+
+	/* check stainfo exist? */
+
+	category = frame_body[0];
+	if (category != RTW_WLAN_CATEGORY_MESH)
+		goto exit;
+
+	action = frame_body[1];
+	switch (action) {
+	case RTW_ACT_MESH_HWMP_PATH_SELECTION:
+		rtw_mesh_rx_path_sel_frame(adapter, rframe);
+		ret = _SUCCESS;
+		break;
+	default:
+		break;
+	}
+
+exit:
+	return ret;
+}
+
+bool rtw_mesh_update_bss_peering_status(_adapter *adapter, WLAN_BSSID_EX *bss)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	u8 num_of_peerings = stapriv->asoc_list_cnt;
+	bool accept_peerings = stapriv->asoc_list_cnt < mcfg->max_peer_links;
+	u8 *ie;
+	int ie_len;
+	bool updated = 0;
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	accept_peerings |= plink_ctl->acnode_rsvd;
+#endif
+
+	ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len, BSS_EX_TLV_IES_LEN(bss));
+	if (!ie || ie_len != 7) {
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	if (GET_MESH_CONF_ELE_NUM_OF_PEERINGS(ie + 2) != num_of_peerings) {
+		SET_MESH_CONF_ELE_NUM_OF_PEERINGS(ie + 2, num_of_peerings);
+		updated = 1;
+	}
+
+	if (GET_MESH_CONF_ELE_ACCEPT_PEERINGS(ie + 2) != accept_peerings) {
+		SET_MESH_CONF_ELE_ACCEPT_PEERINGS(ie + 2, accept_peerings);
+		updated = 1;
+	}
+
+exit:
+	return updated;
+}
+
+bool rtw_mesh_update_bss_formation_info(_adapter *adapter, WLAN_BSSID_EX *bss)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	u8 cto_mgate = (minfo->num_gates || mcfg->dot11MeshGateAnnouncementProtocol);
+	u8 cto_as = 0;
+	u8 *ie;
+	int ie_len;
+	bool updated = 0;
+
+	ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,
+			BSS_EX_TLV_IES_LEN(bss));
+	if (!ie || ie_len != 7) {
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	if (GET_MESH_CONF_ELE_CTO_MGATE(ie + 2) != cto_mgate) {
+		SET_MESH_CONF_ELE_CTO_MGATE(ie + 2, cto_mgate);
+		updated = 1;
+	}
+
+	if (GET_MESH_CONF_ELE_CTO_AS(ie + 2) != cto_as) {
+		SET_MESH_CONF_ELE_CTO_AS(ie + 2, cto_as);
+		updated = 1;
+	}
+
+exit:
+	return updated;
+}
+
+bool rtw_mesh_update_bss_forwarding_state(_adapter *adapter, WLAN_BSSID_EX *bss)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	u8 forward = mcfg->dot11MeshForwarding;
+	u8 *ie;
+	int ie_len;
+	bool updated = 0;
+
+	ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,
+			BSS_EX_TLV_IES_LEN(bss));
+	if (!ie || ie_len != 7) {
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	if (GET_MESH_CONF_ELE_FORWARDING(ie + 2) != forward) {
+		SET_MESH_CONF_ELE_FORWARDING(ie + 2, forward);
+		updated = 1;
+	}
+
+exit:
+	return updated;
+}
+
+struct mesh_plink_ent *_rtw_mesh_plink_get(_adapter *adapter, const u8 *hwaddr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent = NULL;
+	int i;
+
+	for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {
+		if (plink_ctl->ent[i].valid == _TRUE
+			&& _rtw_memcmp(plink_ctl->ent[i].addr, hwaddr, ETH_ALEN) == _TRUE
+		) {
+			ent = &plink_ctl->ent[i];
+			break;
+		}
+	}
+
+exit:
+	return ent;
+}
+
+struct mesh_plink_ent *rtw_mesh_plink_get(_adapter *adapter, const u8 *hwaddr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent = NULL;
+	_irqL irqL;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+	ent = _rtw_mesh_plink_get(adapter, hwaddr);
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+
+exit:
+	return ent;
+}
+
+struct mesh_plink_ent *rtw_mesh_plink_get_no_estab_by_idx(_adapter *adapter, u8 idx)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent = NULL;
+	int i, j = 0;
+	_irqL irqL;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+	for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {
+		if (plink_ctl->ent[i].valid == _TRUE
+			&& plink_ctl->ent[i].plink_state != RTW_MESH_PLINK_ESTAB
+		) {
+			if (j == idx) {
+				ent = &plink_ctl->ent[i];
+				break;
+			}
+			j++;
+		}
+	}
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+
+	return ent;
+}
+
+int _rtw_mesh_plink_add(_adapter *adapter, const u8 *hwaddr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent = NULL;
+	u8 exist = _FALSE;
+	int i;
+
+	for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {
+		if (plink_ctl->ent[i].valid == _TRUE
+			&& _rtw_memcmp(plink_ctl->ent[i].addr, hwaddr, ETH_ALEN) == _TRUE
+		) {
+			ent = &plink_ctl->ent[i];
+			exist = _TRUE;
+			break;
+		}
+
+		if (ent == NULL && plink_ctl->ent[i].valid == _FALSE)
+			ent = &plink_ctl->ent[i];
+	}
+
+	if (exist == _FALSE && ent) {
+		_rtw_memcpy(ent->addr, hwaddr, ETH_ALEN);
+		ent->valid = _TRUE;
+		#ifdef CONFIG_RTW_MESH_AEK
+		ent->aek_valid = 0;
+		#endif
+		ent->llid = 0;
+		ent->plid = 0;
+		_rtw_memset(ent->chosen_pmk, 0, 16);
+		#ifdef CONFIG_RTW_MESH_AEK
+		_rtw_memset(ent->sel_pcs, 0, 4);
+		_rtw_memset(ent->l_nonce, 0, 32);
+		_rtw_memset(ent->p_nonce, 0, 32);
+		#endif
+		ent->plink_state = RTW_MESH_PLINK_LISTEN;
+		#ifndef CONFIG_RTW_MESH_DRIVER_AID
+		ent->aid = 0;
+		#endif
+		ent->peer_aid = 0;
+		SET_PEER_CONF_DISABLED(ent);
+		SET_CTO_MGATE_CONF_DISABLED(ent);
+		plink_ctl->num++;
+	}
+
+exit:
+	return exist == _TRUE ? RTW_ALREADY : (ent ? _SUCCESS : _FAIL);
+}
+
+int rtw_mesh_plink_add(_adapter *adapter, const u8 *hwaddr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	_irqL irqL;
+	int ret;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+	ret = _rtw_mesh_plink_add(adapter, hwaddr);
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+
+	return ret;
+}
+
+int rtw_mesh_plink_set_state(_adapter *adapter, const u8 *hwaddr, u8 state)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent = NULL;
+	_irqL irqL;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+	ent = _rtw_mesh_plink_get(adapter, hwaddr);
+	if (ent)
+		ent->plink_state = state;
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+
+exit:
+	return ent ? _SUCCESS : _FAIL;
+}
+
+#ifdef CONFIG_RTW_MESH_AEK
+int rtw_mesh_plink_set_aek(_adapter *adapter, const u8 *hwaddr, const u8 *aek)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent = NULL;
+	_irqL irqL;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+	ent = _rtw_mesh_plink_get(adapter, hwaddr);
+	if (ent) {
+		_rtw_memcpy(ent->aek, aek, 32);
+		ent->aek_valid = 1;
+	}
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+
+exit:
+	return ent ? _SUCCESS : _FAIL;
+}
+#endif
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+int rtw_mesh_plink_set_peer_conf_timeout(_adapter *adapter, const u8 *hwaddr)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent = NULL;
+	_irqL irqL;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+	ent = _rtw_mesh_plink_get(adapter, hwaddr);
+	if (ent) {
+		if (IS_PEER_CONF_DISABLED(ent))
+			SET_PEER_CONF_END_TIME(ent, mcfg->peer_sel_policy.peer_conf_timeout_ms);
+	}
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+
+exit:
+	return ent ? _SUCCESS : _FAIL;
+}
+#endif
+
+void _rtw_mesh_plink_del_ent(_adapter *adapter, struct mesh_plink_ent *ent)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+
+	ent->valid = _FALSE;
+	#ifdef CONFIG_RTW_MESH_DRIVER_AID
+	if (ent->tx_conf_ies && ent->tx_conf_ies_len)
+		rtw_mfree(ent->tx_conf_ies, ent->tx_conf_ies_len);
+	ent->tx_conf_ies = NULL;
+	ent->tx_conf_ies_len = 0;
+	#endif
+	if (ent->rx_conf_ies && ent->rx_conf_ies_len)
+		rtw_mfree(ent->rx_conf_ies, ent->rx_conf_ies_len);
+	ent->rx_conf_ies = NULL;
+	ent->rx_conf_ies_len = 0;
+	if (ent->scanned)
+		ent->scanned = NULL;
+	plink_ctl->num--;
+}
+
+int rtw_mesh_plink_del(_adapter *adapter, const u8 *hwaddr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent = NULL;
+	u8 exist = _FALSE;
+	int i;
+	_irqL irqL;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+	for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {
+		if (plink_ctl->ent[i].valid == _TRUE
+			&& _rtw_memcmp(plink_ctl->ent[i].addr, hwaddr, ETH_ALEN) == _TRUE
+		) {
+			ent = &plink_ctl->ent[i];
+			exist = _TRUE;
+			break;
+		}
+	}
+
+	if (exist == _TRUE)
+		_rtw_mesh_plink_del_ent(adapter, ent);
+
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+
+exit:
+	return exist == _TRUE ? _SUCCESS : RTW_ALREADY;
+}
+
+void rtw_mesh_plink_ctl_init(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	int i;
+
+	_rtw_spinlock_init(&plink_ctl->lock);
+	plink_ctl->num = 0;
+	for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++)
+		plink_ctl->ent[i].valid = _FALSE;
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+	_rtw_init_queue(&plink_ctl->peer_blacklist);
+#endif
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	_rtw_init_queue(&plink_ctl->cto_mgate_blacklist);
+#endif
+}
+
+void rtw_mesh_plink_ctl_deinit(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent;
+	int i;
+	_irqL irqL;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+	for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {
+		ent = &plink_ctl->ent[i];
+		#ifdef CONFIG_RTW_MESH_DRIVER_AID
+		if (ent->tx_conf_ies && ent->tx_conf_ies_len)
+			rtw_mfree(ent->tx_conf_ies, ent->tx_conf_ies_len);
+		#endif
+		if (ent->rx_conf_ies && ent->rx_conf_ies_len)
+			rtw_mfree(ent->rx_conf_ies, ent->rx_conf_ies_len);
+	}
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+
+	_rtw_spinlock_free(&plink_ctl->lock);
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+	rtw_mesh_peer_blacklist_flush(adapter);
+	_rtw_deinit_queue(&plink_ctl->peer_blacklist);
+#endif
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	rtw_mesh_cto_mgate_blacklist_flush(adapter);
+	_rtw_deinit_queue(&plink_ctl->cto_mgate_blacklist);
+#endif
+}
+
+void dump_mesh_plink_ctl(void *sel, _adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *ent;
+	int i;
+
+	RTW_PRINT_SEL(sel, "num:%u\n", plink_ctl->num);
+	#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	RTW_PRINT_SEL(sel, "acnode_rsvd:%u\n", plink_ctl->acnode_rsvd);
+	#endif
+
+	for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++)  {
+		ent = &plink_ctl->ent[i];
+		if (!ent->valid)
+			continue;
+
+		RTW_PRINT_SEL(sel, "\n");
+		RTW_PRINT_SEL(sel, "peer:"MAC_FMT"\n", MAC_ARG(ent->addr));
+		RTW_PRINT_SEL(sel, "plink_state:%s\n", rtw_mesh_plink_str(ent->plink_state));
+
+		#ifdef CONFIG_RTW_MESH_AEK
+		if (ent->aek_valid)
+			RTW_PRINT_SEL(sel, "aek:"KEY_FMT KEY_FMT"\n", KEY_ARG(ent->aek), KEY_ARG(ent->aek + 16));
+		#endif
+
+		RTW_PRINT_SEL(sel, "llid:%u, plid:%u\n", ent->llid, ent->plid);
+		#ifndef CONFIG_RTW_MESH_DRIVER_AID
+		RTW_PRINT_SEL(sel, "aid:%u\n", ent->aid);
+		#endif
+		RTW_PRINT_SEL(sel, "peer_aid:%u\n", ent->peer_aid);
+
+		RTW_PRINT_SEL(sel, "chosen_pmk:"KEY_FMT"\n", KEY_ARG(ent->chosen_pmk));
+
+		#ifdef CONFIG_RTW_MESH_AEK
+		RTW_PRINT_SEL(sel, "sel_pcs:%02x%02x%02x%02x\n"
+			, ent->sel_pcs[0], ent->sel_pcs[1], ent->sel_pcs[2], ent->sel_pcs[3]);
+		RTW_PRINT_SEL(sel, "l_nonce:"KEY_FMT KEY_FMT"\n", KEY_ARG(ent->l_nonce), KEY_ARG(ent->l_nonce + 16));
+		RTW_PRINT_SEL(sel, "p_nonce:"KEY_FMT KEY_FMT"\n", KEY_ARG(ent->p_nonce), KEY_ARG(ent->p_nonce + 16));
+		#endif
+
+		#ifdef CONFIG_RTW_MESH_DRIVER_AID
+		RTW_PRINT_SEL(sel, "tx_conf_ies:%p, len:%u\n", ent->tx_conf_ies, ent->tx_conf_ies_len);
+		#endif
+		RTW_PRINT_SEL(sel, "rx_conf_ies:%p, len:%u\n", ent->rx_conf_ies, ent->rx_conf_ies_len);
+		RTW_PRINT_SEL(sel, "scanned:%p\n", ent->scanned);
+
+		#if CONFIG_RTW_MESH_PEER_BLACKLIST
+		if (!IS_PEER_CONF_DISABLED(ent)) {
+			if (!IS_PEER_CONF_TIMEOUT(ent))
+				RTW_PRINT_SEL(sel, "peer_conf:%d\n", rtw_systime_to_ms(ent->peer_conf_end_time - rtw_get_current_time()));
+			else
+				RTW_PRINT_SEL(sel, "peer_conf:TIMEOUT\n");
+		}
+		#endif
+
+		#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+		if (!IS_CTO_MGATE_CONF_DISABLED(ent)) {
+			if (!IS_CTO_MGATE_CONF_TIMEOUT(ent))
+				RTW_PRINT_SEL(sel, "cto_mgate_conf:%d\n", rtw_systime_to_ms(ent->cto_mgate_conf_end_time - rtw_get_current_time()));
+			else
+				RTW_PRINT_SEL(sel, "cto_mgate_conf:TIMEOUT\n");
+		}
+		#endif
+	}
+}
+
+/* this function is called with plink_ctl being locked */
+int rtw_mesh_peer_establish(_adapter *adapter, struct mesh_plink_ent *plink, struct sta_info *sta)
+{
+#ifndef DBG_RTW_MESH_PEER_ESTABLISH
+#define DBG_RTW_MESH_PEER_ESTABLISH 0
+#endif
+
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	u8 *tlv_ies;
+	u16 tlv_ieslen;
+	struct rtw_ieee802_11_elems elems;
+	_irqL irqL;
+	int i;
+	int ret = _FAIL;
+
+	if (!plink->rx_conf_ies || !plink->rx_conf_ies_len) {
+		RTW_INFO(FUNC_ADPT_FMT" no rx confirm from sta "MAC_FMT"\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));
+		goto exit;
+	}
+
+	if (plink->rx_conf_ies_len < 4) {
+		RTW_INFO(FUNC_ADPT_FMT" confirm from sta "MAC_FMT" too short\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));
+		goto exit;
+	}
+
+#ifdef CONFIG_RTW_MESH_DRIVER_AID
+	if (!plink->tx_conf_ies || !plink->tx_conf_ies_len) {
+		RTW_INFO(FUNC_ADPT_FMT" no tx confirm to sta "MAC_FMT"\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));
+		goto exit;
+	}
+
+	if (plink->tx_conf_ies_len < 4) {
+		RTW_INFO(FUNC_ADPT_FMT" confirm to sta "MAC_FMT" too short\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));
+		goto exit;
+	}
+#endif
+
+	tlv_ies = plink->rx_conf_ies + 4;
+	tlv_ieslen = plink->rx_conf_ies_len - 4;
+
+	if (DBG_RTW_MESH_PEER_ESTABLISH)
+		dump_ies(RTW_DBGDUMP, tlv_ies, tlv_ieslen);
+
+	if (rtw_ieee802_11_parse_elems(tlv_ies, tlv_ieslen, &elems, 1) == ParseFailed) {
+		RTW_INFO(FUNC_ADPT_FMT" sta "MAC_FMT" sent invalid confirm\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));
+		goto exit;
+	}
+
+	SET_PEER_CONF_DISABLED(plink);
+	if (rtw_bss_is_cto_mgate(&plink->scanned->network)
+		&& !rtw_bss_is_forwarding(&plink->scanned->network))
+		SET_CTO_MGATE_CONF_END_TIME(plink, mcfg->peer_sel_policy.cto_mgate_conf_timeout_ms);
+	else
+		SET_CTO_MGATE_CONF_DISABLED(plink);
+
+	sta->state &= (~WIFI_FW_AUTH_SUCCESS);
+	sta->state |= WIFI_FW_ASSOC_STATE;
+
+	rtw_ap_parse_sta_capability(adapter, sta, plink->rx_conf_ies);
+
+	if (rtw_ap_parse_sta_supported_rates(adapter, sta, tlv_ies, tlv_ieslen) != _STATS_SUCCESSFUL_)
+		goto exit;
+	
+	if (rtw_ap_parse_sta_security_ie(adapter, sta, &elems) != _STATS_SUCCESSFUL_)
+		goto exit;
+
+	rtw_ap_parse_sta_wmm_ie(adapter, sta, tlv_ies, tlv_ieslen);
+
+	rtw_ap_parse_sta_ht_ie(adapter, sta, &elems);
+	rtw_ap_parse_sta_vht_ie(adapter, sta, &elems);
+
+	/* AID */
+#ifdef CONFIG_RTW_MESH_DRIVER_AID
+	sta->cmn.aid = RTW_GET_LE16(plink->tx_conf_ies + 2);
+#else
+	sta->cmn.aid = plink->aid;
+#endif
+	stapriv->sta_aid[sta->cmn.aid - 1] = sta;
+	RTW_INFO(FUNC_ADPT_FMT" sta "MAC_FMT" aid:%u\n"
+		, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr), sta->cmn.aid);
+
+	sta->state &= (~WIFI_FW_ASSOC_STATE);
+	sta->state |= WIFI_FW_ASSOC_SUCCESS;
+
+	sta->local_mps = RTW_MESH_PS_ACTIVE;
+
+	rtw_ewma_err_rate_init(&sta->metrics.err_rate);
+	rtw_ewma_err_rate_add(&sta->metrics.err_rate, 1);
+	/* init data_rate to 1M */
+	sta->metrics.data_rate = 10;
+
+	_enter_critical_bh(&stapriv->asoc_list_lock, &irqL);
+	if (rtw_is_list_empty(&sta->asoc_list)) {
+		STA_SET_MESH_PLINK(sta, plink);
+		/* TBD: up layer timeout mechanism */
+		/* sta->expire_to = mcfg->plink_timeout / 2; */
+		rtw_list_insert_tail(&sta->asoc_list, &stapriv->asoc_list);
+		stapriv->asoc_list_cnt++;
+	}
+	_exit_critical_bh(&stapriv->asoc_list_lock, &irqL);
+
+	bss_cap_update_on_sta_join(adapter, sta);
+	sta_info_update(adapter, sta);
+	report_add_sta_event(adapter, sta->cmn.mac_addr);
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+
+void rtw_mesh_expire_peer_notify(_adapter *adapter, const u8 *peer_addr)
+{
+	u8 null_ssid[2] = {0, 0};
+
+#ifdef CONFIG_IOCTL_CFG80211
+	rtw_cfg80211_notify_new_peer_candidate(adapter->rtw_wdev
+		, peer_addr
+		, null_ssid
+		, 2
+		, GFP_ATOMIC
+	);
+#endif
+
+exit:
+	return;
+}
+
+static u8 *rtw_mesh_construct_peer_mesh_close(_adapter *adapter, struct mesh_plink_ent *plink, u16 reason, u32 *len)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	u8 *frame = NULL, *pos;
+	u32 flen;
+	struct rtw_ieee80211_hdr *whdr;
+
+	if (minfo->mesh_auth_id && !MESH_PLINK_AEK_VALID(plink))
+		goto exit;
+
+	flen = sizeof(struct rtw_ieee80211_hdr_3addr)
+		+ 2 /* category, action */
+		+ 2 + minfo->mesh_id_len /* mesh id */
+		+ 2 + 8 + (minfo->mesh_auth_id ? 16 : 0) /* mpm */
+		+ (minfo->mesh_auth_id ? 2 + AES_BLOCK_SIZE : 0) /* mic */
+		+ (minfo->mesh_auth_id ? 70 : 0) /* ampe */
+		;
+
+	pos = frame = rtw_zmalloc(flen);
+	if (!frame)
+		goto exit;
+
+	whdr = (struct rtw_ieee80211_hdr *)frame;
+	_rtw_memcpy(whdr->addr1, adapter_mac_addr(adapter), ETH_ALEN);
+	_rtw_memcpy(whdr->addr2, plink->addr, ETH_ALEN);
+	_rtw_memcpy(whdr->addr3, adapter_mac_addr(adapter), ETH_ALEN);
+
+	set_frame_sub_type(frame, WIFI_ACTION);
+
+	pos += sizeof(struct rtw_ieee80211_hdr_3addr);
+	*(pos++) = RTW_WLAN_CATEGORY_SELF_PROTECTED;
+	*(pos++) = RTW_ACT_SELF_PROTECTED_MESH_CLOSE;
+
+	pos = rtw_set_ie_mesh_id(pos, NULL, minfo->mesh_id, minfo->mesh_id_len);
+
+	pos = rtw_set_ie_mpm(pos, NULL
+		, minfo->mesh_auth_id ? 1 : 0
+		, plink->plid
+		, &plink->llid
+		, &reason
+		, minfo->mesh_auth_id ? plink->chosen_pmk : NULL);
+
+#ifdef CONFIG_RTW_MESH_AEK
+	if (minfo->mesh_auth_id) {
+		u8 ampe_buf[70];
+		int enc_ret;
+
+		*pos = WLAN_EID_MIC;
+		*(pos + 1) = AES_BLOCK_SIZE;
+
+		ampe_buf[0] = WLAN_EID_AMPE;
+		ampe_buf[1] = 68;
+		_rtw_memcpy(ampe_buf + 2, plink->sel_pcs, 4);
+		_rtw_memcpy(ampe_buf + 6, plink->p_nonce, 32);
+		_rtw_memcpy(ampe_buf + 38, plink->l_nonce, 32);
+
+		enc_ret = rtw_mpm_ampe_enc(adapter, plink
+			, frame + sizeof(struct rtw_ieee80211_hdr_3addr)
+			, pos, ampe_buf, 1);
+		if (enc_ret != _SUCCESS) {
+			rtw_mfree(frame, flen);
+			frame = NULL;
+			goto exit;
+		}
+	}
+#endif
+
+	*len = flen;
+
+exit:
+	return frame;
+}
+
+void _rtw_mesh_expire_peer_ent(_adapter *adapter, struct mesh_plink_ent *plink)
+{
+#if defined(CONFIG_RTW_MESH_STA_DEL_DISASOC)
+	_rtw_mesh_plink_del_ent(adapter, plink);
+	rtw_cfg80211_indicate_sta_disassoc(adapter, plink->addr, 0);
+#else
+	u8 *frame = NULL;
+	u32 flen;
+
+	if (plink->plink_state == RTW_MESH_PLINK_ESTAB)
+		frame = rtw_mesh_construct_peer_mesh_close(adapter, plink, WLAN_REASON_MESH_CLOSE, &flen);
+
+	if (frame) {
+		struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+		struct wireless_dev *wdev = adapter->rtw_wdev;
+		s32 freq = rtw_ch2freq(mlmeext->cur_channel);
+
+		#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+		rtw_cfg80211_rx_mgmt(wdev, freq, 0, frame, flen, GFP_ATOMIC);
+		#else
+		cfg80211_rx_action(adapter->pnetdev, freq, frame, flen, GFP_ATOMIC);
+		#endif
+
+		rtw_mfree(frame, flen);
+	} else {
+		rtw_mesh_expire_peer_notify(adapter, plink->addr);
+		RTW_INFO(FUNC_ADPT_FMT" set "MAC_FMT" plink unknown\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(plink->addr));
+		plink->plink_state = RTW_MESH_PLINK_UNKNOWN;
+	}
+#endif
+}
+
+void rtw_mesh_expire_peer(_adapter *adapter, const u8 *peer_addr)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;
+	struct mesh_plink_ent *plink;
+	_irqL irqL;
+
+	_enter_critical_bh(&(plink_ctl->lock), &irqL);
+
+	plink = _rtw_mesh_plink_get(adapter, peer_addr);
+	if (!plink)
+		goto exit;
+
+	_rtw_mesh_expire_peer_ent(adapter, plink);
+
+exit:
+	_exit_critical_bh(&(plink_ctl->lock), &irqL);
+}
+
+u8 rtw_mesh_ps_annc(_adapter *adapter, u8 ps)
+{
+	_irqL irqL;
+	_list *head, *list;
+	struct sta_info *sta;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	u8 sta_alive_num = 0, i;
+	char sta_alive_list[NUM_STA];
+	u8 annc_cnt = 0;
+
+	if (rtw_linked_check(adapter) == _FALSE)
+		goto exit;
+
+	_enter_critical_bh(&stapriv->asoc_list_lock, &irqL);
+
+	head = &stapriv->asoc_list;
+	list = get_next(head);
+	while ((rtw_end_of_queue_search(head, list)) == _FALSE) {
+		int stainfo_offset;
+
+		sta = LIST_CONTAINOR(list, struct sta_info, asoc_list);
+		list = get_next(list);
+
+		stainfo_offset = rtw_stainfo_offset(stapriv, sta);
+		if (stainfo_offset_valid(stainfo_offset))
+			sta_alive_list[sta_alive_num++] = stainfo_offset;
+	}
+	_exit_critical_bh(&stapriv->asoc_list_lock, &irqL);
+
+	for (i = 0; i < sta_alive_num; i++) {
+		sta = rtw_get_stainfo_by_offset(stapriv, sta_alive_list[i]);
+		if (!sta)
+			continue;
+
+		issue_qos_nulldata(adapter, sta->cmn.mac_addr, 7, ps, 3, 500);
+		annc_cnt++;
+	}
+
+exit:
+	return annc_cnt;
+}
+
+static void mpath_tx_tasklet_hdl(void *priv)
+{
+	_adapter *adapter = (_adapter *)priv;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct xmit_frame *xframe;
+	_list *list, *head;
+	_list tmp;
+	u32 tmp_len;
+	s32 res;
+
+	_rtw_init_listhead(&tmp);
+
+	while (1) {
+		tmp_len = 0;
+		enter_critical_bh(&minfo->mpath_tx_queue.lock);
+		if (minfo->mpath_tx_queue_len) {
+			rtw_list_splice_init(&minfo->mpath_tx_queue.queue, &tmp);
+			tmp_len = minfo->mpath_tx_queue_len;
+			minfo->mpath_tx_queue_len = 0;
+		}
+		exit_critical_bh(&minfo->mpath_tx_queue.lock);
+
+		if (!tmp_len)
+			break;
+
+		head = &tmp;
+		list = get_next(head);
+		while (rtw_end_of_queue_search(head, list) == _FALSE) {
+			xframe = LIST_CONTAINOR(list, struct xmit_frame, list);
+			list = get_next(list);
+			rtw_list_delete(&xframe->list);
+			res = rtw_xmit_posthandle(adapter, xframe, xframe->pkt);
+			if (res < 0) {
+				#ifdef DBG_TX_DROP_FRAME
+				RTW_INFO("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__);
+				#endif
+				adapter->xmitpriv.tx_drop++;
+			}
+		}
+	}
+}
+
+static void rtw_mpath_tx_queue_flush(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct xmit_frame *xframe;
+	_list *list, *head;
+	_list tmp;
+
+	_rtw_init_listhead(&tmp);
+
+	enter_critical_bh(&minfo->mpath_tx_queue.lock);
+	rtw_list_splice_init(&minfo->mpath_tx_queue.queue, &tmp);
+	minfo->mpath_tx_queue_len = 0;
+	exit_critical_bh(&minfo->mpath_tx_queue.lock);
+
+	head = &tmp;
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		xframe = LIST_CONTAINOR(list, struct xmit_frame, list);
+		list = get_next(list);
+		rtw_list_delete(&xframe->list);
+		rtw_free_xmitframe(&adapter->xmitpriv, xframe);
+	}
+}
+
+#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */
+#if defined(CONFIG_SLUB)
+#include <linux/slub_def.h>
+#elif defined(CONFIG_SLAB)
+#include <linux/slab_def.h>
+#endif
+typedef struct kmem_cache rtw_mcache;
+#endif
+
+rtw_mcache *rtw_mcache_create(const char *name, size_t size)
+{
+#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */
+	return kmem_cache_create(name, size, 0, 0, NULL);
+#else
+	#error "TBD\n";
+#endif
+}
+
+void rtw_mcache_destroy(rtw_mcache *s)
+{
+#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */
+	kmem_cache_destroy(s);
+#else
+	#error "TBD\n";
+#endif
+}
+
+void *_rtw_mcache_alloc(rtw_mcache *cachep)
+{
+#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */
+	return kmem_cache_alloc(cachep, GFP_ATOMIC);
+#else
+	#error "TBD\n";
+#endif
+}
+
+void _rtw_mcache_free(rtw_mcache *cachep, void *objp)
+{
+#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */
+	kmem_cache_free(cachep, objp);
+#else
+	#error "TBD\n";
+#endif
+}
+
+#ifdef DBG_MEM_ALLOC
+inline void *dbg_rtw_mcache_alloc(rtw_mcache *cachep, const enum mstat_f flags, const char *func, const int line)
+{
+	void *p;
+	u32 sz = cachep->size;
+
+	if (match_mstat_sniff_rules(flags, sz))
+		RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%u)\n", func, line, __func__, sz);
+
+	p = _rtw_mcache_alloc(cachep);
+
+	rtw_mstat_update(
+		flags
+		, p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+		, sz
+	);
+
+	return p;
+}
+
+inline void dbg_rtw_mcache_free(rtw_mcache *cachep, void *pbuf, const enum mstat_f flags, const char *func, const int line)
+{
+	u32 sz = cachep->size;
+
+	if (match_mstat_sniff_rules(flags, sz))
+		RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%u)\n", func, line, __func__, sz);
+
+	_rtw_mcache_free(cachep, pbuf);
+
+	rtw_mstat_update(
+		flags
+		, MSTAT_FREE
+		, sz
+	);
+}
+
+#define rtw_mcache_alloc(cachep) dbg_rtw_mcache_alloc(cachep, MSTAT_TYPE_PHY, __FUNCTION__, __LINE__)
+#define rtw_mcache_free(cachep, objp) dbg_rtw_mcache_free(cachep, objp, MSTAT_TYPE_PHY, __FUNCTION__, __LINE__)
+#else
+#define rtw_mcache_alloc(cachep) _rtw_mcache_alloc(cachep)
+#define rtw_mcache_free(cachep, objp) _rtw_mcache_free(cachep, objp)
+#endif /* DBG_MEM_ALLOC */
+
+/* Mesh Received Cache */
+#define RTW_MRC_BUCKETS			256 /* must be a power of 2 */
+#define RTW_MRC_QUEUE_MAX_LEN	4
+#define RTW_MRC_TIMEOUT_MS		(3 * 1000)
+
+/**
+ * struct rtw_mrc_entry - entry in the Mesh Received Cache
+ *
+ * @seqnum: mesh sequence number of the frame
+ * @exp_time: expiration time of the entry
+ * @msa: mesh source address of the frame
+ * @list: hashtable list pointer
+ *
+ * The Mesh Received Cache keeps track of the latest received frames that
+ * have been received by a mesh interface and discards received frames
+ * that are found in the cache.
+ */
+struct rtw_mrc_entry {
+	rtw_hlist_node list;
+	systime exp_time;
+	u32 seqnum;
+	u8 msa[ETH_ALEN];
+};
+
+struct rtw_mrc {
+	rtw_hlist_head bucket[RTW_MRC_BUCKETS];
+	u32 idx_mask;
+	rtw_mcache *cache;
+};
+
+static int rtw_mrc_init(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	char cache_name[IFNAMSIZ + 8 + 1];
+	int i;
+
+	minfo->mrc = rtw_malloc(sizeof(struct rtw_mrc));
+	if (!minfo->mrc)
+		return -ENOMEM;
+	minfo->mrc->idx_mask = RTW_MRC_BUCKETS - 1;
+	for (i = 0; i < RTW_MRC_BUCKETS; i++)
+		rtw_hlist_head_init(&minfo->mrc->bucket[i]);
+
+	sprintf(cache_name, "rtw_mrc_%s", ADPT_ARG(adapter));
+	minfo->mrc->cache = rtw_mcache_create(cache_name, sizeof(struct rtw_mrc_entry));
+
+	return 0;
+}
+
+static void rtw_mrc_free(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rtw_mrc *mrc = minfo->mrc;
+	struct rtw_mrc_entry *p;
+	rtw_hlist_node *np, *n;
+	int i;
+
+	if (!mrc)
+		return;
+
+	for (i = 0; i < RTW_MRC_BUCKETS; i++) {
+		rtw_hlist_for_each_entry_safe(p, np, n, &mrc->bucket[i], list) {
+			rtw_hlist_del(&p->list);
+			rtw_mcache_free(mrc->cache, p);
+		}
+	}
+
+	rtw_mcache_destroy(mrc->cache);
+
+	rtw_mfree(mrc, sizeof(struct rtw_mrc));
+	minfo->mrc = NULL;
+}
+
+/**
+ * rtw_mrc_check - Check frame in mesh received cache and add if absent.
+ *
+ * @adapter:	interface
+ * @msa:		mesh source address
+ * @seq:		mesh seq number
+ *
+ * Returns: 0 if the frame is not in the cache, nonzero otherwise.
+ *
+ * Checks using the mesh source address and the mesh sequence number if we have
+ * received this frame lately. If the frame is not in the cache, it is added to
+ * it.
+ */
+static int rtw_mrc_check(_adapter *adapter, const u8 *msa, u32 seq)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rtw_mrc *mrc = minfo->mrc;
+	int entries = 0;
+	u8 idx;
+	struct rtw_mrc_entry *p;
+	rtw_hlist_node *np, *n;
+	u8 timeout;
+
+	if (!mrc)
+		return -1;
+
+	idx = seq & mrc->idx_mask;
+	rtw_hlist_for_each_entry_safe(p, np, n, &mrc->bucket[idx], list) {
+		++entries;
+		timeout = rtw_time_after(rtw_get_current_time(), p->exp_time);
+		if (timeout || entries == RTW_MRC_QUEUE_MAX_LEN) {
+			if (!timeout)
+				minfo->mshstats.mrc_del_qlen++;
+
+			rtw_hlist_del(&p->list);
+			rtw_mcache_free(mrc->cache, p);
+			--entries;
+		} else if ((seq == p->seqnum) && _rtw_memcmp(msa, p->msa, ETH_ALEN) == _TRUE)
+			return -1;
+	}
+
+	p = rtw_mcache_alloc(mrc->cache);
+	if (!p)
+		return 0;
+
+	p->seqnum = seq;
+	p->exp_time = rtw_get_current_time() + rtw_ms_to_systime(RTW_MRC_TIMEOUT_MS);
+	_rtw_memcpy(p->msa, msa, ETH_ALEN);
+	rtw_hlist_add_head(&p->list, &mrc->bucket[idx]);
+	return 0;
+}
+
+static int rtw_mesh_decache(_adapter *adapter, const u8 *msa, u32 seq)
+{
+	return rtw_mrc_check(adapter, msa, seq);
+}
+
+#ifndef RTW_MESH_SCAN_RESULT_EXP_MS
+#define RTW_MESH_SCAN_RESULT_EXP_MS (10 * 1000)
+#endif
+
+#ifndef RTW_MESH_ACNODE_PREVENT
+#define RTW_MESH_ACNODE_PREVENT 0
+#endif
+#ifndef RTW_MESH_ACNODE_CONF_TIMEOUT_MS
+#define RTW_MESH_ACNODE_CONF_TIMEOUT_MS (20 * 1000)
+#endif
+#ifndef RTW_MESH_ACNODE_NOTIFY_TIMEOUT_MS
+#define RTW_MESH_ACNODE_NOTIFY_TIMEOUT_MS (2 * 1000)
+#endif
+
+#ifndef RTW_MESH_OFFCH_CAND
+#define RTW_MESH_OFFCH_CAND 1
+#endif
+#ifndef RTW_MESH_OFFCH_CAND_FIND_INT_MS
+#define RTW_MESH_OFFCH_CAND_FIND_INT_MS (10 * 1000)
+#endif
+
+#ifndef RTW_MESH_PEER_CONF_TIMEOUT_MS
+#define RTW_MESH_PEER_CONF_TIMEOUT_MS (20 * 1000)
+#endif
+#ifndef RTW_MESH_PEER_BLACKLIST_TIMEOUT_MS
+#define RTW_MESH_PEER_BLACKLIST_TIMEOUT_MS (20 * 1000)
+#endif
+
+#ifndef RTW_MESH_CTO_MGATE_REQUIRE
+#define RTW_MESH_CTO_MGATE_REQUIRE 0
+#endif
+#ifndef RTW_MESH_CTO_MGATE_CONF_TIMEOUT_MS
+#define RTW_MESH_CTO_MGATE_CONF_TIMEOUT_MS (20 * 1000)
+#endif
+#ifndef RTW_MESH_CTO_MGATE_BLACKLIST_TIMEOUT_MS
+#define RTW_MESH_CTO_MGATE_BLACKLIST_TIMEOUT_MS (20 * 1000)
+#endif
+
+void rtw_mesh_cfg_init_peer_sel_policy(struct rtw_mesh_cfg *mcfg)
+{
+	struct mesh_peer_sel_policy *sel_policy = &mcfg->peer_sel_policy;
+
+	sel_policy->scanr_exp_ms = RTW_MESH_SCAN_RESULT_EXP_MS;
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	sel_policy->acnode_prevent = RTW_MESH_ACNODE_PREVENT;
+	sel_policy->acnode_conf_timeout_ms = RTW_MESH_ACNODE_CONF_TIMEOUT_MS;
+	sel_policy->acnode_notify_timeout_ms = RTW_MESH_ACNODE_NOTIFY_TIMEOUT_MS;
+#endif
+
+#if CONFIG_RTW_MESH_OFFCH_CAND
+	sel_policy->offch_cand = RTW_MESH_OFFCH_CAND;
+	sel_policy->offch_find_int_ms = RTW_MESH_OFFCH_CAND_FIND_INT_MS;
+#endif
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+	sel_policy->peer_conf_timeout_ms = RTW_MESH_PEER_CONF_TIMEOUT_MS;
+	sel_policy->peer_blacklist_timeout_ms = RTW_MESH_PEER_BLACKLIST_TIMEOUT_MS;
+#endif
+
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	sel_policy->cto_mgate_require = RTW_MESH_CTO_MGATE_REQUIRE;
+	sel_policy->cto_mgate_conf_timeout_ms = RTW_MESH_CTO_MGATE_CONF_TIMEOUT_MS;
+	sel_policy->cto_mgate_blacklist_timeout_ms = RTW_MESH_CTO_MGATE_BLACKLIST_TIMEOUT_MS;
+#endif
+}
+
+void rtw_mesh_cfg_init(_adapter *adapter)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+
+	mcfg->max_peer_links = RTW_MESH_MAX_PEER_LINKS;
+	mcfg->plink_timeout = RTW_MESH_PEER_LINK_TIMEOUT;
+
+	mcfg->dot11MeshTTL = RTW_MESH_TTL;
+	mcfg->element_ttl = RTW_MESH_DEFAULT_ELEMENT_TTL;
+	mcfg->dot11MeshHWMPmaxPREQretries = RTW_MESH_MAX_PREQ_RETRIES;
+	mcfg->path_refresh_time = RTW_MESH_PATH_REFRESH_TIME;
+	mcfg->min_discovery_timeout = RTW_MESH_MIN_DISCOVERY_TIMEOUT;
+	mcfg->dot11MeshHWMPactivePathTimeout = RTW_MESH_PATH_TIMEOUT;
+	mcfg->dot11MeshHWMPpreqMinInterval = RTW_MESH_PREQ_MIN_INT;
+	mcfg->dot11MeshHWMPperrMinInterval = RTW_MESH_PERR_MIN_INT;
+	mcfg->dot11MeshHWMPnetDiameterTraversalTime = RTW_MESH_DIAM_TRAVERSAL_TIME;
+	mcfg->dot11MeshHWMPRootMode = RTW_IEEE80211_ROOTMODE_NO_ROOT;
+	mcfg->dot11MeshHWMPRannInterval = RTW_MESH_RANN_INTERVAL;
+	mcfg->dot11MeshGateAnnouncementProtocol = _FALSE;
+	mcfg->dot11MeshForwarding = _TRUE;
+	mcfg->rssi_threshold = 0;
+	mcfg->dot11MeshHWMPactivePathToRootTimeout = RTW_MESH_PATH_TO_ROOT_TIMEOUT;
+	mcfg->dot11MeshHWMProotInterval = RTW_MESH_ROOT_INTERVAL;
+	mcfg->dot11MeshHWMPconfirmationInterval = RTW_MESH_ROOT_CONFIRMATION_INTERVAL;
+	mcfg->path_gate_timeout_factor = 3;
+	rtw_mesh_cfg_init_peer_sel_policy(mcfg);
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+	mcfg->sane_metric_delta = RTW_MESH_SANE_METRIC_DELTA;
+	mcfg->max_root_add_chk_cnt = RTW_MESH_MAX_ROOT_ADD_CHK_CNT;
+#endif
+
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+	mcfg->b2u_flags_msrc = 0;
+	mcfg->b2u_flags_mfwd = RTW_MESH_B2U_GA_UCAST;
+#endif
+}
+
+void rtw_mesh_cfg_init_max_peer_links(_adapter *adapter, u8 stack_conf)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+
+	mcfg->max_peer_links = RTW_MESH_MAX_PEER_LINKS;
+
+	if (mcfg->max_peer_links > stack_conf)
+		mcfg->max_peer_links = stack_conf;
+}
+
+void rtw_mesh_cfg_init_plink_timeout(_adapter *adapter, u32 stack_conf)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+
+	mcfg->plink_timeout = stack_conf;
+}
+
+void rtw_mesh_init_mesh_info(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+
+	_rtw_memset(minfo, 0, sizeof(struct rtw_mesh_info));
+
+	rtw_mesh_plink_ctl_init(adapter);
+	
+	minfo->last_preq = rtw_get_current_time();
+	/* minfo->last_sn_update = rtw_get_current_time(); */
+	minfo->next_perr = rtw_get_current_time();
+	
+	ATOMIC_SET(&minfo->mpaths, 0);
+	rtw_mesh_pathtbl_init(adapter);
+
+	_rtw_init_queue(&minfo->mpath_tx_queue);
+	tasklet_init(&minfo->mpath_tx_tasklet
+		, (void(*)(unsigned long))mpath_tx_tasklet_hdl
+		, (unsigned long)adapter);
+
+	rtw_mrc_init(adapter);
+
+	_rtw_init_listhead(&minfo->preq_queue.list);
+	_rtw_spinlock_init(&minfo->mesh_preq_queue_lock);
+	
+	rtw_init_timer(&adapter->mesh_path_timer, adapter, rtw_ieee80211_mesh_path_timer, adapter);
+	rtw_init_timer(&adapter->mesh_path_root_timer, adapter, rtw_ieee80211_mesh_path_root_timer, adapter);
+	rtw_init_timer(&adapter->mesh_atlm_param_req_timer, adapter, rtw_mesh_atlm_param_req_timer, adapter);
+	_init_workitem(&adapter->mesh_work, rtw_mesh_work_hdl, NULL);
+}
+
+void rtw_mesh_deinit_mesh_info(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+
+	tasklet_kill(&minfo->mpath_tx_tasklet);
+	rtw_mpath_tx_queue_flush(adapter);
+	_rtw_deinit_queue(&adapter->mesh_info.mpath_tx_queue);
+
+	rtw_mrc_free(adapter);
+
+	rtw_mesh_pathtbl_unregister(adapter);
+
+	rtw_mesh_plink_ctl_deinit(adapter);
+
+	_cancel_workitem_sync(&adapter->mesh_work);
+	_cancel_timer_ex(&adapter->mesh_path_timer);
+	_cancel_timer_ex(&adapter->mesh_path_root_timer);
+	_cancel_timer_ex(&adapter->mesh_atlm_param_req_timer);
+}
+
+/**
+ * rtw_mesh_nexthop_resolve - lookup next hop; conditionally start path discovery
+ *
+ * @skb: 802.11 frame to be sent
+ * @sdata: network subif the frame will be sent through
+ *
+ * Lookup next hop for given skb and start path discovery if no
+ * forwarding information is found.
+ *
+ * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
+ * skb is freeed here if no mpath could be allocated.
+ */
+int rtw_mesh_nexthop_resolve(_adapter *adapter,
+			struct xmit_frame *xframe)
+{
+	struct pkt_attrib *attrib = &xframe->attrib;
+	struct rtw_mesh_path *mpath;
+	struct xmit_frame *xframe_to_free = NULL;
+	u8 *target_addr = attrib->mda;
+	int err = 0;
+	int ret = _SUCCESS;
+
+	rtw_rcu_read_lock();
+	err = rtw_mesh_nexthop_lookup(adapter, target_addr, attrib->msa, attrib->ra);
+	if (!err)
+		goto endlookup;
+
+	/* no nexthop found, start resolving */
+	mpath = rtw_mesh_path_lookup(adapter, target_addr);
+	if (!mpath) {
+		mpath = rtw_mesh_path_add(adapter, target_addr);
+		if (IS_ERR(mpath)) {
+			xframe->pkt = NULL; /* free pkt outside */
+			rtw_mesh_path_discard_frame(adapter, xframe);
+			err = PTR_ERR(mpath);
+			ret = _FAIL;
+			goto endlookup;
+		}
+	}
+
+	if (!(mpath->flags & RTW_MESH_PATH_RESOLVING))
+		rtw_mesh_queue_preq(mpath, RTW_PREQ_Q_F_START);
+
+	enter_critical_bh(&mpath->frame_queue.lock);
+
+	if (mpath->frame_queue_len >= RTW_MESH_FRAME_QUEUE_LEN) {
+		xframe_to_free = LIST_CONTAINOR(get_next(get_list_head(&mpath->frame_queue)), struct xmit_frame, list);
+		rtw_list_delete(&(xframe_to_free->list));
+		mpath->frame_queue_len--;
+	}
+
+	rtw_list_insert_tail(&xframe->list, get_list_head(&mpath->frame_queue));
+	mpath->frame_queue_len++;
+
+	exit_critical_bh(&mpath->frame_queue.lock);
+
+	ret = RTW_RA_RESOLVING;
+	if (xframe_to_free)
+		rtw_mesh_path_discard_frame(adapter, xframe_to_free);
+
+endlookup:
+	rtw_rcu_read_unlock();
+	return ret;
+}
+
+/**
+ * rtw_mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
+ * this function is considered "using" the associated mpath, so preempt a path
+ * refresh if this mpath expires soon.
+ *
+ * @skb: 802.11 frame to be sent
+ * @sdata: network subif the frame will be sent through
+ *
+ * Returns: 0 if the next hop was found. Nonzero otherwise.
+ */
+int rtw_mesh_nexthop_lookup(_adapter *adapter,
+	const u8 *mda, const u8 *msa, u8 *ra)
+{
+	struct rtw_mesh_path *mpath;
+	struct sta_info *next_hop;
+	const u8 *target_addr = mda;
+	int err = -ENOENT;
+
+	rtw_rcu_read_lock();
+	mpath = rtw_mesh_path_lookup(adapter, target_addr);
+
+	if (!mpath || !(mpath->flags & RTW_MESH_PATH_ACTIVE))
+		goto endlookup;
+
+	if (rtw_time_after(rtw_get_current_time(),
+		       mpath->exp_time -
+		       rtw_ms_to_systime(adapter->mesh_cfg.path_refresh_time)) &&
+	    _rtw_memcmp(adapter_mac_addr(adapter), msa, ETH_ALEN) == _TRUE &&
+	    !(mpath->flags & RTW_MESH_PATH_RESOLVING) &&
+	    !(mpath->flags & RTW_MESH_PATH_FIXED)) {
+		rtw_mesh_queue_preq(mpath, RTW_PREQ_Q_F_START | RTW_PREQ_Q_F_REFRESH);
+	}
+
+	next_hop = rtw_rcu_dereference(mpath->next_hop);
+	if (next_hop) {
+		_rtw_memcpy(ra, next_hop->cmn.mac_addr, ETH_ALEN);
+		err = 0;
+	}
+
+endlookup:
+	rtw_rcu_read_unlock();
+	return err;
+}
+
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+static bool rtw_mesh_data_bmc_to_uc(_adapter *adapter
+	, const u8 *da, const u8 *sa, const u8 *mda, const u8 *msa
+	, u8 ae_need, const u8 *ori_ta, u8 mfwd_ttl
+	, _list *b2u_list, u8 *b2u_num, u32 *b2u_mseq)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct xmit_priv *xmitpriv = &adapter->xmitpriv;
+	_irqL irqL;
+	_list *head, *list;
+	struct sta_info *sta;
+	char b2u_sta_id[NUM_STA];
+	u8 b2u_sta_num = 0;
+	bool bmc_need = _FALSE;
+	int i;
+
+	_enter_critical_bh(&stapriv->asoc_list_lock, &irqL);
+	head = &stapriv->asoc_list;
+	list = get_next(head);
+
+	while ((rtw_end_of_queue_search(head, list)) == _FALSE) {
+		int stainfo_offset;
+
+		sta = LIST_CONTAINOR(list, struct sta_info, asoc_list);
+		list = get_next(list);
+	
+		stainfo_offset = rtw_stainfo_offset(stapriv, sta);
+		if (stainfo_offset_valid(stainfo_offset))
+			b2u_sta_id[b2u_sta_num++] = stainfo_offset;
+	}
+	_exit_critical_bh(&stapriv->asoc_list_lock, &irqL);
+
+	if (!b2u_sta_num)
+		goto exit;
+
+	for (i = 0; i < b2u_sta_num; i++) {
+		struct xmit_frame *b2uframe;
+		struct pkt_attrib *attrib;
+
+		sta = rtw_get_stainfo_by_offset(stapriv, b2u_sta_id[i]);
+		if (!(sta->state & _FW_LINKED)
+			|| _rtw_memcmp(sta->cmn.mac_addr, msa, ETH_ALEN) == _TRUE
+			|| (ori_ta && _rtw_memcmp(sta->cmn.mac_addr, ori_ta, ETH_ALEN) == _TRUE)
+			|| is_broadcast_mac_addr(sta->cmn.mac_addr)
+			|| is_zero_mac_addr(sta->cmn.mac_addr))
+			continue;
+
+		b2uframe = rtw_alloc_xmitframe(xmitpriv);
+		if (!b2uframe) {
+			bmc_need = _TRUE;
+			break;
+		}
+
+		if ((*b2u_num)++ == 0 && !ori_ta) {
+			*b2u_mseq = (cpu_to_le32(adapter->mesh_info.mesh_seqnum));
+			adapter->mesh_info.mesh_seqnum++;
+		}
+
+		attrib = &b2uframe->attrib;
+
+		attrib->mb2u = 1;
+		attrib->mseq = *b2u_mseq;
+		attrib->mfwd_ttl = ori_ta ? mfwd_ttl : 0;
+		_rtw_memcpy(attrib->ra, sta->cmn.mac_addr, ETH_ALEN);
+		_rtw_memcpy(attrib->ta, adapter_mac_addr(adapter), ETH_ALEN);
+		_rtw_memcpy(attrib->mda, mda, ETH_ALEN);
+		_rtw_memcpy(attrib->msa, msa, ETH_ALEN);
+		_rtw_memcpy(attrib->dst, da, ETH_ALEN);
+		_rtw_memcpy(attrib->src, sa, ETH_ALEN);
+		attrib->mesh_frame_mode = ae_need ? MESH_UCAST_PX_DATA : MESH_UCAST_DATA;
+
+		rtw_list_insert_tail(&b2uframe->list, b2u_list);
+	}
+
+exit:
+	return bmc_need;
+}
+
+void dump_mesh_b2u_flags(void *sel, _adapter *adapter)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+
+	RTW_PRINT_SEL(sel, "%4s %4s\n", "msrc", "mfwd");
+	RTW_PRINT_SEL(sel, "0x%02x 0x%02x\n", mcfg->b2u_flags_msrc, mcfg->b2u_flags_mfwd);
+}
+#endif /* CONFIG_RTW_MESH_DATA_BMC_TO_UC */
+
+int rtw_mesh_addr_resolve(_adapter *adapter, struct xmit_frame *xframe, _pkt *pkt, _list *b2u_list)
+{
+	struct pkt_file pktfile;
+	struct ethhdr etherhdr;
+	struct pkt_attrib *attrib;
+	struct rtw_mesh_path *mpath = NULL, *mppath = NULL;
+	u8 is_da_mcast;
+	u8 ae_need;
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+	bool bmc_need = _TRUE;
+	u8 b2u_num = 0;
+	u32 b2u_mseq = 0;
+#endif
+	int res = _SUCCESS;
+
+	_rtw_open_pktfile(pkt, &pktfile);
+	if (_rtw_pktfile_read(&pktfile, (u8 *)&etherhdr, ETH_HLEN) != ETH_HLEN) {
+		res = _FAIL;
+		goto exit;
+	}
+	
+	xframe->pkt = pkt;
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+	_rtw_init_listhead(b2u_list);
+#endif
+
+	is_da_mcast = IS_MCAST(etherhdr.h_dest);
+	if (!is_da_mcast) {
+		struct sta_info *next_hop; 
+		bool mpp_lookup = 1;
+	
+		mpath = rtw_mesh_path_lookup(adapter, etherhdr.h_dest);
+		if (mpath) {
+			mpp_lookup = 0;
+			next_hop = rtw_rcu_dereference(mpath->next_hop);
+			if (!next_hop
+				|| !(mpath->flags & (RTW_MESH_PATH_ACTIVE | RTW_MESH_PATH_RESOLVING))
+			) {
+				/* mpath is not valid, search mppath */
+				mpp_lookup = 1;
+			}
+		}
+
+		if (mpp_lookup) {
+			mppath = rtw_mpp_path_lookup(adapter, etherhdr.h_dest);
+			if (mppath)
+				mppath->exp_time = rtw_get_current_time();
+		}
+
+		if (mppath && mpath)
+			rtw_mesh_path_del(adapter, mpath->dst);
+
+		ae_need = _rtw_memcmp(adapter_mac_addr(adapter), etherhdr.h_source, ETH_ALEN) == _FALSE
+			|| (mppath && _rtw_memcmp(mppath->mpp, etherhdr.h_dest, ETH_ALEN) == _FALSE);
+	} else {
+		ae_need = _rtw_memcmp(adapter_mac_addr(adapter), etherhdr.h_source, ETH_ALEN) == _FALSE;
+
+		#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+		if (rtw_msrc_b2u_policy_chk(adapter->mesh_cfg.b2u_flags_msrc, etherhdr.h_dest)) {
+			bmc_need = rtw_mesh_data_bmc_to_uc(adapter
+				, etherhdr.h_dest, etherhdr.h_source
+				, etherhdr.h_dest, adapter_mac_addr(adapter), ae_need, NULL, 0
+				, b2u_list, &b2u_num, &b2u_mseq);
+			if (bmc_need == _FALSE) {
+				res = RTW_BMC_NO_NEED;
+				goto exit;
+			}
+		}
+		#endif
+	}
+
+	attrib = &xframe->attrib;
+
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+	if (b2u_num) {
+		attrib->mb2u = 1;
+		attrib->mseq = b2u_mseq;
+	} else
+		attrib->mb2u = 0;
+#endif
+
+	attrib->mfwd_ttl = 0;
+	_rtw_memcpy(attrib->dst, etherhdr.h_dest, ETH_ALEN);
+	_rtw_memcpy(attrib->src, etherhdr.h_source, ETH_ALEN);
+	_rtw_memcpy(attrib->ta, adapter_mac_addr(adapter), ETH_ALEN);
+
+	if (is_da_mcast) {
+		attrib->mesh_frame_mode = ae_need ? MESH_BMCAST_PX_DATA : MESH_BMCAST_DATA;
+		_rtw_memcpy(attrib->ra, attrib->dst, ETH_ALEN);
+		_rtw_memcpy(attrib->msa, adapter_mac_addr(adapter), ETH_ALEN);
+	} else {
+		attrib->mesh_frame_mode = ae_need ? MESH_UCAST_PX_DATA : MESH_UCAST_DATA;
+		_rtw_memcpy(attrib->mda, (mppath && ae_need) ? mppath->mpp : attrib->dst, ETH_ALEN);
+		_rtw_memcpy(attrib->msa, adapter_mac_addr(adapter), ETH_ALEN);
+		/* RA needs to be resolved */
+		res = rtw_mesh_nexthop_resolve(adapter, xframe);
+	}
+
+exit:
+	return res;
+}
+
+s8 rtw_mesh_tx_set_whdr_mctrl_len(u8 mesh_frame_mode, struct pkt_attrib *attrib)
+{
+	u8 ret = 0;
+	switch (mesh_frame_mode) {
+	case MESH_UCAST_DATA:
+		attrib->hdrlen = WLAN_HDR_A4_QOS_LEN;
+		/* mesh flag + mesh TTL + Mesh SN. no ext addr. */
+		attrib->meshctrl_len = 6;
+		break;
+	case MESH_BMCAST_DATA:
+		attrib->hdrlen = WLAN_HDR_A3_QOS_LEN;
+		/* mesh flag + mesh TTL + Mesh SN. no ext addr. */
+		attrib->meshctrl_len = 6;
+		break;
+	case MESH_UCAST_PX_DATA:
+		attrib->hdrlen = WLAN_HDR_A4_QOS_LEN;
+		/* mesh flag + mesh TTL + Mesh SN + extaddr1 + extaddr2. */
+		attrib->meshctrl_len = 18;
+		break;
+	case MESH_BMCAST_PX_DATA:
+		attrib->hdrlen = WLAN_HDR_A3_QOS_LEN;
+		/* mesh flag + mesh TTL + Mesh SN + extaddr1 */
+		attrib->meshctrl_len = 12;
+		break;
+	default:
+		RTW_WARN("Invalid mesh frame mode:%u\n", mesh_frame_mode);
+		ret = -1;
+		break;
+	}				
+
+	return ret;
+}
+
+void rtw_mesh_tx_build_mctrl(_adapter *adapter, struct pkt_attrib *attrib, u8 *buf)
+{
+	struct rtw_ieee80211s_hdr *mctrl = (struct rtw_ieee80211s_hdr *)buf;
+
+	_rtw_memset(mctrl, 0, XATTRIB_GET_MCTRL_LEN(attrib));
+
+	if (attrib->mfwd_ttl
+		#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+		|| attrib->mb2u
+		#endif
+	) {
+		#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+		if (!attrib->mfwd_ttl)
+			mctrl->ttl = adapter->mesh_cfg.dot11MeshTTL;
+		else
+		#endif
+			mctrl->ttl = attrib->mfwd_ttl;
+
+		mctrl->seqnum = (cpu_to_le32(attrib->mseq));
+	} else {
+		mctrl->ttl = adapter->mesh_cfg.dot11MeshTTL;
+		mctrl->seqnum = (cpu_to_le32(adapter->mesh_info.mesh_seqnum));
+		adapter->mesh_info.mesh_seqnum++;
+	}
+
+	switch (attrib->mesh_frame_mode){
+	case MESH_UCAST_DATA:
+	case MESH_BMCAST_DATA:
+		break;
+	case MESH_UCAST_PX_DATA:
+		mctrl->flags |= MESH_FLAGS_AE_A5_A6;
+		_rtw_memcpy(mctrl->eaddr1, attrib->dst, ETH_ALEN);
+		_rtw_memcpy(mctrl->eaddr2, attrib->src, ETH_ALEN);
+		break;
+	case MESH_BMCAST_PX_DATA:
+		mctrl->flags |= MESH_FLAGS_AE_A4;
+		_rtw_memcpy(mctrl->eaddr1, attrib->src, ETH_ALEN);
+		break;
+	case MESH_MHOP_UCAST_ACT:
+		/* TBD */
+		break;
+	case MESH_MHOP_BMCAST_ACT:
+		/* TBD */
+		break;
+	default:
+		break;
+	}
+}
+
+u8 rtw_mesh_tx_build_whdr(_adapter *adapter, struct pkt_attrib *attrib
+	, u16 *fctrl, struct rtw_ieee80211_hdr *whdr)
+{
+	switch (attrib->mesh_frame_mode) {
+	case MESH_UCAST_DATA:		/* 1, 1, RA, TA, mDA(=DA),	mSA(=SA) */
+	case MESH_UCAST_PX_DATA:	/* 1, 1, RA, TA, mDA,		mSA,		[DA, SA] */
+		SetToDs(fctrl);
+		SetFrDs(fctrl);
+		_rtw_memcpy(whdr->addr1, attrib->ra, ETH_ALEN);
+		_rtw_memcpy(whdr->addr2, attrib->ta, ETH_ALEN);
+		_rtw_memcpy(whdr->addr3, attrib->mda, ETH_ALEN);
+		_rtw_memcpy(whdr->addr4, attrib->msa, ETH_ALEN);
+		break;
+	case MESH_BMCAST_DATA:		/* 0, 1, RA(DA), TA, mSA(SA) */
+	case MESH_BMCAST_PX_DATA:	/* 0, 1, RA(DA), TA, mSA,		[SA] */
+		SetFrDs(fctrl);
+		_rtw_memcpy(whdr->addr1, attrib->ra, ETH_ALEN);
+		_rtw_memcpy(whdr->addr2, attrib->ta, ETH_ALEN);
+		_rtw_memcpy(whdr->addr3, attrib->msa, ETH_ALEN);
+		break;
+	case MESH_MHOP_UCAST_ACT:
+		/* TBD */
+		RTW_INFO("MESH_MHOP_UCAST_ACT\n");
+		break;
+	case MESH_MHOP_BMCAST_ACT:
+		/* TBD */
+		RTW_INFO("MESH_MHOP_BMCAST_ACT\n");
+		break;
+	default:
+		RTW_WARN("Invalid mesh frame mode\n");
+		break;
+	}
+	
+	return 0;
+}
+
+int rtw_mesh_rx_data_validate_hdr(_adapter *adapter, union recv_frame *rframe, struct sta_info **sta)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct rx_pkt_attrib *rattrib = &rframe->u.hdr.attrib;
+	u8 *whdr = get_recvframe_data(rframe);
+	u8 is_ra_bmc = 0;
+	u8 a4_shift = 0;
+	u8 ps;
+	u8 *qc;
+	u8 mps_mode = RTW_MESH_PS_UNKNOWN;
+	sint ret = _FAIL;
+
+	if (!(MLME_STATE(adapter) & WIFI_ASOC_STATE))
+		goto exit;
+
+	if (!rattrib->qos)
+		goto exit;
+
+	switch (rattrib->to_fr_ds) {
+	case 1:
+		if (!IS_MCAST(GetAddr1Ptr(whdr)))
+			goto exit;
+		*sta = rtw_get_stainfo(stapriv, get_addr2_ptr(whdr));
+		if (*sta == NULL) {
+			ret = _SUCCESS; /* return _SUCCESS to drop at sta checking */
+			goto exit;
+		}
+		_rtw_memcpy(rattrib->ra, GetAddr1Ptr(whdr), ETH_ALEN);
+		_rtw_memcpy(rattrib->ta, get_addr2_ptr(whdr), ETH_ALEN);
+		_rtw_memcpy(rattrib->mda, GetAddr1Ptr(whdr), ETH_ALEN);
+		_rtw_memcpy(rattrib->msa, GetAddr3Ptr(whdr), ETH_ALEN); /* may change after checking AMSDU subframe header */
+		_rtw_memcpy(rattrib->dst, GetAddr1Ptr(whdr), ETH_ALEN);
+		_rtw_memcpy(rattrib->src, GetAddr3Ptr(whdr), ETH_ALEN); /* may change after checking mesh ctrl field */
+		_rtw_memcpy(rattrib->bssid, get_addr2_ptr(whdr), ETH_ALEN);
+		is_ra_bmc = 1;
+		break;
+	case 3:
+		if (IS_MCAST(GetAddr1Ptr(whdr)))
+			goto exit;
+		*sta = rtw_get_stainfo(stapriv, get_addr2_ptr(whdr));
+		if (*sta == NULL) {
+			ret = _SUCCESS; /* return _SUCCESS to drop at sta checking */
+			goto exit;
+		}
+		_rtw_memcpy(rattrib->ra, GetAddr1Ptr(whdr), ETH_ALEN);
+		_rtw_memcpy(rattrib->ta, get_addr2_ptr(whdr), ETH_ALEN);
+		_rtw_memcpy(rattrib->mda, GetAddr3Ptr(whdr), ETH_ALEN); /* may change after checking AMSDU subframe header */
+		_rtw_memcpy(rattrib->msa, GetAddr4Ptr(whdr), ETH_ALEN); /* may change after checking AMSDU subframe header */
+		_rtw_memcpy(rattrib->dst, GetAddr3Ptr(whdr), ETH_ALEN); /* may change after checking mesh ctrl field */
+		_rtw_memcpy(rattrib->src, GetAddr4Ptr(whdr), ETH_ALEN); /* may change after checking mesh ctrl field */
+		_rtw_memcpy(rattrib->bssid, get_addr2_ptr(whdr), ETH_ALEN);
+		a4_shift = ETH_ALEN;
+		break;
+	default:
+		goto exit;
+	}
+
+	qc = whdr + WLAN_HDR_A3_LEN + a4_shift;
+	ps = GetPwrMgt(whdr);
+	mps_mode = ps ? (is_ra_bmc || (get_mps_lv(qc)) ? RTW_MESH_PS_DSLEEP : RTW_MESH_PS_LSLEEP) : RTW_MESH_PS_ACTIVE;
+
+	if (ps) {
+		if (!((*sta)->state & WIFI_SLEEP_STATE))
+			stop_sta_xmit(adapter, *sta);
+	} else {
+		if ((*sta)->state & WIFI_SLEEP_STATE)
+			wakeup_sta_to_xmit(adapter, *sta);
+	}
+
+	if (is_ra_bmc)
+		(*sta)->nonpeer_mps = mps_mode;
+	else {
+		(*sta)->peer_mps = mps_mode;
+		if (mps_mode != RTW_MESH_PS_ACTIVE && (*sta)->nonpeer_mps == RTW_MESH_PS_ACTIVE)
+			(*sta)->nonpeer_mps = RTW_MESH_PS_DSLEEP;
+	}
+
+	if (get_frame_sub_type(whdr) & BIT(6)) {
+		/* No data, will not indicate to upper layer, temporily count it here */
+		count_rx_stats(adapter, rframe, *sta);
+		ret = RTW_RX_HANDLED;
+		goto exit;
+	}
+
+	rattrib->mesh_ctrl_present = get_mctrl_present(qc) ? 1 : 0;
+	if (!rattrib->mesh_ctrl_present)
+		goto exit;
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+
+int rtw_mesh_rx_data_validate_mctrl(_adapter *adapter, union recv_frame *rframe
+	, const struct rtw_ieee80211s_hdr *mctrl, const u8 *mda, const u8 *msa
+	, u8 *mctrl_len
+	, const u8 **da, const u8 **sa)
+{
+	struct rx_pkt_attrib *rattrib = &rframe->u.hdr.attrib;
+	u8 mlen;
+	u8 ae;
+	int ret = _SUCCESS;
+
+	ae = mctrl->flags & MESH_FLAGS_AE;
+	mlen = ae_to_mesh_ctrl_len[ae];
+	switch (rattrib->to_fr_ds) {
+	case 1:
+		*da = mda;
+		if (ae == MESH_FLAGS_AE_A4)
+			*sa = mctrl->eaddr1;
+		else if (ae == 0)
+			*sa = msa;
+		else
+			ret = _FAIL;
+		break;
+	case 3:
+		if (ae == MESH_FLAGS_AE_A5_A6) {
+			*da = mctrl->eaddr1;
+			*sa = mctrl->eaddr2;
+		} else if (ae == 0) {
+			*da = mda;
+			*sa = msa;
+		} else
+			ret = _FAIL;
+		break;
+	default:
+		ret = _FAIL;
+	}
+
+	if (ret == _FAIL) {
+		#ifdef DBG_RX_DROP_FRAME
+		RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" invalid tfDS:%u AE:%u combination ra="MAC_FMT" ta="MAC_FMT"\n"
+			, FUNC_ADPT_ARG(adapter), rattrib->to_fr_ds, ae, MAC_ARG(rattrib->ra), MAC_ARG(rattrib->ta));
+		#endif
+		*mctrl_len = 0;
+	} else
+		*mctrl_len = mlen;
+
+	return ret;	
+}
+
+inline int rtw_mesh_rx_validate_mctrl_non_amsdu(_adapter *adapter, union recv_frame *rframe)
+{
+	struct rx_pkt_attrib *rattrib = &rframe->u.hdr.attrib;
+	const u8 *da, *sa;
+	int ret;
+
+	ret = rtw_mesh_rx_data_validate_mctrl(adapter, rframe
+			, (struct rtw_ieee80211s_hdr *)(get_recvframe_data(rframe) + rattrib->hdrlen + rattrib->iv_len)
+			, rattrib->mda, rattrib->msa
+			, &rattrib->mesh_ctrl_len
+			, &da, &sa);
+
+	if (ret == _SUCCESS) {
+		_rtw_memcpy(rattrib->dst, da, ETH_ALEN);
+		_rtw_memcpy(rattrib->src, sa, ETH_ALEN);
+	}
+
+	return ret;
+}
+
+/**
+ * rtw_mesh_rx_nexthop_resolve - lookup next hop; conditionally start path discovery
+ *
+ * @skb: 802.11 frame to be sent
+ * @sdata: network subif the frame will be sent through
+ *
+ * Lookup next hop for given skb and start path discovery if no
+ * forwarding information is found.
+ *
+ * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
+ * skb is freeed here if no mpath could be allocated.
+ */
+static int rtw_mesh_rx_nexthop_resolve(_adapter *adapter,
+	const u8 *mda, const u8 *msa, u8 *ra)
+{
+	struct rtw_mesh_path *mpath;
+	struct xmit_frame *xframe_to_free = NULL;
+	int err = 0;
+	int ret = _SUCCESS;
+
+	rtw_rcu_read_lock();
+	err = rtw_mesh_nexthop_lookup(adapter, mda, msa, ra);
+	if (!err)
+		goto endlookup;
+
+	/* no nexthop found, start resolving */
+	mpath = rtw_mesh_path_lookup(adapter, mda);
+	if (!mpath) {
+		mpath = rtw_mesh_path_add(adapter, mda);
+		if (IS_ERR(mpath)) {
+			err = PTR_ERR(mpath);
+			ret = _FAIL;
+			goto endlookup;
+		}
+	}
+
+	if (!(mpath->flags & RTW_MESH_PATH_RESOLVING))
+		rtw_mesh_queue_preq(mpath, RTW_PREQ_Q_F_START);
+
+	ret = _FAIL;
+
+endlookup:
+	rtw_rcu_read_unlock();
+	return ret;
+}
+
+#define RTW_MESH_DECACHE_BMC 1
+#define RTW_MESH_DECACHE_UC 0
+
+#define RTW_MESH_FORWARD_MDA_SELF_COND 0
+#define DBG_RTW_MESH_FORWARD_MDA_SELF_COND 0
+int rtw_mesh_rx_msdu_act_check(union recv_frame *rframe
+	, const u8 *mda, const u8 *msa
+	, const u8 *da, const u8 *sa
+	, struct rtw_ieee80211s_hdr *mctrl
+	, struct xmit_frame **fwd_frame, _list *b2u_list)
+{
+	_adapter *adapter = rframe->u.hdr.adapter;
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rx_pkt_attrib *rattrib = &rframe->u.hdr.attrib;
+	struct rtw_mesh_path *mppath;
+	u8 is_mda_bmc = IS_MCAST(mda); 
+	u8 is_mda_self = !is_mda_bmc && _rtw_memcmp(mda, adapter_mac_addr(adapter), ETH_ALEN);
+	struct xmit_frame *xframe;
+	struct pkt_attrib *xattrib;
+	u8 fwd_ra[ETH_ALEN] = {0};
+	u8 fwd_mpp[ETH_ALEN] = {0}; /* forward to other gate */
+	u32 fwd_mseq;
+	int act = 0;
+	u8 ae_need;
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+	bool bmc_need = _TRUE;
+	u8 b2u_num = 0;
+#endif
+
+	/* fwd info lifetime update */
+	#if 0
+	if (!is_mda_self)
+		mDA(A3) fwinfo.lifetime
+	mSA(A4) fwinfo.lifetime
+	Precursor-to-mDA(A2) fwinfo.lifetime
+	#endif
+
+	/* update/create pxoxy info for SA, mSA */
+	if ((mctrl->flags & MESH_FLAGS_AE)
+		&& sa != msa && _rtw_memcmp(sa, msa, ETH_ALEN) == _FALSE
+	) {
+		const u8 *proxied_addr = sa;
+		const u8 *mpp_addr = msa;
+
+		rtw_rcu_read_lock();
+		mppath = rtw_mpp_path_lookup(adapter, proxied_addr);
+		if (!mppath)
+			rtw_mpp_path_add(adapter, proxied_addr, mpp_addr);
+		else {
+			enter_critical_bh(&mppath->state_lock);
+			if (_rtw_memcmp(mppath->mpp, mpp_addr, ETH_ALEN) == _FALSE)
+				_rtw_memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
+			mppath->exp_time = rtw_get_current_time();
+			exit_critical_bh(&mppath->state_lock);
+		}
+		rtw_rcu_read_unlock();
+	}
+
+	/* mSA is self, need no further process */
+	if (_rtw_memcmp(msa, adapter_mac_addr(adapter), ETH_ALEN) == _TRUE)
+		goto exit;
+
+	fwd_mseq = le32_to_cpu(mctrl->seqnum);
+
+	/* check duplicate MSDU from mSA */
+	if (((RTW_MESH_DECACHE_BMC && is_mda_bmc)
+			|| (RTW_MESH_DECACHE_UC && !is_mda_bmc))
+		&& rtw_mesh_decache(adapter, msa, fwd_mseq)
+	) {
+		minfo->mshstats.dropped_frames_duplicate++;
+		goto exit;
+	}
+
+	if (is_mda_bmc) {
+		/* mDA is bmc addr */
+		act |= RTW_RX_MSDU_ACT_INDICATE;
+		if (!mcfg->dot11MeshForwarding)
+			goto exit;
+		goto fwd_chk;
+
+	} else if (!is_mda_self) {
+		/* mDA is unicast but not self */
+		if (!mcfg->dot11MeshForwarding) {
+			rtw_mesh_path_error_tx(adapter
+				, adapter->mesh_cfg.element_ttl
+				, mda, 0
+				, WLAN_REASON_MESH_PATH_NOFORWARD
+				, rattrib->ta
+			);
+			#ifdef DBG_RX_DROP_FRAME
+			RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" mDA("MAC_FMT") not self, !dot11MeshForwarding\n"
+				, FUNC_ADPT_ARG(adapter), MAC_ARG(mda));
+			#endif
+			goto exit;
+		}
+
+		if (rtw_mesh_rx_nexthop_resolve(adapter, mda, msa, fwd_ra) != _SUCCESS) {
+			/* mDA is unknown */
+			rtw_mesh_path_error_tx(adapter
+				, adapter->mesh_cfg.element_ttl
+				, mda, 0
+				, WLAN_REASON_MESH_PATH_NOFORWARD
+				, rattrib->ta
+			);
+			#ifdef DBG_RX_DROP_FRAME
+			RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" mDA("MAC_FMT") unknown\n"
+				, FUNC_ADPT_ARG(adapter), MAC_ARG(mda));
+			#endif
+			minfo->mshstats.dropped_frames_no_route++;
+			goto exit;
+
+		} else {
+			/* mDA is known in fwd info */
+			#if 0
+			if	(TA is not in precursors)
+				goto exit;
+			#endif
+			goto fwd_chk;
+		}
+
+	} else {
+		/* mDA is self */
+		#if RTW_MESH_FORWARD_MDA_SELF_COND
+		if (da == mda
+			|| _rtw_memcmp(da, adapter_mac_addr(adapter), ETH_ALEN)
+		) {
+			/* DA is self, indicate */
+			act |= RTW_RX_MSDU_ACT_INDICATE;
+			goto exit;
+		}
+
+		if (rtw_get_iface_by_macddr(adapter, da)) {
+			/* DA is buddy, indicate */
+			act |= RTW_RX_MSDU_ACT_INDICATE;
+			#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND
+			RTW_INFO(FUNC_ADPT_FMT" DA("MAC_FMT") is buddy("ADPT_FMT")\n"
+				, FUNC_ADPT_ARG(adapter), MAC_ARG(da), ADPT_ARG(rtw_get_iface_by_macddr(adapter, da)));
+			#endif
+			goto exit;
+		}
+
+		/* DA is not self or buddy */
+		if (rtw_mesh_nexthop_lookup(adapter, da, msa, fwd_ra) == 0) {
+			/* DA is known in fwd info */
+			if (!mcfg->dot11MeshForwarding) {
+				/* path error to? */
+				#if defined(DBG_RX_DROP_FRAME) || DBG_RTW_MESH_FORWARD_MDA_SELF_COND
+				RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" DA("MAC_FMT") not self, !dot11MeshForwarding\n"
+					, FUNC_ADPT_ARG(adapter), MAC_ARG(da));
+				#endif
+				goto exit;
+			}
+			mda = da;
+			#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND
+			RTW_INFO(FUNC_ADPT_FMT" fwd to DA("MAC_FMT"), fwd_RA("MAC_FMT")\n"
+				, FUNC_ADPT_ARG(adapter), MAC_ARG(da), MAC_ARG(fwd_ra));
+			#endif
+			goto fwd_chk;
+		}
+
+		rtw_rcu_read_lock();
+		mppath = rtw_mpp_path_lookup(adapter, da);
+		if (mppath) {
+			if (_rtw_memcmp(mppath->mpp, adapter_mac_addr(adapter), ETH_ALEN) == _FALSE) {
+				/* DA is proxied by others */
+				if (!mcfg->dot11MeshForwarding) {
+					/* path error to? */
+					#if defined(DBG_RX_DROP_FRAME) || DBG_RTW_MESH_FORWARD_MDA_SELF_COND
+					RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" DA("MAC_FMT") is proxied by ("MAC_FMT"), !dot11MeshForwarding\n"
+						, FUNC_ADPT_ARG(adapter), MAC_ARG(da), MAC_ARG(mppath->mpp));
+					#endif
+					rtw_rcu_read_unlock();
+					goto exit;
+				}
+				_rtw_memcpy(fwd_mpp, mppath->mpp, ETH_ALEN);
+				mda = fwd_mpp;
+				msa = adapter_mac_addr(adapter);
+				rtw_rcu_read_unlock();
+
+				/* resolve RA */
+				if (rtw_mesh_nexthop_lookup(adapter, mda, msa, fwd_ra) != 0) {
+					minfo->mshstats.dropped_frames_no_route++;
+					#if defined(DBG_RX_DROP_FRAME) || DBG_RTW_MESH_FORWARD_MDA_SELF_COND
+					RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" DA("MAC_FMT") is proxied by ("MAC_FMT"), RA resolve fail\n"
+						, FUNC_ADPT_ARG(adapter), MAC_ARG(da), MAC_ARG(mppath->mpp));
+					#endif
+					goto exit;
+				}
+				#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND
+				RTW_INFO(FUNC_ADPT_FMT" DA("MAC_FMT") is proxied by ("MAC_FMT"), fwd_RA("MAC_FMT")\n"
+					, FUNC_ADPT_ARG(adapter), MAC_ARG(da), MAC_ARG(mppath->mpp), MAC_ARG(fwd_ra));
+				#endif
+				goto fwd_chk; /*  forward to other gate */
+			} else {
+				#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND
+				RTW_INFO(FUNC_ADPT_FMT" DA("MAC_FMT") is proxied by self\n"
+					, FUNC_ADPT_ARG(adapter), MAC_ARG(da));
+				#endif
+			}
+		}
+		rtw_rcu_read_unlock();
+
+		if (!mppath) {
+			#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND
+			RTW_INFO(FUNC_ADPT_FMT" DA("MAC_FMT") unknown\n"
+				, FUNC_ADPT_ARG(adapter), MAC_ARG(da));
+			#endif
+			/* DA is unknown */
+			#if 0 /* TODO: flags with AE bit */
+			rtw_mesh_path_error_tx(adapter
+				, adapter->mesh_cfg.element_ttl
+				, mda, adapter->mesh_info.last_sn_update
+				, WLAN_REASON_MESH_PATH_NOPROXY
+				, msa
+			);
+			#endif
+		}
+
+		/*
+		* indicate to DS for both cases:
+		* 1.) DA is proxied by self
+		* 2.) DA is unknown
+		*/
+		#endif /* RTW_MESH_FORWARD_MDA_SELF_COND */
+		act |= RTW_RX_MSDU_ACT_INDICATE;
+		goto exit;
+	}
+
+fwd_chk:
+
+	if (adapter->stapriv.asoc_list_cnt <= 1)
+		goto exit;
+
+	if (mctrl->ttl == 1) {
+		minfo->mshstats.dropped_frames_ttl++;
+		if (!act) {
+			#ifdef DBG_RX_DROP_FRAME
+			RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" ttl reaches 0, not forwarding\n"
+				, FUNC_ADPT_ARG(adapter));
+			#endif
+		}
+		goto exit;
+	}
+
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+	_rtw_init_listhead(b2u_list);
+#endif
+
+	ae_need = _rtw_memcmp(da , mda, ETH_ALEN) == _FALSE
+		|| _rtw_memcmp(sa , msa, ETH_ALEN) == _FALSE;
+
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+	if (is_mda_bmc
+		&& rtw_mfwd_b2u_policy_chk(mcfg->b2u_flags_mfwd, mda, rattrib->to_fr_ds == 3)
+	) {
+		bmc_need = rtw_mesh_data_bmc_to_uc(adapter
+			, da, sa, mda, msa, ae_need, rframe->u.hdr.psta->cmn.mac_addr, mctrl->ttl - 1
+			, b2u_list, &b2u_num, &fwd_mseq);
+	}
+
+	if (bmc_need == _TRUE)
+#endif
+	{
+		xframe = rtw_alloc_xmitframe(&adapter->xmitpriv);
+		if (!xframe) {
+			#ifdef DBG_TX_DROP_FRAME
+			RTW_INFO("DBG_TX_DROP_FRAME "FUNC_ADPT_FMT" rtw_alloc_xmitframe fail\n"
+				, FUNC_ADPT_ARG(adapter));
+			#endif
+			goto exit;
+		}
+
+		xattrib = &xframe->attrib;
+
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+		if (b2u_num)
+			xattrib->mb2u = 1;
+		else
+			xattrib->mb2u = 0;
+#endif
+		xattrib->mfwd_ttl = mctrl->ttl - 1;
+		xattrib->mseq = fwd_mseq;
+		_rtw_memcpy(xattrib->dst, da, ETH_ALEN);
+		_rtw_memcpy(xattrib->src, sa, ETH_ALEN);
+		_rtw_memcpy(xattrib->mda, mda, ETH_ALEN);
+		_rtw_memcpy(xattrib->msa, msa, ETH_ALEN);
+		_rtw_memcpy(xattrib->ta, adapter_mac_addr(adapter), ETH_ALEN);
+
+		if (is_mda_bmc) {
+			xattrib->mesh_frame_mode = ae_need ? MESH_BMCAST_PX_DATA : MESH_BMCAST_DATA;
+			_rtw_memcpy(xattrib->ra, mda, ETH_ALEN);
+		} else {
+			xattrib->mesh_frame_mode = ae_need ? MESH_UCAST_PX_DATA : MESH_UCAST_DATA;
+			_rtw_memcpy(xattrib->ra, fwd_ra, ETH_ALEN);
+		}
+
+		*fwd_frame = xframe;
+	}
+
+	act |= RTW_RX_MSDU_ACT_FORWARD;
+	if (is_mda_bmc)
+		minfo->mshstats.fwded_mcast++;
+	else
+		minfo->mshstats.fwded_unicast++;
+	minfo->mshstats.fwded_frames++;
+
+exit:
+	return act;
+}
+
+void dump_mesh_stats(void *sel, _adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rtw_mesh_stats *stats = &minfo->mshstats;
+
+	RTW_PRINT_SEL(sel, "fwd_bmc:%u\n", stats->fwded_mcast);
+	RTW_PRINT_SEL(sel, "fwd_uc:%u\n", stats->fwded_unicast);
+
+	RTW_PRINT_SEL(sel, "drop_ttl:%u\n", stats->dropped_frames_ttl);
+	RTW_PRINT_SEL(sel, "drop_no_route:%u\n", stats->dropped_frames_no_route);
+	RTW_PRINT_SEL(sel, "drop_congestion:%u\n", stats->dropped_frames_congestion);
+	RTW_PRINT_SEL(sel, "drop_dup:%u\n", stats->dropped_frames_duplicate);
+
+	RTW_PRINT_SEL(sel, "mrc_del_qlen:%u\n", stats->mrc_del_qlen);
+}
+#endif /* CONFIG_RTW_MESH */
+

+ 534 - 0
core/mesh/rtw_mesh.h

@@ -0,0 +1,534 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+#ifndef __RTW_MESH_H_
+#define __RTW_MESH_H_
+
+#ifndef CONFIG_AP_MODE
+	#error "CONFIG_RTW_MESH can't be enabled when CONFIG_AP_MODE is not defined\n"
+#endif
+
+#define RTW_MESH_TTL				31
+#define RTW_MESH_PERR_MIN_INT			100
+#define RTW_MESH_DEFAULT_ELEMENT_TTL		31
+#define RTW_MESH_RANN_INTERVAL			5000
+#define RTW_MESH_PATH_TO_ROOT_TIMEOUT		6000
+#define RTW_MESH_DIAM_TRAVERSAL_TIME		50
+#define RTW_MESH_PATH_TIMEOUT			5000
+#define RTW_MESH_PREQ_MIN_INT			10
+#define RTW_MESH_MAX_PREQ_RETRIES		4
+#define RTW_MESH_MIN_DISCOVERY_TIMEOUT 		(2 * RTW_MESH_DIAM_TRAVERSAL_TIME)
+#define RTW_MESH_ROOT_CONFIRMATION_INTERVAL	2000
+#define RTW_MESH_PATH_REFRESH_TIME		1000
+#define RTW_MESH_ROOT_INTERVAL			5000
+
+#define RTW_MESH_SANE_METRIC_DELTA		100
+#define RTW_MESH_MAX_ROOT_ADD_CHK_CNT		2
+
+#define RTW_MESH_PLINK_UNKNOWN	0
+#define RTW_MESH_PLINK_LISTEN	1
+#define RTW_MESH_PLINK_OPN_SNT	2
+#define RTW_MESH_PLINK_OPN_RCVD 3
+#define RTW_MESH_PLINK_CNF_RCVD 4
+#define RTW_MESH_PLINK_ESTAB	5
+#define RTW_MESH_PLINK_HOLDING	6
+#define RTW_MESH_PLINK_BLOCKED	7
+
+extern const char *_rtw_mesh_plink_str[];
+#define rtw_mesh_plink_str(s) ((s <= RTW_MESH_PLINK_BLOCKED) ? _rtw_mesh_plink_str[s] : _rtw_mesh_plink_str[RTW_MESH_PLINK_UNKNOWN])
+
+#define RTW_MESH_PS_UNKNOWN 0
+#define RTW_MESH_PS_ACTIVE 1
+#define RTW_MESH_PS_LSLEEP 2
+#define RTW_MESH_PS_DSLEEP 3
+
+extern const char *_rtw_mesh_ps_str[];
+#define rtw_mesh_ps_str(mps) ((mps <= RTW_MESH_PS_DSLEEP) ? _rtw_mesh_ps_str[mps] : _rtw_mesh_ps_str[RTW_MESH_PS_UNKNOWN])
+
+#define GET_MESH_CONF_ELE_PATH_SEL_PROTO_ID(_iec)		LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 0, 0, 8)
+#define GET_MESH_CONF_ELE_PATH_SEL_METRIC_ID(_iec)		LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 1, 0, 8)
+#define GET_MESH_CONF_ELE_CONGEST_CTRL_MODE_ID(_iec)	LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 2, 0, 8)
+#define GET_MESH_CONF_ELE_SYNC_METHOD_ID(_iec)			LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 3, 0, 8)
+#define GET_MESH_CONF_ELE_AUTH_PROTO_ID(_iec)			LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 4, 0, 8)
+
+#define GET_MESH_CONF_ELE_MESH_FORMATION(_iec)			LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 5, 0, 8)
+#define GET_MESH_CONF_ELE_CTO_MGATE(_iec)				LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 5, 0, 1)
+#define GET_MESH_CONF_ELE_NUM_OF_PEERINGS(_iec)			LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 5, 1, 6)
+#define GET_MESH_CONF_ELE_CTO_AS(_iec)					LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 5, 7, 1)
+
+#define GET_MESH_CONF_ELE_MESH_CAP(_iec)				LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 6, 0, 8)
+#define GET_MESH_CONF_ELE_ACCEPT_PEERINGS(_iec)			LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 6, 0, 1)
+#define GET_MESH_CONF_ELE_MCCA_SUP(_iec)				LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 6, 1, 1)
+#define GET_MESH_CONF_ELE_MCCA_EN(_iec)					LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 6, 2, 1)
+#define GET_MESH_CONF_ELE_FORWARDING(_iec)				LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 6, 3, 1)
+#define GET_MESH_CONF_ELE_MBCA_EN(_iec)					LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 6, 4, 1)
+#define GET_MESH_CONF_ELE_TBTT_ADJ(_iec)				LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 6, 5, 1)
+#define GET_MESH_CONF_ELE_PS_LEVEL(_iec)				LE_BITS_TO_1BYTE(((u8 *)(_iec)) + 6, 6, 1)
+
+#define SET_MESH_CONF_ELE_PATH_SEL_PROTO_ID(_iec, _val)		SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 0, 0, 8, _val)
+#define SET_MESH_CONF_ELE_PATH_SEL_METRIC_ID(_iec, _val)	SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 1, 0, 8, _val)
+#define SET_MESH_CONF_ELE_CONGEST_CTRL_MODE_ID(_iec, _val)	SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 2, 0, 8, _val)
+#define SET_MESH_CONF_ELE_SYNC_METHOD_ID(_iec, _val)		SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 3, 0, 8, _val)
+#define SET_MESH_CONF_ELE_AUTH_PROTO_ID(_iec, _val)			SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 4, 0, 8, _val)
+
+#define SET_MESH_CONF_ELE_CTO_MGATE(_iec, _val)				SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 5, 0, 1, _val)
+#define SET_MESH_CONF_ELE_NUM_OF_PEERINGS(_iec, _val)		SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 5, 1, 6, _val)
+#define SET_MESH_CONF_ELE_CTO_AS(_iec, _val)				SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 5, 7, 1, _val)
+
+#define SET_MESH_CONF_ELE_ACCEPT_PEERINGS(_iec, _val)		SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 6, 0, 1, _val)
+#define SET_MESH_CONF_ELE_MCCA_SUP(_iec, _val)				SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 6, 1, 1, _val)
+#define SET_MESH_CONF_ELE_MCCA_EN(_iec, _val)				SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 6, 2, 1, _val)
+#define SET_MESH_CONF_ELE_FORWARDING(_iec, _val)			SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 6, 3, 1, _val)
+#define SET_MESH_CONF_ELE_MBCA_EN(_iec, _val)				SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 6, 4, 1, _val)
+#define SET_MESH_CONF_ELE_TBTT_ADJ(_iec, _val)				SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 6, 5, 1, _val)
+#define SET_MESH_CONF_ELE_PS_LEVEL(_iec, _val)				SET_BITS_TO_LE_1BYTE(((u8 *)(_iec)) + 6, 6, 1, _val)
+
+/* Mesh flags */
+#define MESH_FLAGS_AE		0x3 /* mask */
+#define MESH_FLAGS_AE_A4 	0x1
+#define MESH_FLAGS_AE_A5_A6	0x2
+
+/* Max number of paths */
+#define RTW_MESH_MAX_PATHS 1024
+
+#define RTW_PREQ_Q_F_START	0x1
+#define RTW_PREQ_Q_F_REFRESH	0x2
+#define RTW_PREQ_Q_F_CHK	0x4
+#define RTW_PREQ_Q_F_PEER_AKA	0x8
+struct rtw_mesh_preq_queue {
+	_list list;
+	u8 dst[ETH_ALEN];
+	u8 flags;
+};
+
+extern const u8 ae_to_mesh_ctrl_len[];
+
+enum mesh_frame_type {
+	MESH_UCAST_DATA		= 0x0,
+	MESH_BMCAST_DATA	= 0x1,
+	MESH_UCAST_PX_DATA	= 0x2,
+	MESH_BMCAST_PX_DATA	= 0x3,
+	MESH_MHOP_UCAST_ACT	= 0x4,
+	MESH_MHOP_BMCAST_ACT	= 0x5,
+};
+
+enum mpath_sel_frame_type {
+	MPATH_PREQ = 0,
+	MPATH_PREP,
+	MPATH_PERR,
+	MPATH_RANN
+};
+
+/**
+ * enum rtw_mesh_deferred_task_flags - mesh deferred tasks
+ *
+ *
+ *
+ * @RTW_MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks
+ * @RTW_MESH_WORK_ROOT: the mesh root station needs to send a frame
+ * @RTW_MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other
+ * mesh nodes
+ * @RTW_MESH_WORK_MBSS_CHANGED: rebuild beacon and notify driver of BSS changes
+ */
+enum rtw_mesh_deferred_task_flags {
+	RTW_MESH_WORK_HOUSEKEEPING,
+	RTW_MESH_WORK_ROOT,
+	RTW_MESH_WORK_DRIFT_ADJUST,
+	RTW_MESH_WORK_MBSS_CHANGED,
+};
+
+#define RTW_MESH_MAX_PEER_CANDIDATES 15 /* aid consideration */
+#define RTW_MESH_MAX_PEER_LINKS 8
+#define RTW_MESH_PEER_LINK_TIMEOUT 20
+
+#define RTW_MESH_PEER_CONF_DISABLED 0 /* special time value means no confirmation ongoing */
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+#define IS_PEER_CONF_DISABLED(plink) ((plink)->peer_conf_end_time == RTW_MESH_PEER_CONF_DISABLED)
+#define IS_PEER_CONF_TIMEOUT(plink)(!IS_PEER_CONF_DISABLED(plink) && rtw_time_after(rtw_get_current_time(), (plink)->peer_conf_end_time))
+#define SET_PEER_CONF_DISABLED(plink) (plink)->peer_conf_end_time = RTW_MESH_PEER_CONF_DISABLED
+#define SET_PEER_CONF_END_TIME(plink, timeout_ms) \
+	do { \
+		(plink)->peer_conf_end_time = rtw_get_current_time() + rtw_ms_to_systime(timeout_ms); \
+		if ((plink)->peer_conf_end_time == RTW_MESH_PEER_CONF_DISABLED) \
+			(plink)->peer_conf_end_time++; \
+	} while (0)
+#else
+#define IS_PEER_CONF_DISABLED(plink) 1
+#define IS_PEER_CONF_TIMEOUT(plink) 0
+#define SET_PEER_CONF_DISABLED(plink) do {} while (0)
+#define SET_PEER_CONF_END_TIME(plink, timeout_ms) do {} while (0)
+#endif /* CONFIG_RTW_MESH_PEER_BLACKLIST */
+
+#define RTW_MESH_CTO_MGATE_CONF_DISABLED 0 /* special time value means no confirmation ongoing */
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+#define IS_CTO_MGATE_CONF_DISABLED(plink) ((plink)->cto_mgate_conf_end_time == RTW_MESH_CTO_MGATE_CONF_DISABLED)
+#define IS_CTO_MGATE_CONF_TIMEOUT(plink)(!IS_CTO_MGATE_CONF_DISABLED(plink) && rtw_time_after(rtw_get_current_time(), (plink)->cto_mgate_conf_end_time))
+#define SET_CTO_MGATE_CONF_DISABLED(plink) (plink)->cto_mgate_conf_end_time = RTW_MESH_CTO_MGATE_CONF_DISABLED
+#define SET_CTO_MGATE_CONF_END_TIME(plink, timeout_ms) \
+	do { \
+		(plink)->cto_mgate_conf_end_time = rtw_get_current_time() + rtw_ms_to_systime(timeout_ms); \
+		if ((plink)->cto_mgate_conf_end_time == RTW_MESH_CTO_MGATE_CONF_DISABLED) \
+			(plink)->cto_mgate_conf_end_time++; \
+	} while (0)
+#else
+#define IS_CTO_MGATE_CONF_DISABLED(plink) 1
+#define IS_CTO_MGATE_CONF_TIMEOUT(plink) 0
+#define SET_CTO_MGATE_CONF_DISABLED(plink) do {} while (0)
+#define SET_CTO_MGATE_CONF_END_TIME(plink, timeout_ms) do {} while (0)
+#endif /* CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST */
+
+struct mesh_plink_ent {
+	u8 valid;
+	u8 addr[ETH_ALEN];
+	u8 plink_state;
+
+#ifdef CONFIG_RTW_MESH_AEK
+	u8 aek_valid;
+	u8 aek[32];
+#endif
+
+	u16 llid;
+	u16 plid;
+#ifndef CONFIG_RTW_MESH_DRIVER_AID
+	u16 aid; /* aid assigned from upper layer */
+#endif
+	u16 peer_aid; /* aid assigned from peer */
+
+	u8 chosen_pmk[16];
+
+#ifdef CONFIG_RTW_MESH_AEK
+	u8 sel_pcs[4];
+	u8 l_nonce[32];
+	u8 p_nonce[32];
+#endif
+
+#ifdef CONFIG_RTW_MESH_DRIVER_AID
+	u8 *tx_conf_ies;
+	u16 tx_conf_ies_len;
+#endif
+	u8 *rx_conf_ies;
+	u16 rx_conf_ies_len;
+
+	struct wlan_network *scanned;
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+	systime peer_conf_end_time;
+#endif
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	systime cto_mgate_conf_end_time;
+#endif
+};
+
+#ifdef CONFIG_RTW_MESH_AEK
+#define MESH_PLINK_AEK_VALID(ent) ent->aek_valid
+#else
+#define MESH_PLINK_AEK_VALID(ent) 0
+#endif
+
+struct mesh_plink_pool {
+	_lock lock;
+	u8 num; /* current ent being used */
+	struct mesh_plink_ent ent[RTW_MESH_MAX_PEER_CANDIDATES];
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	u8 acnode_rsvd;
+#endif
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+	_queue peer_blacklist;
+#endif
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	_queue cto_mgate_blacklist;
+#endif
+};
+
+struct mesh_peer_sel_policy {
+	u32 scanr_exp_ms;
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+	u8 acnode_prevent;
+	u32 acnode_conf_timeout_ms;
+	u32 acnode_notify_timeout_ms;
+#endif
+
+#if CONFIG_RTW_MESH_OFFCH_CAND
+	u8 offch_cand;
+	u32 offch_find_int_ms; /* 0 means no offch find triggerred by driver self*/
+#endif
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+	u32 peer_conf_timeout_ms;
+	u32 peer_blacklist_timeout_ms;
+#endif
+
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+	u8 cto_mgate_require;
+	u32 cto_mgate_conf_timeout_ms;
+	u32 cto_mgate_blacklist_timeout_ms;
+#endif
+};
+
+/* b2u flags */
+#define RTW_MESH_B2U_ALL		BIT0
+#define RTW_MESH_B2U_GA_UCAST	BIT1 /* Group addressed unicast frame, forward only */
+#define RTW_MESH_B2U_BCAST		BIT2
+#define RTW_MESH_B2U_IP_MCAST	BIT3
+
+#define rtw_msrc_b2u_policy_chk(flags, mda) ( \
+	(flags & RTW_MESH_B2U_ALL) \
+	|| ((flags & RTW_MESH_B2U_BCAST) && is_broadcast_mac_addr(mda)) \
+	|| ((flags & RTW_MESH_B2U_IP_MCAST) && (IP_MCAST_MAC(mda) || ICMPV6_MCAST_MAC(mda))) \
+	)
+
+#define rtw_mfwd_b2u_policy_chk(flags, mda, ucst) ( \
+	(flags & RTW_MESH_B2U_ALL) \
+	|| ((flags & RTW_MESH_B2U_GA_UCAST) && ucst) \
+	|| ((flags & RTW_MESH_B2U_BCAST) && is_broadcast_mac_addr(mda)) \
+	|| ((flags & RTW_MESH_B2U_IP_MCAST) && (IP_MCAST_MAC(mda) || ICMPV6_MCAST_MAC(mda))) \
+	)
+
+/**
+ * @sane_metric_delta: Controlling if trigger additional path check mechanism
+ * @max_root_add_chk_cnt: The retry cnt to send additional root confirmation
+ *	PREQ through old(last) path
+ */
+struct rtw_mesh_cfg {
+	u8 max_peer_links; /* peering limit */
+	u32 plink_timeout; /* seconds */
+
+	u8 dot11MeshTTL;
+	u8 element_ttl;
+	u32 path_refresh_time;
+	u16 dot11MeshHWMPpreqMinInterval;
+	u16 dot11MeshHWMPnetDiameterTraversalTime;
+	u32 dot11MeshHWMPactivePathTimeout;
+	u8 dot11MeshHWMPmaxPREQretries;
+	u16 min_discovery_timeout;
+	u16 dot11MeshHWMPconfirmationInterval;
+	u16 dot11MeshHWMPperrMinInterval;
+	u8 dot11MeshHWMPRootMode;
+	BOOLEAN dot11MeshForwarding;
+	s32 rssi_threshold; /* in dBm, 0: no specified */
+	u16 dot11MeshHWMPRannInterval;
+	BOOLEAN dot11MeshGateAnnouncementProtocol;
+	u32 dot11MeshHWMPactivePathToRootTimeout;
+	u16 dot11MeshHWMProotInterval;
+	u8 path_gate_timeout_factor;
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+	u16 sane_metric_delta;
+	u8 max_root_add_chk_cnt;
+#endif
+
+	struct mesh_peer_sel_policy peer_sel_policy;
+
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+	u8 b2u_flags_msrc;
+	u8 b2u_flags_mfwd;
+#endif
+};
+
+struct rtw_mesh_stats {
+	u32 fwded_mcast;		/* Mesh forwarded multicast frames */
+	u32 fwded_unicast;		/* Mesh forwarded unicast frames */
+	u32 fwded_frames;		/* Mesh total forwarded frames */
+	u32 dropped_frames_ttl;	/* Not transmitted since mesh_ttl == 0*/
+	u32 dropped_frames_no_route;	/* Not transmitted, no route found */
+	u32 dropped_frames_congestion;/* Not forwarded due to congestion */
+	u32 dropped_frames_duplicate;
+
+	u32 mrc_del_qlen; /* MRC entry deleted cause by queue length limit */
+};
+
+struct rtw_mrc;
+
+struct rtw_mesh_info {
+	u8 mesh_id[NDIS_802_11_LENGTH_SSID];
+	size_t mesh_id_len;
+	/* Active Path Selection Protocol Identifier */
+	u8 mesh_pp_id;
+	/* Active Path Selection Metric Identifier */
+	u8 mesh_pm_id;
+	/* Congestion Control Mode Identifier */
+	u8 mesh_cc_id;
+	/* Synchronization Protocol Identifier */
+	u8 mesh_sp_id;
+	/* Authentication Protocol Identifier */
+	u8 mesh_auth_id;
+
+	struct mesh_plink_pool plink_ctl;
+
+	u32 mesh_seqnum;
+	/* MSTA's own hwmp sequence number */
+	u32 sn;
+	systime last_preq;
+	systime last_sn_update;
+	systime next_perr;
+	/* Last used Path Discovery ID */
+	u32 preq_id;
+	
+	ATOMIC_T mpaths;
+	struct rtw_mesh_table *mesh_paths;
+	struct rtw_mesh_table *mpp_paths;
+	int mesh_paths_generation;
+	int mpp_paths_generation;
+
+	int num_gates;
+	struct rtw_mesh_path *max_addr_gate;
+	bool max_addr_gate_is_larger_than_self;
+
+	struct rtw_mesh_stats mshstats;
+
+	_queue mpath_tx_queue;
+	u32 mpath_tx_queue_len;
+	struct tasklet_struct mpath_tx_tasklet;
+
+	struct rtw_mrc *mrc;
+
+	_lock mesh_preq_queue_lock;
+	struct rtw_mesh_preq_queue preq_queue;
+	int preq_queue_len;
+};
+
+extern const char *_action_self_protected_str[];
+#define action_self_protected_str(action) ((action < RTW_ACT_SELF_PROTECTED_NUM) ? _action_self_protected_str[action] : _action_self_protected_str[0])
+
+u8 *rtw_set_ie_mesh_id(u8 *buf, u32 *buf_len, const char *mesh_id, u8 id_len);
+u8 *rtw_set_ie_mesh_config(u8 *buf, u32 *buf_len
+	, u8 path_sel_proto, u8 path_sel_metric, u8 congest_ctl_mode, u8 sync_method, u8 auth_proto
+	, u8 num_of_peerings, bool cto_mgate, bool cto_as
+	, bool accept_peerings, bool mcca_sup, bool mcca_en, bool forwarding
+	, bool mbca_en, bool tbtt_adj, bool ps_level);
+
+int rtw_bss_is_same_mbss(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b);
+int rtw_bss_is_candidate_mesh_peer(WLAN_BSSID_EX *self, WLAN_BSSID_EX *target, u8 ch, u8 add_peer);
+
+void rtw_chk_candidate_peer_notify(_adapter *adapter, struct wlan_network *scanned);
+
+void rtw_mesh_peer_status_chk(_adapter *adapter);
+
+#if CONFIG_RTW_MESH_ACNODE_PREVENT
+void rtw_mesh_update_scanned_acnode_status(_adapter *adapter, struct wlan_network *scanned);
+bool rtw_mesh_scanned_is_acnode_confirmed(_adapter *adapter, struct wlan_network *scanned);
+bool rtw_mesh_acnode_prevent_allow_sacrifice(_adapter *adapter);
+struct sta_info *rtw_mesh_acnode_prevent_pick_sacrifice(_adapter *adapter);
+void dump_mesh_acnode_prevent_settings(void *sel, _adapter *adapter);
+#endif
+
+#if CONFIG_RTW_MESH_OFFCH_CAND
+u8 rtw_mesh_offch_candidate_accepted(_adapter *adapter);
+u8 rtw_mesh_select_operating_ch(_adapter *adapter);
+void dump_mesh_offch_cand_settings(void *sel, _adapter *adapter);
+#endif
+
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+int rtw_mesh_peer_blacklist_add(_adapter *adapter, const u8 *addr);
+int rtw_mesh_peer_blacklist_del(_adapter *adapter, const u8 *addr);
+int rtw_mesh_peer_blacklist_search(_adapter *adapter, const u8 *addr);
+void rtw_mesh_peer_blacklist_flush(_adapter *adapter);
+void dump_mesh_peer_blacklist(void *sel, _adapter *adapter);
+void dump_mesh_peer_blacklist_settings(void *sel, _adapter *adapter);
+#endif
+#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST
+u8 rtw_mesh_cto_mgate_required(_adapter *adapter);
+u8 rtw_mesh_cto_mgate_network_filter(_adapter *adapter, struct wlan_network *scanned);
+int rtw_mesh_cto_mgate_blacklist_add(_adapter *adapter, const u8 *addr);
+int rtw_mesh_cto_mgate_blacklist_del(_adapter *adapter, const u8 *addr);
+int rtw_mesh_cto_mgate_blacklist_search(_adapter *adapter, const u8 *addr);
+void rtw_mesh_cto_mgate_blacklist_flush(_adapter *adapter);
+void dump_mesh_cto_mgate_blacklist(void *sel, _adapter *adapter);
+void dump_mesh_cto_mgate_blacklist_settings(void *sel, _adapter *adapter);
+#endif
+void dump_mesh_peer_sel_policy(void *sel, _adapter *adapter);
+void dump_mesh_networks(void *sel, _adapter *adapter);
+
+void rtw_mesh_adjust_chbw(u8 req_ch, u8 *req_bw, u8 *req_offset);
+
+int rtw_sae_check_frames(_adapter *adapter, const u8 *buf, u32 len, u8 tx);
+int rtw_mesh_check_frames_tx(_adapter *adapter, const u8 **buf, size_t *len);
+int rtw_mesh_check_frames_rx(_adapter *adapter, const u8 *buf, size_t len);
+
+int rtw_mesh_on_auth(_adapter *adapter, union recv_frame *rframe);
+unsigned int on_action_self_protected(_adapter *adapter, union recv_frame *rframe);
+
+bool rtw_mesh_update_bss_peering_status(_adapter *adapter, WLAN_BSSID_EX *bss);
+bool rtw_mesh_update_bss_formation_info(_adapter *adapter, WLAN_BSSID_EX *bss);
+bool rtw_mesh_update_bss_forwarding_state(_adapter *adapter, WLAN_BSSID_EX *bss);
+
+struct mesh_plink_ent *_rtw_mesh_plink_get(_adapter *adapter, const u8 *hwaddr);
+struct mesh_plink_ent *rtw_mesh_plink_get(_adapter *adapter, const u8 *hwaddr);
+struct mesh_plink_ent *rtw_mesh_plink_get_no_estab_by_idx(_adapter *adapter, u8 idx);
+int _rtw_mesh_plink_add(_adapter *adapter, const u8 *hwaddr);
+int rtw_mesh_plink_add(_adapter *adapter, const u8 *hwaddr);
+int rtw_mesh_plink_set_state(_adapter *adapter, const u8 *hwaddr, u8 state);
+#ifdef CONFIG_RTW_MESH_AEK
+int rtw_mesh_plink_set_aek(_adapter *adapter, const u8 *hwaddr, const u8 *aek);
+#endif
+#if CONFIG_RTW_MESH_PEER_BLACKLIST
+int rtw_mesh_plink_set_peer_conf_timeout(_adapter *adapter, const u8 *hwaddr);
+#endif
+void _rtw_mesh_plink_del_ent(_adapter *adapter, struct mesh_plink_ent *ent);
+int rtw_mesh_plink_del(_adapter *adapter, const u8 *hwaddr);
+void rtw_mesh_plink_ctl_init(_adapter *adapter);
+void rtw_mesh_plink_ctl_deinit(_adapter *adapter);
+void dump_mesh_plink_ctl(void *sel, _adapter *adapter);
+
+int rtw_mesh_peer_establish(_adapter *adapter, struct mesh_plink_ent *plink, struct sta_info *sta);
+void _rtw_mesh_expire_peer_ent(_adapter *adapter, struct mesh_plink_ent *plink);
+void rtw_mesh_expire_peer(_adapter *adapter, const u8 *peer_addr);
+u8 rtw_mesh_ps_annc(_adapter *adapter, u8 ps);
+
+unsigned int on_action_mesh(_adapter *adapter, union recv_frame *rframe);
+
+void rtw_mesh_cfg_init(_adapter *adapter);
+void rtw_mesh_cfg_init_max_peer_links(_adapter *adapter, u8 stack_conf);
+void rtw_mesh_cfg_init_plink_timeout(_adapter *adapter, u32 stack_conf);
+void rtw_mesh_init_mesh_info(_adapter *adapter);
+void rtw_mesh_deinit_mesh_info(_adapter *adapter);
+
+#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
+void dump_mesh_b2u_flags(void *sel, _adapter *adapter);
+#endif
+
+int rtw_mesh_addr_resolve(_adapter *adapter, struct xmit_frame *xframe, _pkt *pkt, _list *b2u_list);
+
+s8 rtw_mesh_tx_set_whdr_mctrl_len(u8 mesh_frame_mode, struct pkt_attrib *attrib);
+void rtw_mesh_tx_build_mctrl(_adapter *adapter, struct pkt_attrib *attrib, u8 *buf);
+u8 rtw_mesh_tx_build_whdr(_adapter *adapter, struct pkt_attrib *attrib
+	, u16 *fctrl, struct rtw_ieee80211_hdr *whdr);
+
+int rtw_mesh_rx_data_validate_hdr(_adapter *adapter, union recv_frame *rframe, struct sta_info **sta);
+int rtw_mesh_rx_data_validate_mctrl(_adapter *adapter, union recv_frame *rframe
+	, const struct rtw_ieee80211s_hdr *mctrl, const u8 *mda, const u8 *msa
+	, u8 *mctrl_len, const u8 **da, const u8 **sa);
+int rtw_mesh_rx_validate_mctrl_non_amsdu(_adapter *adapter, union recv_frame *rframe);
+
+int rtw_mesh_rx_msdu_act_check(union recv_frame *rframe
+	, const u8 *mda, const u8 *msa
+	, const u8 *da, const u8 *sa
+	, struct rtw_ieee80211s_hdr *mctrl
+	, struct xmit_frame **fwd_frame, _list *b2u_list);
+
+void dump_mesh_stats(void *sel, _adapter *adapter);
+
+#if defined(PLATFORM_LINUX) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
+#define rtw_lockdep_assert_held(l) lockdep_assert_held(l)
+#define rtw_lockdep_is_held(l) lockdep_is_held(l)
+#else
+#error "TBD\n"
+#endif
+
+#include "rtw_mesh_pathtbl.h"
+#include "rtw_mesh_hwmp.h"
+#endif /* __RTW_MESH_H_ */
+

+ 1665 - 0
core/mesh/rtw_mesh_hwmp.c

@@ -0,0 +1,1665 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+#define _RTW_HWMP_C_
+
+#ifdef CONFIG_RTW_MESH
+#include <drv_types.h>
+#include <hal_data.h>
+
+#define RTW_TEST_FRAME_LEN	8192
+#define RTW_MAX_METRIC	0xffffffff
+#define RTW_ARITH_SHIFT	8
+#define RTW_LINK_FAIL_THRESH 95
+#define RTW_MAX_PREQ_QUEUE_LEN	64
+#define RTW_ATLM_REQ_CYCLE 1000
+
+#define rtw_ilog2(n)			\
+(					\
+	(n) < 2 ? 0 :			\
+	(n) & (1ULL << 63) ? 63 :	\
+	(n) & (1ULL << 62) ? 62 :	\
+	(n) & (1ULL << 61) ? 61 :	\
+	(n) & (1ULL << 60) ? 60 :	\
+	(n) & (1ULL << 59) ? 59 :	\
+	(n) & (1ULL << 58) ? 58 :	\
+	(n) & (1ULL << 57) ? 57 :	\
+	(n) & (1ULL << 56) ? 56 :	\
+	(n) & (1ULL << 55) ? 55 :	\
+	(n) & (1ULL << 54) ? 54 :	\
+	(n) & (1ULL << 53) ? 53 :	\
+	(n) & (1ULL << 52) ? 52 :	\
+	(n) & (1ULL << 51) ? 51 :	\
+	(n) & (1ULL << 50) ? 50 :	\
+	(n) & (1ULL << 49) ? 49 :	\
+	(n) & (1ULL << 48) ? 48 :	\
+	(n) & (1ULL << 47) ? 47 :	\
+	(n) & (1ULL << 46) ? 46 :	\
+	(n) & (1ULL << 45) ? 45 :	\
+	(n) & (1ULL << 44) ? 44 :	\
+	(n) & (1ULL << 43) ? 43 :	\
+	(n) & (1ULL << 42) ? 42 :	\
+	(n) & (1ULL << 41) ? 41 :	\
+	(n) & (1ULL << 40) ? 40 :	\
+	(n) & (1ULL << 39) ? 39 :	\
+	(n) & (1ULL << 38) ? 38 :	\
+	(n) & (1ULL << 37) ? 37 :	\
+	(n) & (1ULL << 36) ? 36 :	\
+	(n) & (1ULL << 35) ? 35 :	\
+	(n) & (1ULL << 34) ? 34 :	\
+	(n) & (1ULL << 33) ? 33 :	\
+	(n) & (1ULL << 32) ? 32 :	\
+	(n) & (1ULL << 31) ? 31 :	\
+	(n) & (1ULL << 30) ? 30 :	\
+	(n) & (1ULL << 29) ? 29 :	\
+	(n) & (1ULL << 28) ? 28 :	\
+	(n) & (1ULL << 27) ? 27 :	\
+	(n) & (1ULL << 26) ? 26 :	\
+	(n) & (1ULL << 25) ? 25 :	\
+	(n) & (1ULL << 24) ? 24 :	\
+	(n) & (1ULL << 23) ? 23 :	\
+	(n) & (1ULL << 22) ? 22 :	\
+	(n) & (1ULL << 21) ? 21 :	\
+	(n) & (1ULL << 20) ? 20 :	\
+	(n) & (1ULL << 19) ? 19 :	\
+	(n) & (1ULL << 18) ? 18 :	\
+	(n) & (1ULL << 17) ? 17 :	\
+	(n) & (1ULL << 16) ? 16 :	\
+	(n) & (1ULL << 15) ? 15 :	\
+	(n) & (1ULL << 14) ? 14 :	\
+	(n) & (1ULL << 13) ? 13 :	\
+	(n) & (1ULL << 12) ? 12 :	\
+	(n) & (1ULL << 11) ? 11 :	\
+	(n) & (1ULL << 10) ? 10 :	\
+	(n) & (1ULL <<  9) ?  9 :	\
+	(n) & (1ULL <<  8) ?  8 :	\
+	(n) & (1ULL <<  7) ?  7 :	\
+	(n) & (1ULL <<  6) ?  6 :	\
+	(n) & (1ULL <<  5) ?  5 :	\
+	(n) & (1ULL <<  4) ?  4 :	\
+	(n) & (1ULL <<  3) ?  3 :	\
+	(n) & (1ULL <<  2) ?  2 :	\
+	1				\
+)
+
+enum rtw_mpath_frame_type {
+	RTW_MPATH_PREQ = 0,
+	RTW_MPATH_PREP,
+	RTW_MPATH_PERR,
+	RTW_MPATH_RANN
+};
+
+static inline u32 rtw_u32_field_get(const u8 *preq_elem, int shift, BOOLEAN ae)
+{
+	if (ae)
+		shift += 6;
+	return LE_BITS_TO_4BYTE(preq_elem + shift, 0, 32);
+}
+
+static inline u16 rtw_u16_field_get(const u8 *preq_elem, int shift, BOOLEAN ae)
+{
+	if (ae)
+		shift += 6;
+	return LE_BITS_TO_2BYTE(preq_elem + shift, 0, 16);
+}
+
+/* HWMP IE processing macros */
+#define RTW_AE_F			(1<<6)
+#define RTW_AE_F_SET(x)			(*x & RTW_AE_F)
+#define RTW_PREQ_IE_FLAGS(x)		(*(x))
+#define RTW_PREQ_IE_HOPCOUNT(x)		(*(x + 1))
+#define RTW_PREQ_IE_TTL(x)		(*(x + 2))
+#define RTW_PREQ_IE_PREQ_ID(x)		rtw_u32_field_get(x, 3, 0)
+#define RTW_PREQ_IE_ORIG_ADDR(x)	(x + 7)
+#define RTW_PREQ_IE_ORIG_SN(x)		rtw_u32_field_get(x, 13, 0)
+#define RTW_PREQ_IE_LIFETIME(x)		rtw_u32_field_get(x, 17, RTW_AE_F_SET(x))
+#define RTW_PREQ_IE_METRIC(x) 		rtw_u32_field_get(x, 21, RTW_AE_F_SET(x))
+#define RTW_PREQ_IE_TARGET_F(x)		(*(RTW_AE_F_SET(x) ? x + 32 : x + 26))
+#define RTW_PREQ_IE_TARGET_ADDR(x) 	(RTW_AE_F_SET(x) ? x + 33 : x + 27)
+#define RTW_PREQ_IE_TARGET_SN(x) 	rtw_u32_field_get(x, 33, RTW_AE_F_SET(x))
+
+#define RTW_PREP_IE_FLAGS(x)		RTW_PREQ_IE_FLAGS(x)
+#define RTW_PREP_IE_HOPCOUNT(x)		RTW_PREQ_IE_HOPCOUNT(x)
+#define RTW_PREP_IE_TTL(x)		RTW_PREQ_IE_TTL(x)
+#define RTW_PREP_IE_ORIG_ADDR(x)	(RTW_AE_F_SET(x) ? x + 27 : x + 21)
+#define RTW_PREP_IE_ORIG_SN(x)		rtw_u32_field_get(x, 27, RTW_AE_F_SET(x))
+#define RTW_PREP_IE_LIFETIME(x)		rtw_u32_field_get(x, 13, RTW_AE_F_SET(x))
+#define RTW_PREP_IE_METRIC(x)		rtw_u32_field_get(x, 17, RTW_AE_F_SET(x))
+#define RTW_PREP_IE_TARGET_ADDR(x)	(x + 3)
+#define RTW_PREP_IE_TARGET_SN(x)	rtw_u32_field_get(x, 9, 0)
+
+#define RTW_PERR_IE_TTL(x)		(*(x))
+#define RTW_PERR_IE_TARGET_FLAGS(x)	(*(x + 2))
+#define RTW_PERR_IE_TARGET_ADDR(x)	(x + 3)
+#define RTW_PERR_IE_TARGET_SN(x)	rtw_u32_field_get(x, 9, 0)
+#define RTW_PERR_IE_TARGET_RCODE(x)	rtw_u16_field_get(x, 13, 0)
+
+#define RTW_TU_TO_SYSTIME(x)	(rtw_us_to_systime((x) * 1024))
+#define RTW_TU_TO_EXP_TIME(x)	(rtw_get_current_time() + RTW_TU_TO_SYSTIME(x))
+#define RTW_MSEC_TO_TU(x) (x*1000/1024)
+#define RTW_SN_GT(x, y) ((s32)(y - x) < 0)
+#define RTW_SN_LT(x, y) ((s32)(x - y) < 0)
+#define RTW_MAX_SANE_SN_DELTA 32
+
+static inline u32 RTW_SN_DELTA(u32 x, u32 y)
+{
+	return x >= y ? x - y : y - x;
+}
+
+#define rtw_net_traversal_jiffies(adapter) \
+	rtw_ms_to_systime(adapter->mesh_cfg.dot11MeshHWMPnetDiameterTraversalTime)
+#define rtw_default_lifetime(adapter) \
+	RTW_MSEC_TO_TU(adapter->mesh_cfg.dot11MeshHWMPactivePathTimeout)
+#define rtw_min_preq_int_jiff(adapter) \
+	(rtw_ms_to_systime(adapter->mesh_cfg.dot11MeshHWMPpreqMinInterval))
+#define rtw_max_preq_retries(adapter) (adapter->mesh_cfg.dot11MeshHWMPmaxPREQretries)
+#define rtw_disc_timeout_jiff(adapter) \
+	rtw_ms_to_systime(adapter->mesh_cfg.min_discovery_timeout)
+#define rtw_root_path_confirmation_jiffies(adapter) \
+	rtw_ms_to_systime(adapter->mesh_cfg.dot11MeshHWMPconfirmationInterval)
+
+static inline BOOLEAN rtw_ether_addr_equal(const u8 *addr1, const u8 *addr2)
+{
+	return _rtw_memcmp(addr1, addr2, ETH_ALEN);
+}
+
+#ifdef PLATFORM_LINUX
+#define rtw_print_ratelimit()	printk_ratelimit()
+#define rtw_mod_timer(ptimer, expires) mod_timer(&(ptimer)->timer, expires)
+#else
+
+#endif
+
+#define RTW_MESH_EWMA_PRECISION 20
+#define RTW_MESH_EWMA_WEIGHT_RCP 8
+#define RTW_TOTAL_PKT_MIN_THRESHOLD 1
+inline void rtw_ewma_err_rate_init(struct rtw_ewma_err_rate *e)
+{
+	e->internal = 0;
+}
+inline unsigned long rtw_ewma_err_rate_read(struct rtw_ewma_err_rate *e)
+{
+	return e->internal >> (RTW_MESH_EWMA_PRECISION);
+}
+inline void rtw_ewma_err_rate_add(struct rtw_ewma_err_rate *e,
+				  unsigned long val)
+{
+	unsigned long internal = e->internal;
+	unsigned long weight_rcp = rtw_ilog2(RTW_MESH_EWMA_WEIGHT_RCP);
+	unsigned long precision = RTW_MESH_EWMA_PRECISION;
+
+	(e->internal) = internal ? (((internal << weight_rcp) - internal) +
+			(val << precision)) >> weight_rcp :
+			(val << precision);
+}
+
+static const u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static int rtw_mesh_path_sel_frame_tx(enum rtw_mpath_frame_type mpath_action, u8 flags,
+				      const u8 *originator_addr, u32 originator_sn,
+				      u8 target_flags, const u8 *target,
+				      u32 target_sn, const u8 *da, u8 hopcount, u8 ttl,
+				      u32 lifetime, u32 metric, u32 preq_id, 
+				      _adapter *adapter)
+{
+	struct xmit_priv *pxmitpriv = &(adapter->xmitpriv);
+	struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
+	struct xmit_frame *pmgntframe = NULL;
+	struct rtw_ieee80211_hdr *pwlanhdr = NULL;
+	struct pkt_attrib *pattrib = NULL;
+	u8 category = RTW_WLAN_CATEGORY_MESH;
+	u8 action = RTW_ACT_MESH_HWMP_PATH_SELECTION;
+	u16 *fctrl = NULL;
+	u8 *pos, ie_len;
+
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return -1;
+
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(adapter, pattrib);
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pos = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pos;
+
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(adapter), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(pos, WIFI_ACTION);
+
+	pos += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pos = rtw_set_fixed_ie(pos, 1, &(category), &(pattrib->pktlen));
+	pos = rtw_set_fixed_ie(pos, 1, &(action), &(pattrib->pktlen));
+
+	switch (mpath_action) {
+	case RTW_MPATH_PREQ:
+		RTW_HWMP_DBG("sending PREQ to "MAC_FMT"\n", MAC_ARG(target));
+		ie_len = 37;
+		pattrib->pktlen += (ie_len + 2);
+		*pos++ = WLAN_EID_PREQ;
+		break;
+	case RTW_MPATH_PREP:
+		RTW_HWMP_DBG("sending PREP to "MAC_FMT"\n", MAC_ARG(originator_addr));
+		ie_len = 31;
+		pattrib->pktlen += (ie_len + 2);
+		*pos++ = WLAN_EID_PREP;
+		break;
+	case RTW_MPATH_RANN:
+		RTW_HWMP_DBG("sending RANN from "MAC_FMT"\n", MAC_ARG(originator_addr));
+		ie_len = sizeof(struct rtw_ieee80211_rann_ie);
+		pattrib->pktlen += (ie_len + 2);
+		*pos++ = WLAN_EID_RANN;
+		break;
+	default:
+		rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
+		rtw_free_xmitframe(pxmitpriv, pmgntframe);
+		return _FAIL;
+	}
+	*pos++ = ie_len;
+	*pos++ = flags;
+	*pos++ = hopcount;
+	*pos++ = ttl;
+	if (mpath_action == RTW_MPATH_PREP) {
+		_rtw_memcpy(pos, target, ETH_ALEN);
+		pos += ETH_ALEN;
+		*(u32 *)pos = cpu_to_le32(target_sn);
+		pos += 4;
+	} else {
+		if (mpath_action == RTW_MPATH_PREQ) {
+			*(u32 *)pos = cpu_to_le32(preq_id);
+			pos += 4;
+		}
+		_rtw_memcpy(pos, originator_addr, ETH_ALEN);
+		pos += ETH_ALEN;
+		*(u32 *)pos = cpu_to_le32(originator_sn);
+		pos += 4;
+	}
+	*(u32 *)pos = cpu_to_le32(lifetime);
+	pos += 4;
+	*(u32 *)pos = cpu_to_le32(metric);
+	pos += 4;
+	if (mpath_action == RTW_MPATH_PREQ) {
+		*pos++ = 1; /* support only 1 destination now */
+		*pos++ = target_flags;
+		_rtw_memcpy(pos, target, ETH_ALEN);
+		pos += ETH_ALEN;
+		*(u32 *)pos = cpu_to_le32(target_sn);
+		pos += 4;
+	} else if (mpath_action == RTW_MPATH_PREP) {
+		_rtw_memcpy(pos, originator_addr, ETH_ALEN);
+		pos += ETH_ALEN;
+		*(u32 *)pos = cpu_to_le32(originator_sn);
+		pos += 4;
+	}
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+	dump_mgntframe(adapter, pmgntframe);
+	return 0;
+}
+
+int rtw_mesh_path_error_tx(_adapter *adapter,
+			   u8 ttl, const u8 *target, u32 target_sn,
+			   u16 perr_reason_code, const u8 *ra)
+{
+
+	struct xmit_priv *pxmitpriv = &(adapter->xmitpriv);
+	struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
+	struct xmit_frame *pmgntframe = NULL;
+	struct rtw_ieee80211_hdr *pwlanhdr = NULL;
+	struct pkt_attrib *pattrib = NULL;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	u8 category = RTW_WLAN_CATEGORY_MESH;
+	u8 action = RTW_ACT_MESH_HWMP_PATH_SELECTION;
+	u8 *pos, ie_len;
+	u16 *fctrl = NULL;
+
+	if (rtw_time_before(rtw_get_current_time(), minfo->next_perr))
+		return -1;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return -1;
+
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(adapter, pattrib);
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pos = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pos;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(adapter), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(pos, WIFI_ACTION);
+
+	pos += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pos = rtw_set_fixed_ie(pos, 1, &(category), &(pattrib->pktlen));
+	pos = rtw_set_fixed_ie(pos, 1, &(action), &(pattrib->pktlen));
+
+	ie_len = 15;
+	pattrib->pktlen += (2 + ie_len);
+	*pos++ = WLAN_EID_PERR;
+	*pos++ = ie_len;
+	/* ttl */
+	*pos++ = ttl;
+	/* The Number of Destinations N */
+	*pos++ = 1;
+	/* Flags format | B7 | B6 | B5:B0 | = | rsvd | AE | rsvd | */
+	*pos = 0;
+	pos++;
+	_rtw_memcpy(pos, target, ETH_ALEN);
+	pos += ETH_ALEN;
+	*(u32 *)pos = cpu_to_le32(target_sn);
+	pos += 4;
+	*(u16 *)pos = cpu_to_le16(perr_reason_code);
+
+	adapter->mesh_info.next_perr = RTW_TU_TO_EXP_TIME(
+				adapter->mesh_cfg.dot11MeshHWMPperrMinInterval);
+	pattrib->last_txcmdsz = pattrib->pktlen;
+	/* Send directly. Rewrite it if deferred tx is needed */
+	dump_mgntframe(adapter, pmgntframe);
+
+	RTW_HWMP_DBG("TX PERR toward "MAC_FMT", ra = "MAC_FMT"\n", MAC_ARG(target), MAC_ARG(ra));
+	
+	return 0;
+}
+
+static u32 rtw_get_vht_bitrate(u8 mcs, u8 bw, u8 nss, u8 sgi)
+{
+	static const u32 base[4][10] = {
+		{   6500000,
+		   13000000,
+		   19500000,
+		   26000000,
+		   39000000,
+		   52000000,
+		   58500000,
+		   65000000,
+		   78000000,
+		/* not in the spec, but some devices use this: */
+		   86500000,
+		},
+		{  13500000,
+		   27000000,
+		   40500000,
+		   54000000,
+		   81000000,
+		  108000000,
+		  121500000,
+		  135000000,
+		  162000000,
+		  180000000,
+		},
+		{  29300000,
+		   58500000,
+		   87800000,
+		  117000000,
+		  175500000,
+		  234000000,
+		  263300000,
+		  292500000,
+		  351000000,
+		  390000000,
+		},
+		{  58500000,
+		  117000000,
+		  175500000,
+		  234000000,
+		  351000000,
+		  468000000,
+		  526500000,
+		  585000000,
+		  702000000,
+		  780000000,
+		},
+	};
+	u32 bitrate;
+	int bw_idx;
+
+	if (mcs > 9) {
+		RTW_HWMP_INFO("Invalid mcs = %d\n", mcs);
+		return 0;
+	}
+
+	if (nss > 4 || nss < 1) {
+		RTW_HWMP_INFO("Now only support nss = 1, 2, 3, 4\n");
+	}
+
+	switch (bw) {
+	case CHANNEL_WIDTH_160:
+		bw_idx = 3;
+		break;
+	case CHANNEL_WIDTH_80:
+		bw_idx = 2;
+		break;
+	case CHANNEL_WIDTH_40:
+		bw_idx = 1;
+		break;
+	case CHANNEL_WIDTH_20:
+		bw_idx = 0;
+		break;
+	default:
+		RTW_HWMP_INFO("bw = %d currently not supported\n", bw);
+		return 0;
+	}
+
+	bitrate = base[bw_idx][mcs];
+	bitrate *= nss;
+
+	if (sgi)
+		bitrate = (bitrate / 9) * 10;
+
+	/* do NOT round down here */
+	return (bitrate + 50000) / 100000;
+}
+
+static u32 rtw_get_ht_bitrate(u8 mcs, u8 bw, u8 sgi)
+{
+	int modulation, streams, bitrate;
+
+	/* the formula below does only work for MCS values smaller than 32 */
+	if (mcs >= 32) {
+		RTW_HWMP_INFO("Invalid mcs = %d\n", mcs);
+		return 0;
+	}
+
+	if (bw > 1) {
+		RTW_HWMP_INFO("Now HT only support bw = 0(20Mhz), 1(40Mhz)\n");
+		return 0;
+	}
+
+	modulation = mcs & 7;
+	streams = (mcs >> 3) + 1;
+
+	bitrate = (bw == 1) ? 13500000 : 6500000;
+
+	if (modulation < 4)
+		bitrate *= (modulation + 1);
+	else if (modulation == 4)
+		bitrate *= (modulation + 2);
+	else
+		bitrate *= (modulation + 3);
+
+	bitrate *= streams;
+
+	if (sgi)
+		bitrate = (bitrate / 9) * 10;
+
+	/* do NOT round down here */
+	return (bitrate + 50000) / 100000;
+}
+
+/**
+ * @bw: 0(20Mhz), 1(40Mhz), 2(80Mhz), 3(160Mhz)
+ * @rate_idx: DESC_RATEXXXX & 0x7f
+ * @sgi: DESC_RATEXXXX >> 7
+ * Returns: bitrate in 100kbps
+ */
+static u32 rtw_desc_rate_to_bitrate(u8 bw, u8 rate_idx, u8 sgi)
+{
+	u32 bitrate;
+
+	if (rate_idx <= DESC_RATE54M){
+		u16 ofdm_rate[12] = {10, 20, 55, 110,
+			60, 90, 120, 180, 240, 360, 480, 540};
+		bitrate = ofdm_rate[rate_idx];
+	} else if ((DESC_RATEMCS0 <= rate_idx) &&
+		   (rate_idx <= DESC_RATEMCS31)) {
+		u8 mcs = rate_idx - DESC_RATEMCS0;
+		bitrate = rtw_get_ht_bitrate(mcs, bw, sgi);
+	} else if ((DESC_RATEVHTSS1MCS0 <= rate_idx) &&
+		   (rate_idx <= DESC_RATEVHTSS4MCS9)) {
+		u8 mcs = (rate_idx - DESC_RATEVHTSS1MCS0) % 10;
+		u8 nss = ((rate_idx - DESC_RATEVHTSS1MCS0) / 10) + 1;
+		bitrate = rtw_get_vht_bitrate(mcs, bw, nss, sgi);
+	} else {
+		/* 60Ghz ??? */
+		bitrate = 1;
+	}
+
+	return bitrate;
+}
+
+static u32 rtw_airtime_link_metric_get(_adapter *adapter, struct sta_info *sta)
+{
+	struct dm_struct *dm = adapter_to_phydm(adapter);
+	int device_constant = phydm_get_plcp(dm, sta->cmn.mac_id) << RTW_ARITH_SHIFT;
+	u32 test_frame_len = RTW_TEST_FRAME_LEN << RTW_ARITH_SHIFT;
+	u32 s_unit = 1 << RTW_ARITH_SHIFT;
+	u32 err;
+	u16 rate;
+	u32 tx_time, estimated_retx;
+	u64 result;
+	/* The fail_avg should <= 100 here */
+	u32 fail_avg = (u32)rtw_ewma_err_rate_read(&sta->metrics.err_rate);
+
+	if (fail_avg > RTW_LINK_FAIL_THRESH)
+		return RTW_MAX_METRIC;
+
+	rate = sta->metrics.data_rate;
+	/* rate unit is 100Kbps, min rate = 10 */
+	if (rate < 10) {
+		RTW_HWMP_INFO("rate = %d\n", rate);
+		return RTW_MAX_METRIC;
+	}
+
+	err = (fail_avg << RTW_ARITH_SHIFT) / 100;
+
+	/* test_frame_len*10 to adjust the unit of rate(100kbps/unit) */
+	tx_time = (device_constant + 10 * test_frame_len / rate);
+	estimated_retx = ((1 << (2 * RTW_ARITH_SHIFT)) / (s_unit - err));
+	result = (tx_time * estimated_retx) >> (2 * RTW_ARITH_SHIFT);
+	/* Convert us to 0.01 TU(10.24us). x/10.24 = x*100/1024 */
+	result = (result * 100) >> 10;
+
+	return (u32)result;
+}
+
+void rtw_ieee80211s_update_metric(_adapter *adapter, u8 mac_id,
+				  u8 per, u8 rate,
+				  u8 bw, u8 total_pkt)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+	struct sta_info *sta;
+	u8 rate_idx;
+	u8 sgi;
+
+	sta = macid_ctl->sta[mac_id];
+	if (!sta)
+		return;
+
+	/* if RA, use reported rate */
+	if (adapter->fix_rate == 0xff) {
+		rate_idx = rate & 0x7f;
+		sgi = rate >> 7;
+	} else {
+		rate_idx = adapter->fix_rate & 0x7f;
+		sgi = adapter->fix_rate >> 7;
+	}
+	sta->metrics.data_rate = rtw_desc_rate_to_bitrate(bw, rate_idx, sgi);
+
+	if (total_pkt < RTW_TOTAL_PKT_MIN_THRESHOLD)
+		return;
+
+	/* TBD: sta->metrics.overhead = phydm_get_plcp(void *dm_void, u16 macid); */
+	sta->metrics.total_pkt = total_pkt;
+
+	rtw_ewma_err_rate_add(&sta->metrics.err_rate, per);
+	if (rtw_ewma_err_rate_read(&sta->metrics.err_rate) > 
+			RTW_LINK_FAIL_THRESH)
+		rtw_mesh_plink_broken(sta);
+}
+
+static void rtw_hwmp_preq_frame_process(_adapter *adapter,
+					struct rtw_ieee80211_hdr_3addr *mgmt,
+					const u8 *preq_elem, u32 originator_metric)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rtw_mesh_cfg *mshcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_path *path = NULL;
+	const u8 *target_addr, *originator_addr;
+	const u8 *da;
+	u8 target_flags, ttl, flags, to_gate_ask = 0;
+	u32 originator_sn, target_sn, lifetime, target_metric = 0;
+	BOOLEAN reply = _FALSE;
+	BOOLEAN forward = _TRUE;
+	BOOLEAN preq_is_gate;
+
+	/* Update target SN, if present */
+	target_addr = RTW_PREQ_IE_TARGET_ADDR(preq_elem);
+	originator_addr = RTW_PREQ_IE_ORIG_ADDR(preq_elem);
+	target_sn = RTW_PREQ_IE_TARGET_SN(preq_elem);
+	originator_sn = RTW_PREQ_IE_ORIG_SN(preq_elem);
+	target_flags = RTW_PREQ_IE_TARGET_F(preq_elem);
+	/* PREQ gate announcements */
+	flags = RTW_PREQ_IE_FLAGS(preq_elem);
+	preq_is_gate = !!(flags & RTW_IEEE80211_PREQ_IS_GATE_FLAG);
+
+	RTW_HWMP_DBG("received PREQ from "MAC_FMT"\n", MAC_ARG(originator_addr));
+
+	if (rtw_ether_addr_equal(target_addr, adapter_mac_addr(adapter))) {
+		RTW_HWMP_DBG("PREQ is for us\n");
+#ifdef CONFIG_RTW_MESH_ON_DMD_GANN
+		rtw_rcu_read_lock();
+		path = rtw_mesh_path_lookup(adapter, originator_addr);
+		if (path) {
+			if (preq_is_gate)
+				rtw_mesh_path_add_gate(path);
+			else if (path->is_gate) {
+				enter_critical_bh(&path->state_lock);
+				rtw_mesh_gate_del(adapter->mesh_info.mesh_paths, path);
+				exit_critical_bh(&path->state_lock);
+			}
+		}
+		path = NULL;
+		rtw_rcu_read_unlock();
+#endif
+		forward = _FALSE;
+		reply = _TRUE;
+		to_gate_ask = 1;
+		target_metric = 0;
+		if (rtw_time_after(rtw_get_current_time(), minfo->last_sn_update +
+					rtw_net_traversal_jiffies(adapter)) ||
+		    rtw_time_before(rtw_get_current_time(), minfo->last_sn_update)) {
+			++minfo->sn;
+			minfo->last_sn_update = rtw_get_current_time();
+		}
+		target_sn = minfo->sn;
+	} else if (is_broadcast_mac_addr(target_addr) &&
+		   (target_flags & RTW_IEEE80211_PREQ_TO_FLAG)) {
+		rtw_rcu_read_lock();
+		path = rtw_mesh_path_lookup(adapter, originator_addr);
+		if (path) {
+			if (flags & RTW_IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
+				reply = _TRUE;
+				target_addr = adapter_mac_addr(adapter);
+				target_sn = ++minfo->sn;
+				target_metric = 0;
+				minfo->last_sn_update = rtw_get_current_time();
+			}
+
+			if (preq_is_gate) {
+				lifetime = RTW_PREQ_IE_LIFETIME(preq_elem);
+				path->gate_ann_int = lifetime;
+				path->gate_asked = false;
+				rtw_mesh_path_add_gate(path);
+			} else if (path->is_gate) {
+				enter_critical_bh(&path->state_lock);
+				rtw_mesh_gate_del(adapter->mesh_info.mesh_paths, path);
+				exit_critical_bh(&path->state_lock);
+			}
+		}
+		rtw_rcu_read_unlock();
+	} else {
+		rtw_rcu_read_lock();
+#ifdef CONFIG_RTW_MESH_ON_DMD_GANN
+		path = rtw_mesh_path_lookup(adapter, originator_addr);
+		if (path) {
+			if (preq_is_gate)
+				rtw_mesh_path_add_gate(path);
+			else if (path->is_gate) {
+				enter_critical_bh(&path->state_lock);
+				rtw_mesh_gate_del(adapter->mesh_info.mesh_paths, path);
+				exit_critical_bh(&path->state_lock);
+			}
+		}
+		path = NULL;
+#endif
+		path = rtw_mesh_path_lookup(adapter, target_addr);
+		if (path) {
+			if ((!(path->flags & RTW_MESH_PATH_SN_VALID)) ||
+					RTW_SN_LT(path->sn, target_sn)) {
+				path->sn = target_sn;
+				path->flags |= RTW_MESH_PATH_SN_VALID;
+			} else if ((!(target_flags & RTW_IEEE80211_PREQ_TO_FLAG)) &&
+					(path->flags & RTW_MESH_PATH_ACTIVE)) {
+				reply = _TRUE;
+				target_metric = path->metric;
+				target_sn = path->sn;
+				/* Case E2 of sec 13.10.9.3 IEEE 802.11-2012*/
+				target_flags |= RTW_IEEE80211_PREQ_TO_FLAG;
+			}
+		}
+		rtw_rcu_read_unlock();
+	}
+
+	if (reply) {
+		lifetime = RTW_PREQ_IE_LIFETIME(preq_elem);
+		ttl = mshcfg->element_ttl;
+		if (ttl != 0 && !to_gate_ask) {
+			RTW_HWMP_DBG("replying to the PREQ\n");
+			rtw_mesh_path_sel_frame_tx(RTW_MPATH_PREP, 0, originator_addr,
+						   originator_sn, 0, target_addr,
+						   target_sn, mgmt->addr2, 0, ttl,
+						   lifetime, target_metric, 0,
+						   adapter);
+		} else if (ttl != 0 && to_gate_ask) {
+			RTW_HWMP_DBG("replying to the PREQ (PREQ for us)\n");
+			if (mshcfg->dot11MeshGateAnnouncementProtocol) {
+				/* BIT 7 is used to identify the prep is from mesh gate */
+				to_gate_ask = RTW_IEEE80211_PREQ_IS_GATE_FLAG | BIT(7);
+			} else {
+				to_gate_ask = 0;
+			}
+
+			rtw_mesh_path_sel_frame_tx(RTW_MPATH_PREP, to_gate_ask, originator_addr,
+						   originator_sn, 0, target_addr,
+						   target_sn, mgmt->addr2, 0, ttl,
+						   lifetime, target_metric, 0,
+						   adapter);
+		} else {
+			minfo->mshstats.dropped_frames_ttl++;
+		}
+	}
+
+	if (forward && mshcfg->dot11MeshForwarding) {
+		u32 preq_id;
+		u8 hopcount;
+
+		ttl = RTW_PREQ_IE_TTL(preq_elem);
+		lifetime = RTW_PREQ_IE_LIFETIME(preq_elem);
+		if (ttl <= 1) {
+			minfo->mshstats.dropped_frames_ttl++;
+			return;
+		}
+		RTW_HWMP_DBG("forwarding the PREQ from "MAC_FMT"\n", MAC_ARG(originator_addr));
+		--ttl;
+		preq_id = RTW_PREQ_IE_PREQ_ID(preq_elem);
+		hopcount = RTW_PREQ_IE_HOPCOUNT(preq_elem) + 1;
+		da = (path && path->is_root) ?
+			path->rann_snd_addr : bcast_addr;
+
+		if (flags & RTW_IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
+			target_addr = RTW_PREQ_IE_TARGET_ADDR(preq_elem);
+			target_sn = RTW_PREQ_IE_TARGET_SN(preq_elem);
+		}
+
+		rtw_mesh_path_sel_frame_tx(RTW_MPATH_PREQ, flags, originator_addr,
+					   originator_sn, target_flags, target_addr,
+					   target_sn, da, hopcount, ttl, lifetime,
+					   originator_metric, preq_id, adapter);
+		if (!is_multicast_mac_addr(da))
+			minfo->mshstats.fwded_unicast++;
+		else
+			minfo->mshstats.fwded_mcast++;
+		minfo->mshstats.fwded_frames++;
+	}
+}
+
+static inline struct sta_info *
+rtw_next_hop_deref_protected(struct rtw_mesh_path *path)
+{
+	return rtw_rcu_dereference_protected(path->next_hop,
+					 rtw_lockdep_is_held(&path->state_lock));
+}
+
+static void rtw_hwmp_prep_frame_process(_adapter *adapter,
+					struct rtw_ieee80211_hdr_3addr *mgmt,
+					const u8 *prep_elem, u32 metric)
+{
+	struct rtw_mesh_cfg *mshcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_stats *mshstats = &adapter->mesh_info.mshstats;
+	struct rtw_mesh_path *path;
+	const u8 *target_addr, *originator_addr;
+	u8 ttl, hopcount, flags;
+	u8 next_hop[ETH_ALEN];
+	u32 target_sn, originator_sn, lifetime;
+
+	RTW_HWMP_DBG("received PREP from "MAC_FMT"\n",
+		  MAC_ARG(RTW_PREP_IE_TARGET_ADDR(prep_elem)));
+
+	originator_addr = RTW_PREP_IE_ORIG_ADDR(prep_elem);
+	if (rtw_ether_addr_equal(originator_addr, adapter_mac_addr(adapter))) {
+		/* destination, no forwarding required */
+		rtw_rcu_read_lock();
+		target_addr = RTW_PREP_IE_TARGET_ADDR(prep_elem);
+		path = rtw_mesh_path_lookup(adapter, target_addr);
+		if (path && path->gate_asked) {
+			flags = RTW_PREP_IE_FLAGS(prep_elem);
+			if (flags & BIT(7)) {
+				enter_critical_bh(&path->state_lock);
+				path->gate_asked = false;
+				exit_critical_bh(&path->state_lock);
+				if (!(flags & RTW_IEEE80211_PREQ_IS_GATE_FLAG)) {
+					enter_critical_bh(&path->state_lock);
+					rtw_mesh_gate_del(adapter->mesh_info.mesh_paths, path);
+					exit_critical_bh(&path->state_lock);
+				}
+			}
+		}
+
+		rtw_rcu_read_unlock();
+		return;
+	}
+
+	if (!mshcfg->dot11MeshForwarding)
+		return;
+
+	ttl = RTW_PREP_IE_TTL(prep_elem);
+	if (ttl <= 1) {
+		mshstats->dropped_frames_ttl++;
+		return;
+	}
+
+	rtw_rcu_read_lock();
+	path = rtw_mesh_path_lookup(adapter, originator_addr);
+	if (path)
+		enter_critical_bh(&path->state_lock);
+	else
+		goto fail;
+	if (!(path->flags & RTW_MESH_PATH_ACTIVE)) {
+		exit_critical_bh(&path->state_lock);
+		goto fail;
+	}
+	_rtw_memcpy(next_hop, rtw_next_hop_deref_protected(path)->cmn.mac_addr, ETH_ALEN);
+	exit_critical_bh(&path->state_lock);
+	--ttl;
+	flags = RTW_PREP_IE_FLAGS(prep_elem);
+	lifetime = RTW_PREP_IE_LIFETIME(prep_elem);
+	hopcount = RTW_PREP_IE_HOPCOUNT(prep_elem) + 1;
+	target_addr = RTW_PREP_IE_TARGET_ADDR(prep_elem);
+	target_sn = RTW_PREP_IE_TARGET_SN(prep_elem);
+	originator_sn = RTW_PREP_IE_ORIG_SN(prep_elem);
+
+	rtw_mesh_path_sel_frame_tx(RTW_MPATH_PREP, flags, originator_addr, originator_sn, 0,
+				   target_addr, target_sn, next_hop, hopcount,
+				   ttl, lifetime, metric, 0, adapter);
+	rtw_rcu_read_unlock();
+
+	mshstats->fwded_unicast++;
+	mshstats->fwded_frames++;
+	return;
+
+fail:
+	rtw_rcu_read_unlock();
+	mshstats->dropped_frames_no_route++;
+}
+
+static void rtw_hwmp_perr_frame_process(_adapter *adapter,
+					struct rtw_ieee80211_hdr_3addr *mgmt,
+					const u8 *perr_elem)
+{
+	struct rtw_mesh_cfg *mshcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_stats *mshstats = &adapter->mesh_info.mshstats;
+	struct rtw_mesh_path *path;
+	u8 ttl;
+	const u8 *ta, *target_addr;
+	u32 target_sn;
+	u16 perr_reason_code;
+
+	ta = mgmt->addr2;
+	ttl = RTW_PERR_IE_TTL(perr_elem);
+	if (ttl <= 1) {
+		mshstats->dropped_frames_ttl++;
+		return;
+	}
+	ttl--;
+	target_addr = RTW_PERR_IE_TARGET_ADDR(perr_elem);
+	target_sn = RTW_PERR_IE_TARGET_SN(perr_elem);
+	perr_reason_code = RTW_PERR_IE_TARGET_RCODE(perr_elem);
+
+	RTW_HWMP_DBG("received PERR toward target "MAC_FMT"\n", MAC_ARG(target_addr));
+
+	rtw_rcu_read_lock();
+	path = rtw_mesh_path_lookup(adapter, target_addr);
+	if (path) {
+		struct sta_info *sta;
+
+		enter_critical_bh(&path->state_lock);
+		sta = rtw_next_hop_deref_protected(path);
+		if (path->flags & RTW_MESH_PATH_ACTIVE &&
+		    rtw_ether_addr_equal(ta, sta->cmn.mac_addr) &&
+		    !(path->flags & RTW_MESH_PATH_FIXED) &&
+		    (!(path->flags & RTW_MESH_PATH_SN_VALID) ||
+		    RTW_SN_GT(target_sn, path->sn)  || target_sn == 0)) {
+			path->flags &= ~RTW_MESH_PATH_ACTIVE;
+			if (target_sn != 0)
+				path->sn = target_sn;
+			else
+				path->sn += 1;
+			exit_critical_bh(&path->state_lock);
+			if (!mshcfg->dot11MeshForwarding)
+				goto endperr;
+			rtw_mesh_path_error_tx(adapter, ttl, target_addr,
+					       target_sn, perr_reason_code,
+					       bcast_addr);
+		} else
+			exit_critical_bh(&path->state_lock);
+	}
+endperr:
+	rtw_rcu_read_unlock();
+}
+
+static void rtw_hwmp_rann_frame_process(_adapter *adapter,
+					struct rtw_ieee80211_hdr_3addr *mgmt,
+					const struct rtw_ieee80211_rann_ie *rann)
+{
+	struct sta_info *sta;
+	struct sta_priv *pstapriv = &adapter->stapriv;
+	struct rtw_mesh_cfg *mshcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_stats *mshstats = &adapter->mesh_info.mshstats;
+	struct rtw_mesh_path *path;
+	u8 ttl, flags, hopcount;
+	const u8 *originator_addr;
+	u32 originator_sn, metric, metric_txsta, interval;
+	BOOLEAN root_is_gate;
+
+	ttl = rann->rann_ttl;
+	flags = rann->rann_flags;
+	root_is_gate = !!(flags & RTW_RANN_FLAG_IS_GATE);
+	originator_addr = rann->rann_addr;
+	originator_sn = le32_to_cpu(rann->rann_seq);
+	interval = le32_to_cpu(rann->rann_interval);
+	hopcount = rann->rann_hopcount;
+	hopcount++;
+	metric = le32_to_cpu(rann->rann_metric);
+
+	/*  Ignore our own RANNs */
+	if (rtw_ether_addr_equal(originator_addr, adapter_mac_addr(adapter)))
+		return;
+
+	RTW_HWMP_DBG("received RANN from "MAC_FMT" via neighbour "MAC_FMT" (is_gate=%d)\n",
+		  MAC_ARG(originator_addr), MAC_ARG(mgmt->addr2), root_is_gate);
+
+	rtw_rcu_read_lock();
+	sta = rtw_get_stainfo(pstapriv, mgmt->addr2);
+	if (!sta) {
+		rtw_rcu_read_unlock();
+		return;
+	}
+
+	metric_txsta = rtw_airtime_link_metric_get(adapter, sta);
+
+	path = rtw_mesh_path_lookup(adapter, originator_addr);
+	if (!path) {
+		path = rtw_mesh_path_add(adapter, originator_addr);
+		if (IS_ERR(path)) {
+			rtw_rcu_read_unlock();
+			mshstats->dropped_frames_no_route++;
+			return;
+		}
+	}
+
+	if (!(RTW_SN_LT(path->sn, originator_sn)) &&
+	    !(path->sn == originator_sn && metric < path->rann_metric)) {
+		rtw_rcu_read_unlock();
+		return;
+	}
+
+	if ((!(path->flags & (RTW_MESH_PATH_ACTIVE | RTW_MESH_PATH_RESOLVING)) ||
+	     (rtw_time_after(rtw_get_current_time(), path->last_preq_to_root +
+				  rtw_root_path_confirmation_jiffies(adapter)) ||
+	     rtw_time_before(rtw_get_current_time(), path->last_preq_to_root))) &&
+	     !(path->flags & RTW_MESH_PATH_FIXED) && (ttl != 0)) {
+		u8 preq_node_flag = RTW_PREQ_Q_F_START | RTW_PREQ_Q_F_REFRESH;
+
+		RTW_HWMP_DBG("time to refresh root path "MAC_FMT"\n",
+			  MAC_ARG(originator_addr));
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+		if (RTW_SN_LT(path->sn, originator_sn) &&
+		    (path->rann_metric + mshcfg->sane_metric_delta < metric) &&
+		    _rtw_memcmp(bcast_addr, path->rann_snd_addr, ETH_ALEN) == _FALSE) {
+			RTW_HWMP_DBG("Trigger additional check for root "
+				     "confirm PREQ. rann_snd_addr = "MAC_FMT
+				     "add_chk_rann_snd_addr= "MAC_FMT"\n",
+					MAC_ARG(mgmt->addr2),
+					MAC_ARG(path->rann_snd_addr));
+			_rtw_memcpy(path->add_chk_rann_snd_addr,
+				    path->rann_snd_addr, ETH_ALEN);
+			preq_node_flag |= RTW_PREQ_Q_F_CHK;
+			
+		}
+#endif
+		rtw_mesh_queue_preq(path, preq_node_flag);
+		path->last_preq_to_root = rtw_get_current_time();
+	}
+
+	path->sn = originator_sn;
+	path->rann_metric = metric + metric_txsta;
+	path->is_root = _TRUE;
+	/* Recording RANNs sender address to send individually
+	 * addressed PREQs destined for root mesh STA */
+	_rtw_memcpy(path->rann_snd_addr, mgmt->addr2, ETH_ALEN);
+
+	if (root_is_gate) {
+		path->gate_ann_int = interval;
+		path->gate_asked = false;
+		rtw_mesh_path_add_gate(path);
+	} else if (path->is_gate) {
+		enter_critical_bh(&path->state_lock);
+		rtw_mesh_gate_del(adapter->mesh_info.mesh_paths, path);
+		exit_critical_bh(&path->state_lock);
+	}
+
+	if (ttl <= 1) {
+		mshstats->dropped_frames_ttl++;
+		rtw_rcu_read_unlock();
+		return;
+	}
+	ttl--;
+
+	if (mshcfg->dot11MeshForwarding) {
+		rtw_mesh_path_sel_frame_tx(RTW_MPATH_RANN, flags, originator_addr,
+					   originator_sn, 0, NULL, 0, bcast_addr,
+					   hopcount, ttl, interval,
+					   metric + metric_txsta, 0, adapter);
+	}
+
+	rtw_rcu_read_unlock();
+}
+
+static u32 rtw_hwmp_route_info_get(_adapter *adapter,
+				   struct rtw_ieee80211_hdr_3addr *mgmt,
+				   const u8 *hwmp_ie, enum rtw_mpath_frame_type action)
+{
+	struct rtw_mesh_path *path;
+	struct sta_priv *pstapriv = &adapter->stapriv;
+	struct sta_info *sta;
+	BOOLEAN fresh_info;
+	const u8 *originator_addr, *ta;
+	u32 originator_sn, originator_metric;
+	unsigned long originator_lifetime, exp_time;
+	u32 last_hop_metric, new_metric;
+	BOOLEAN process = _TRUE;
+
+	rtw_rcu_read_lock();
+	sta = rtw_get_stainfo(pstapriv, mgmt->addr2);
+	if (!sta) {
+		rtw_rcu_read_unlock();
+		return 0;
+	}
+
+	last_hop_metric = rtw_airtime_link_metric_get(adapter, sta);
+	/* Update and check originator routing info */
+	fresh_info = _TRUE;
+
+	switch (action) {
+	case RTW_MPATH_PREQ:
+		originator_addr = RTW_PREQ_IE_ORIG_ADDR(hwmp_ie);
+		originator_sn = RTW_PREQ_IE_ORIG_SN(hwmp_ie);
+		originator_lifetime = RTW_PREQ_IE_LIFETIME(hwmp_ie);
+		originator_metric = RTW_PREQ_IE_METRIC(hwmp_ie);
+		break;
+	case RTW_MPATH_PREP:
+		/* Note: For coding, the naming is not consist with spec */
+		originator_addr = RTW_PREP_IE_TARGET_ADDR(hwmp_ie);
+		originator_sn = RTW_PREP_IE_TARGET_SN(hwmp_ie);
+		originator_lifetime = RTW_PREP_IE_LIFETIME(hwmp_ie);
+		originator_metric = RTW_PREP_IE_METRIC(hwmp_ie);
+		break;
+	default:
+		rtw_rcu_read_unlock();
+		return 0;
+	}
+	new_metric = originator_metric + last_hop_metric;
+	if (new_metric < originator_metric)
+		new_metric = RTW_MAX_METRIC;
+	exp_time = RTW_TU_TO_EXP_TIME(originator_lifetime);
+
+	if (rtw_ether_addr_equal(originator_addr, adapter_mac_addr(adapter))) {
+		process = _FALSE;
+		fresh_info = _FALSE;
+	} else {
+		path = rtw_mesh_path_lookup(adapter, originator_addr);
+		if (path) {
+			enter_critical_bh(&path->state_lock);
+			if (path->flags & RTW_MESH_PATH_FIXED)
+				fresh_info = _FALSE;
+			else if ((path->flags & RTW_MESH_PATH_ACTIVE) &&
+			    (path->flags & RTW_MESH_PATH_SN_VALID)) {
+				if (RTW_SN_GT(path->sn, originator_sn) ||
+				    (path->sn == originator_sn &&
+				     new_metric >= path->metric)) {
+					process = _FALSE;
+					fresh_info = _FALSE;
+				}
+			} else if (!(path->flags & RTW_MESH_PATH_ACTIVE)) {
+				BOOLEAN have_sn, newer_sn, bounced;
+
+				have_sn = path->flags & RTW_MESH_PATH_SN_VALID;
+				newer_sn = have_sn && RTW_SN_GT(originator_sn, path->sn);
+				bounced = have_sn &&
+					  (RTW_SN_DELTA(originator_sn, path->sn) >
+							RTW_MAX_SANE_SN_DELTA);
+
+				if (!have_sn || newer_sn) {
+				} else if (bounced) {
+				} else {
+					process = _FALSE;
+					fresh_info = _FALSE;
+				}
+			}
+		} else {
+			path = rtw_mesh_path_add(adapter, originator_addr);
+			if (IS_ERR(path)) {
+				rtw_rcu_read_unlock();
+				return 0;
+			}
+			enter_critical_bh(&path->state_lock);
+		}
+
+		if (fresh_info) {
+			rtw_mesh_path_assign_nexthop(path, sta);
+			path->flags |= RTW_MESH_PATH_SN_VALID;
+			path->metric = new_metric;
+			path->sn = originator_sn;
+			path->exp_time = rtw_time_after(path->exp_time, exp_time)
+					  ?  path->exp_time : exp_time;
+			rtw_mesh_path_activate(path);
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+			if (path->is_root && (action == RTW_MPATH_PREP)) {
+				_rtw_memcpy(path->rann_snd_addr, 
+				mgmt->addr2, ETH_ALEN);
+				path->rann_metric = new_metric;
+			}
+#endif
+			exit_critical_bh(&path->state_lock);
+			rtw_mesh_path_tx_pending(path);
+		} else
+			exit_critical_bh(&path->state_lock);
+	}
+
+	/* Update and check transmitter routing info */
+	ta = mgmt->addr2;
+	if (rtw_ether_addr_equal(originator_addr, ta))
+		fresh_info = _FALSE;
+	else {
+		fresh_info = _TRUE;
+
+		path = rtw_mesh_path_lookup(adapter, ta);
+		if (path) {
+			enter_critical_bh(&path->state_lock);
+			if ((path->flags & RTW_MESH_PATH_FIXED) ||
+				((path->flags & RTW_MESH_PATH_ACTIVE) &&
+					(last_hop_metric > path->metric)))
+				fresh_info = _FALSE;
+		} else {
+			path = rtw_mesh_path_add(adapter, ta);
+			if (IS_ERR(path)) {
+				rtw_rcu_read_unlock();
+				return 0;
+			}
+			enter_critical_bh(&path->state_lock);
+		}
+
+		if (fresh_info) {
+			rtw_mesh_path_assign_nexthop(path, sta);
+			path->metric = last_hop_metric;
+			path->exp_time = rtw_time_after(path->exp_time, exp_time)
+					  ?  path->exp_time : exp_time;
+			rtw_mesh_path_activate(path);
+			exit_critical_bh(&path->state_lock);
+			rtw_mesh_path_tx_pending(path);
+		} else
+			exit_critical_bh(&path->state_lock);
+	}
+
+	rtw_rcu_read_unlock();
+
+	return process ? new_metric : 0;
+}
+
+static void rtw_mesh_rx_hwmp_frame_cnts(_adapter *adapter, u8 *addr)
+{
+	struct sta_info *sta;
+
+	sta = rtw_get_stainfo(&adapter->stapriv, addr);
+	if (sta)
+		sta->sta_stats.rx_hwmp_pkts++;
+}
+
+void rtw_mesh_rx_path_sel_frame(_adapter *adapter, union recv_frame *rframe)
+{
+	struct mesh_plink_ent *plink = NULL;
+	struct rtw_ieee802_11_elems elems;
+	u32 path_metric;
+	struct rx_pkt_attrib *attrib = &rframe->u.hdr.attrib;
+	u8 *pframe = rframe->u.hdr.rx_data, *start;
+	uint frame_len = rframe->u.hdr.len, left;
+	struct rtw_ieee80211_hdr_3addr *frame_hdr = (struct rtw_ieee80211_hdr_3addr *)pframe;
+	u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+	ParseRes parse_res;
+
+	plink = rtw_mesh_plink_get(adapter, get_addr2_ptr(pframe));
+	if (!plink || plink->plink_state != RTW_MESH_PLINK_ESTAB)
+		return;
+
+	rtw_mesh_rx_hwmp_frame_cnts(adapter, get_addr2_ptr(pframe));
+
+	/* Mesh action frame IE offset = 2 */
+	attrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+	left = frame_len - attrib->hdrlen - attrib->iv_len - attrib->icv_len - 2;
+	start = pframe + attrib->hdrlen + 2;
+
+	parse_res = rtw_ieee802_11_parse_elems(start, left, &elems, 1);
+	if (parse_res == ParseFailed)
+		RTW_HWMP_INFO(FUNC_ADPT_FMT" Path Select Frame ParseFailed\n"
+			, FUNC_ADPT_ARG(adapter));
+	else if (parse_res == ParseUnknown)
+		RTW_HWMP_INFO(FUNC_ADPT_FMT" Path Select Frame ParseUnknown\n"
+			, FUNC_ADPT_ARG(adapter));
+
+	if (elems.preq) {
+		if (elems.preq_len != 37)
+			/* Right now we support just 1 destination and no AE */
+			return;
+		path_metric = rtw_hwmp_route_info_get(adapter, frame_hdr, elems.preq,
+						  MPATH_PREQ);
+		if (path_metric)
+			rtw_hwmp_preq_frame_process(adapter, frame_hdr, elems.preq,
+						path_metric);
+	}
+	if (elems.prep) {
+		if (elems.prep_len != 31)
+			/* Right now we support no AE */
+			return;
+		path_metric = rtw_hwmp_route_info_get(adapter, frame_hdr, elems.prep,
+						  MPATH_PREP);
+		if (path_metric)
+			rtw_hwmp_prep_frame_process(adapter, frame_hdr, elems.prep,
+						path_metric);
+	}
+	if (elems.perr) {
+		if (elems.perr_len != 15)
+			/* Right now we support only one destination per PERR */
+			return;
+		rtw_hwmp_perr_frame_process(adapter, frame_hdr, elems.perr);
+	}
+	if (elems.rann)
+		rtw_hwmp_rann_frame_process(adapter, frame_hdr, (struct rtw_ieee80211_rann_ie *)elems.rann);
+}
+
+void rtw_mesh_queue_preq(struct rtw_mesh_path *path, u8 flags)
+{
+	_adapter *adapter = path->adapter;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rtw_mesh_preq_queue *preq_node;
+
+	preq_node = rtw_malloc(sizeof(struct rtw_mesh_preq_queue));
+	if (!preq_node) {
+		RTW_HWMP_INFO("could not allocate PREQ node\n");
+		return;
+	}
+
+	enter_critical_bh(&minfo->mesh_preq_queue_lock);
+	if (minfo->preq_queue_len == RTW_MAX_PREQ_QUEUE_LEN) {
+		exit_critical_bh(&minfo->mesh_preq_queue_lock);
+		rtw_mfree(preq_node, sizeof(struct rtw_mesh_preq_queue));
+		if (rtw_print_ratelimit())
+			RTW_HWMP_INFO("PREQ node queue full\n");
+		return;
+	}
+
+	_rtw_spinlock(&path->state_lock);
+	if (path->flags & RTW_MESH_PATH_REQ_QUEUED) {
+		_rtw_spinunlock(&path->state_lock);
+		exit_critical_bh(&minfo->mesh_preq_queue_lock);
+		rtw_mfree(preq_node, sizeof(struct rtw_mesh_preq_queue));
+		return;
+	}
+
+	_rtw_memcpy(preq_node->dst, path->dst, ETH_ALEN);
+	preq_node->flags = flags;
+
+	path->flags |= RTW_MESH_PATH_REQ_QUEUED;
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+	if (flags & RTW_PREQ_Q_F_CHK)
+		path->flags |= RTW_MESH_PATH_ROOT_ADD_CHK;
+#endif
+	if (flags & RTW_PREQ_Q_F_PEER_AKA)
+		path->flags |= RTW_MESH_PATH_PEER_AKA;
+	_rtw_spinunlock(&path->state_lock);
+
+	rtw_list_insert_tail(&preq_node->list, &minfo->preq_queue.list);
+	++minfo->preq_queue_len;
+	exit_critical_bh(&minfo->mesh_preq_queue_lock);
+
+	if (rtw_time_after(rtw_get_current_time(), minfo->last_preq + rtw_min_preq_int_jiff(adapter)))
+		rtw_mesh_work(&adapter->mesh_work);
+
+	else if (rtw_time_before(rtw_get_current_time(), minfo->last_preq)) {
+		/* systime wrapped around issue */
+		minfo->last_preq = rtw_get_current_time() - rtw_min_preq_int_jiff(adapter) - 1;
+		rtw_mesh_work(&adapter->mesh_work);
+	} else
+		rtw_mod_timer(&adapter->mesh_path_timer, minfo->last_preq +
+					rtw_min_preq_int_jiff(adapter) + 1);
+}
+
+static const u8 *rtw_hwmp_preq_da(struct rtw_mesh_path *path,
+			    BOOLEAN is_root_add_chk, BOOLEAN da_is_peer)
+{
+	const u8 *da;
+
+	if (da_is_peer)
+		da = path->dst;
+	else if (path->is_root)
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+		da = is_root_add_chk ? path->add_chk_rann_snd_addr:
+				       path->rann_snd_addr;
+#else
+		da = path->rann_snd_addr;
+#endif
+	else
+		da = bcast_addr;
+
+	return da;
+}
+
+void rtw_mesh_path_start_discovery(_adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rtw_mesh_cfg *mshcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_preq_queue *preq_node;
+	struct rtw_mesh_path *path;
+	u8 ttl, target_flags = 0;
+	const u8 *da;
+	u32 lifetime;
+	u8 flags = 0;
+	BOOLEAN is_root_add_chk = _FALSE;
+	BOOLEAN da_is_peer;
+
+	enter_critical_bh(&minfo->mesh_preq_queue_lock);
+	if (!minfo->preq_queue_len ||
+		rtw_time_before(rtw_get_current_time(), minfo->last_preq +
+				rtw_min_preq_int_jiff(adapter))) {
+		exit_critical_bh(&minfo->mesh_preq_queue_lock);
+		return;
+	}
+
+	preq_node = rtw_list_first_entry(&minfo->preq_queue.list,
+			struct rtw_mesh_preq_queue, list);
+	rtw_list_delete(&preq_node->list); /* list_del_init(&preq_node->list); */
+	--minfo->preq_queue_len;
+	exit_critical_bh(&minfo->mesh_preq_queue_lock);
+
+	rtw_rcu_read_lock();
+	path = rtw_mesh_path_lookup(adapter, preq_node->dst);
+	if (!path)
+		goto enddiscovery;
+
+	enter_critical_bh(&path->state_lock);
+	if (path->flags & (RTW_MESH_PATH_DELETED | RTW_MESH_PATH_FIXED)) {
+		exit_critical_bh(&path->state_lock);
+		goto enddiscovery;
+	}
+	path->flags &= ~RTW_MESH_PATH_REQ_QUEUED;
+	if (preq_node->flags & RTW_PREQ_Q_F_START) {
+		if (path->flags & RTW_MESH_PATH_RESOLVING) {
+			exit_critical_bh(&path->state_lock);
+			goto enddiscovery;
+		} else {
+			path->flags &= ~RTW_MESH_PATH_RESOLVED;
+			path->flags |= RTW_MESH_PATH_RESOLVING;
+			path->discovery_retries = 0;
+			path->discovery_timeout = rtw_disc_timeout_jiff(adapter);
+		}
+	} else if (!(path->flags & RTW_MESH_PATH_RESOLVING) ||
+			path->flags & RTW_MESH_PATH_RESOLVED) {
+		path->flags &= ~RTW_MESH_PATH_RESOLVING;
+		exit_critical_bh(&path->state_lock);
+		goto enddiscovery;
+	}
+
+	minfo->last_preq = rtw_get_current_time();
+
+	if (rtw_time_after(rtw_get_current_time(), minfo->last_sn_update +
+				rtw_net_traversal_jiffies(adapter)) ||
+	    rtw_time_before(rtw_get_current_time(), minfo->last_sn_update)) {
+		++minfo->sn;
+		minfo->last_sn_update = rtw_get_current_time();
+	}
+	lifetime = rtw_default_lifetime(adapter);
+	ttl = mshcfg->element_ttl;
+	if (ttl == 0) {
+		minfo->mshstats.dropped_frames_ttl++;
+		exit_critical_bh(&path->state_lock);
+		goto enddiscovery;
+	}
+
+	if (preq_node->flags & RTW_PREQ_Q_F_REFRESH)
+		target_flags |= RTW_IEEE80211_PREQ_TO_FLAG;
+	else
+		target_flags &= ~RTW_IEEE80211_PREQ_TO_FLAG;
+
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+	is_root_add_chk = !!(path->flags & RTW_MESH_PATH_ROOT_ADD_CHK);
+#endif
+	da_is_peer = !!(path->flags & RTW_MESH_PATH_PEER_AKA);
+	exit_critical_bh(&path->state_lock);
+
+	da = rtw_hwmp_preq_da(path, is_root_add_chk, da_is_peer);
+
+#ifdef CONFIG_RTW_MESH_ON_DMD_GANN
+	flags = (mshcfg->dot11MeshGateAnnouncementProtocol)
+		? RTW_IEEE80211_PREQ_IS_GATE_FLAG : 0;
+#endif
+	rtw_mesh_path_sel_frame_tx(RTW_MPATH_PREQ, flags, adapter_mac_addr(adapter), minfo->sn,
+				   target_flags, path->dst, path->sn, da, 0,
+				   ttl, lifetime, 0, minfo->preq_id++, adapter);
+	rtw_mod_timer(&path->timer, rtw_get_current_time() + path->discovery_timeout);
+
+enddiscovery:
+	rtw_rcu_read_unlock();
+	rtw_mfree(preq_node, sizeof(struct rtw_mesh_preq_queue));
+}
+
+void rtw_mesh_path_timer(void *ctx)
+{
+	struct rtw_mesh_path *path = (void *) ctx;
+	_adapter *adapter = path->adapter;
+	int ret;
+	u8 retry = 0;
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+	struct rtw_mesh_cfg *mshcfg = &adapter->mesh_cfg;
+#endif
+	/* TBD: Proctect for suspend */
+#if 0
+	if (suspending)
+		return;
+#endif
+	enter_critical_bh(&path->state_lock);
+	if (path->flags & RTW_MESH_PATH_RESOLVED ||
+			(!(path->flags & RTW_MESH_PATH_RESOLVING))) {
+		path->flags &= ~(RTW_MESH_PATH_RESOLVING |
+				 RTW_MESH_PATH_RESOLVED |
+				 RTW_MESH_PATH_ROOT_ADD_CHK |
+				 RTW_MESH_PATH_PEER_AKA);
+		exit_critical_bh(&path->state_lock);
+	} else if (path->discovery_retries < rtw_max_preq_retries(adapter)) {
+		++path->discovery_retries;
+		path->discovery_timeout *= 2;
+		path->flags &= ~RTW_MESH_PATH_REQ_QUEUED;
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+		if (path->discovery_retries > mshcfg->max_root_add_chk_cnt)
+			path->flags &= ~RTW_MESH_PATH_ROOT_ADD_CHK;
+#endif
+		if (path->gate_asked)
+			retry |= RTW_PREQ_Q_F_REFRESH;
+
+		exit_critical_bh(&path->state_lock);
+		rtw_mesh_queue_preq(path, retry);
+	} else {
+		path->flags &= ~(RTW_MESH_PATH_RESOLVING |
+				  RTW_MESH_PATH_RESOLVED |
+				  RTW_MESH_PATH_REQ_QUEUED |
+				  RTW_MESH_PATH_ROOT_ADD_CHK |
+				  RTW_MESH_PATH_PEER_AKA);
+		path->exp_time = rtw_get_current_time();
+		exit_critical_bh(&path->state_lock);
+		if (!path->is_gate && rtw_mesh_gate_num(adapter) > 0) {
+			ret = rtw_mesh_path_send_to_gates(path);
+			if (ret)
+				RTW_HWMP_DBG("no gate was reachable\n");
+		} else
+			rtw_mesh_path_flush_pending(path);
+	}
+}
+
+
+void rtw_mesh_path_tx_root_frame(_adapter *adapter)
+{
+	struct rtw_mesh_cfg *mshcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	u32 interval = mshcfg->dot11MeshHWMPRannInterval;
+	u8 flags, target_flags = 0;
+
+	flags = (mshcfg->dot11MeshGateAnnouncementProtocol)
+			? RTW_RANN_FLAG_IS_GATE : 0;
+
+	switch (mshcfg->dot11MeshHWMPRootMode) {
+	case RTW_IEEE80211_PROACTIVE_RANN:
+		rtw_mesh_path_sel_frame_tx(RTW_MPATH_RANN, flags, adapter_mac_addr(adapter),
+					   ++minfo->sn, 0, NULL, 0, bcast_addr,
+					   0, mshcfg->element_ttl,
+					   interval, 0, 0, adapter);
+		break;
+	case RTW_IEEE80211_PROACTIVE_PREQ_WITH_PREP:
+		flags |= RTW_IEEE80211_PREQ_PROACTIVE_PREP_FLAG;
+	case RTW_IEEE80211_PROACTIVE_PREQ_NO_PREP:
+		interval = mshcfg->dot11MeshHWMPactivePathToRootTimeout;
+		target_flags |= RTW_IEEE80211_PREQ_TO_FLAG |
+				RTW_IEEE80211_PREQ_USN_FLAG;
+		rtw_mesh_path_sel_frame_tx(RTW_MPATH_PREQ, flags, adapter_mac_addr(adapter),
+					   ++minfo->sn, target_flags,
+					   (u8 *) bcast_addr, 0, bcast_addr,
+					   0, mshcfg->element_ttl, interval,
+					   0, minfo->preq_id++, adapter);
+		break;
+	default:
+		RTW_HWMP_INFO("Proactive mechanism not supported\n");
+		return;
+	}
+}
+
+void rtw_mesh_work(_workitem *work)
+{
+	/* use kernel global workqueue */
+	_set_workitem(work);
+}
+
+void rtw_ieee80211_mesh_path_timer(void *ctx)
+{
+	_adapter *adapter = (_adapter *)ctx;
+	rtw_mesh_work(&adapter->mesh_work);
+}
+
+void rtw_ieee80211_mesh_path_root_timer(void *ctx)
+{
+	_adapter *adapter = (_adapter *)ctx;
+
+	rtw_set_bit(RTW_MESH_WORK_ROOT, &adapter->wrkq_flags);
+
+	rtw_mesh_work(&adapter->mesh_work);
+}
+
+static void rtw_ieee80211_mesh_rootpath(_adapter *adapter)
+{
+	u32 interval;
+
+	rtw_mesh_path_tx_root_frame(adapter);
+
+	if (adapter->mesh_cfg.dot11MeshHWMPRootMode == RTW_IEEE80211_PROACTIVE_RANN)
+		interval = adapter->mesh_cfg.dot11MeshHWMPRannInterval;
+	else
+		interval = adapter->mesh_cfg.dot11MeshHWMProotInterval;
+
+	rtw_mod_timer(&adapter->mesh_path_root_timer,
+		  RTW_TU_TO_EXP_TIME(interval));
+}
+
+BOOLEAN rtw_ieee80211_mesh_root_setup(_adapter *adapter)
+{
+	BOOLEAN root_enabled = _FALSE;
+
+	if (adapter->mesh_cfg.dot11MeshHWMPRootMode > RTW_IEEE80211_ROOTMODE_ROOT) {
+		rtw_set_bit(RTW_MESH_WORK_ROOT, &adapter->wrkq_flags);
+		root_enabled = _TRUE;
+	}
+	else {
+		rtw_clear_bit(RTW_MESH_WORK_ROOT, &adapter->wrkq_flags);
+		/* stop running timer */
+		_cancel_timer_ex(&adapter->mesh_path_root_timer);
+		root_enabled = _FALSE;
+	}
+
+	return root_enabled;
+}
+
+void rtw_mesh_work_hdl(_workitem *work)
+{
+	_adapter *adapter = container_of(work, _adapter, mesh_work);
+
+	while(adapter->mesh_info.preq_queue_len) {
+		if (rtw_time_after(rtw_get_current_time(),
+		       adapter->mesh_info.last_preq + rtw_min_preq_int_jiff(adapter)))
+		       /* It will consume preq_queue_len */
+		       rtw_mesh_path_start_discovery(adapter);
+		else {
+			struct rtw_mesh_info *minfo = &adapter->mesh_info;
+
+			rtw_mod_timer(&adapter->mesh_path_timer,
+				minfo->last_preq + rtw_min_preq_int_jiff(adapter) + 1);
+			break;
+		}
+	}
+
+	if (rtw_test_and_clear_bit(RTW_MESH_WORK_ROOT, &adapter->wrkq_flags))
+		rtw_ieee80211_mesh_rootpath(adapter);
+}
+
+#ifndef RTW_PER_CMD_SUPPORT_FW
+static void rtw_update_metric_directly(_adapter *adapter)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+	u8 i;
+
+	for (i = 0; i < macid_ctl->num; i++) {
+		u8 role;
+		role = GET_H2CCMD_MSRRPT_PARM_ROLE(&macid_ctl->h2c_msr[i]);
+		if (role == H2C_MSR_ROLE_MESH) {
+			struct sta_info *sta = macid_ctl->sta[i];
+			u8 rate_idx, sgi, bw;
+			u32 rate;
+
+			if (!sta)
+				continue;
+			rate_idx = rtw_get_current_tx_rate(adapter, sta);
+			sgi = rtw_get_current_tx_sgi(adapter, sta);
+			bw = sta->cmn.bw_mode;
+			rate = rtw_desc_rate_to_bitrate(bw, rate_idx, sgi);
+			sta->metrics.data_rate = rate;
+		}
+	}
+}
+#endif
+
+void rtw_mesh_atlm_param_req_timer(void *ctx)
+{
+	_adapter *adapter = (_adapter *)ctx;
+	u8 ret = _FAIL;
+
+#ifdef RTW_PER_CMD_SUPPORT_FW
+	ret = rtw_req_per_cmd(adapter);
+	if (ret == _FAIL)
+		RTW_HWMP_INFO("rtw_req_per_cmd fail\n");
+#else
+	rtw_update_metric_directly(adapter);
+#endif
+	_set_timer(&adapter->mesh_atlm_param_req_timer, RTW_ATLM_REQ_CYCLE);
+}
+
+#endif /* CONFIG_RTW_MESH */
+

+ 60 - 0
core/mesh/rtw_mesh_hwmp.h

@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+#ifndef __RTW_MESH_HWMP_H_
+#define __RTW_MESH_HWMP_H_
+
+#ifndef DBG_RTW_HWMP
+#define DBG_RTW_HWMP 0
+#endif
+#if DBG_RTW_HWMP
+#define RTW_HWMP_DBG(fmt, arg...) RTW_PRINT(fmt, ##arg)
+#else
+#define RTW_HWMP_DBG(fmt, arg...) RTW_DBG(fmt, ##arg)
+#endif
+
+#ifndef INFO_RTW_HWMP
+#define INFO_RTW_HWMP 0
+#endif
+#if INFO_RTW_HWMP
+#define RTW_HWMP_INFO(fmt, arg...) RTW_PRINT(fmt, ##arg)
+#else
+#define RTW_HWMP_INFO(fmt, arg...) RTW_INFO(fmt, ##arg)
+#endif
+
+
+void rtw_ewma_err_rate_init(struct rtw_ewma_err_rate *e);
+unsigned long rtw_ewma_err_rate_read(struct rtw_ewma_err_rate *e);
+void rtw_ewma_err_rate_add(struct rtw_ewma_err_rate *e, unsigned long val);
+int rtw_mesh_path_error_tx(_adapter *adapter,
+			   u8 ttl, const u8 *target, u32 target_sn,
+			   u16 target_rcode, const u8 *ra);
+void rtw_ieee80211s_update_metric(_adapter *adapter, u8 mac_id,
+				  u8 per, u8 rate,
+				  u8 bw, u8 total_pkt);
+void rtw_mesh_rx_path_sel_frame(_adapter *adapter, union recv_frame *rframe);
+void rtw_mesh_queue_preq(struct rtw_mesh_path *mpath, u8 flags);
+void rtw_mesh_path_start_discovery(_adapter *adapter);
+void rtw_mesh_path_timer(void *ctx);
+void rtw_mesh_path_tx_root_frame(_adapter *adapter);
+void rtw_mesh_work_hdl(_workitem *work);
+void rtw_ieee80211_mesh_path_timer(void *ctx);
+void rtw_ieee80211_mesh_path_root_timer(void *ctx);
+BOOLEAN rtw_ieee80211_mesh_root_setup(_adapter *adapter);
+void rtw_mesh_work(_workitem *work);
+void rtw_mesh_atlm_param_req_timer(void *ctx);
+
+#endif /* __RTW_MESH_HWMP_H_ */
+
+

+ 1185 - 0
core/mesh/rtw_mesh_pathtbl.c

@@ -0,0 +1,1185 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+#define _RTW_MESH_PATHTBL_C_
+
+#ifdef CONFIG_RTW_MESH
+#include <drv_types.h>
+#include <linux/jhash.h>
+
+#ifdef PLATFORM_LINUX
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+static void rtw_mpath_free_rcu(struct rtw_mesh_path *mpath)
+{
+	kfree_rcu(mpath, rcu);
+	rtw_mstat_update(MSTAT_TYPE_PHY, MSTAT_FREE, sizeof(struct rtw_mesh_path));
+}
+#else
+static void rtw_mpath_free_rcu_callback(rtw_rcu_head *head)
+{
+	struct rtw_mesh_path *mpath;
+
+	mpath = container_of(head, struct rtw_mesh_path, rcu);
+	rtw_mfree(mpath, sizeof(struct rtw_mesh_path));
+}
+
+static void rtw_mpath_free_rcu(struct rtw_mesh_path *mpath)
+{
+	call_rcu(&mpath->rcu, rtw_mpath_free_rcu_callback);
+}
+#endif
+#endif /* PLATFORM_LINUX */
+
+static void rtw_mesh_path_free_rcu(struct rtw_mesh_table *tbl, struct rtw_mesh_path *mpath);
+
+static u32 rtw_mesh_table_hash(const void *addr, u32 len, u32 seed)
+{
+	/* Use last four bytes of hw addr as hash index */
+	return jhash_1word(*(u32 *)(addr+2), seed);
+}
+
+static const rtw_rhashtable_params rtw_mesh_rht_params = {
+	.nelem_hint = 2,
+	.automatic_shrinking = true,
+	.key_len = ETH_ALEN,
+	.key_offset = offsetof(struct rtw_mesh_path, dst),
+	.head_offset = offsetof(struct rtw_mesh_path, rhash),
+	.hashfn = rtw_mesh_table_hash,
+};
+
+static inline bool rtw_mpath_expired(struct rtw_mesh_path *mpath)
+{
+	return (mpath->flags & RTW_MESH_PATH_ACTIVE) &&
+	       rtw_time_after(rtw_get_current_time(), mpath->exp_time) &&
+	       !(mpath->flags & RTW_MESH_PATH_FIXED);
+}
+
+static void rtw_mesh_path_rht_free(void *ptr, void *tblptr)
+{
+	struct rtw_mesh_path *mpath = ptr;
+	struct rtw_mesh_table *tbl = tblptr;
+
+	rtw_mesh_path_free_rcu(tbl, mpath);
+}
+
+static struct rtw_mesh_table *rtw_mesh_table_alloc(void)
+{
+	struct rtw_mesh_table *newtbl;
+
+	newtbl = rtw_malloc(sizeof(struct rtw_mesh_table));
+	if (!newtbl)
+		return NULL;
+
+	rtw_hlist_head_init(&newtbl->known_gates);
+	ATOMIC_SET(&newtbl->entries,  0);
+	_rtw_spinlock_init(&newtbl->gates_lock);
+
+	return newtbl;
+}
+
+static void rtw_mesh_table_free(struct rtw_mesh_table *tbl)
+{
+	rtw_rhashtable_free_and_destroy(&tbl->rhead,
+				    rtw_mesh_path_rht_free, tbl);
+	rtw_mfree(tbl, sizeof(struct rtw_mesh_table));
+}
+
+/**
+ *
+ * rtw_mesh_path_assign_nexthop - update mesh path next hop
+ *
+ * @mpath: mesh path to update
+ * @sta: next hop to assign
+ *
+ * Locking: mpath->state_lock must be held when calling this function
+ */
+void rtw_mesh_path_assign_nexthop(struct rtw_mesh_path *mpath, struct sta_info *sta)
+{
+	struct xmit_frame *xframe;
+	_list *list, *head;
+
+	rtw_rcu_assign_pointer(mpath->next_hop, sta);
+
+	enter_critical_bh(&mpath->frame_queue.lock);
+	head = &mpath->frame_queue.queue;
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		xframe = LIST_CONTAINOR(list, struct xmit_frame, list);
+		list = get_next(list);
+		_rtw_memcpy(xframe->attrib.ra, sta->cmn.mac_addr, ETH_ALEN);
+	}
+
+	exit_critical_bh(&mpath->frame_queue.lock);
+}
+
+static void rtw_prepare_for_gate(struct xmit_frame *xframe, char *dst_addr,
+			     struct rtw_mesh_path *gate_mpath)
+{
+	struct pkt_attrib *attrib = &xframe->attrib;
+	char *next_hop;
+
+	if (attrib->mesh_frame_mode == MESH_UCAST_DATA)
+		attrib->mesh_frame_mode = MESH_UCAST_PX_DATA;
+
+	/* update next hop */
+	rtw_rcu_read_lock();
+	next_hop = rtw_rcu_dereference(gate_mpath->next_hop)->cmn.mac_addr;
+	_rtw_memcpy(attrib->ra, next_hop, ETH_ALEN);
+	rtw_rcu_read_unlock();
+	_rtw_memcpy(attrib->mda, dst_addr, ETH_ALEN);
+}
+
+/**
+ *
+ * rtw_mesh_path_move_to_queue - Move or copy frames from one mpath queue to another
+ *
+ * This function is used to transfer or copy frames from an unresolved mpath to
+ * a gate mpath.  The function also adds the Address Extension field and
+ * updates the next hop.
+ *
+ * If a frame already has an Address Extension field, only the next hop and
+ * destination addresses are updated.
+ *
+ * The gate mpath must be an active mpath with a valid mpath->next_hop.
+ *
+ * @mpath: An active mpath the frames will be sent to (i.e. the gate)
+ * @from_mpath: The failed mpath
+ * @copy: When true, copy all the frames to the new mpath queue.  When false,
+ * move them.
+ */
+static void rtw_mesh_path_move_to_queue(struct rtw_mesh_path *gate_mpath,
+				    struct rtw_mesh_path *from_mpath,
+				    bool copy)
+{
+	struct xmit_frame *fskb;
+	_list *list, *head;
+	_list failq;
+	u32 failq_len;
+	_irqL flags;
+
+	if (rtw_warn_on(gate_mpath == from_mpath))
+		return;
+	if (rtw_warn_on(!gate_mpath->next_hop))
+		return;
+
+	_rtw_init_listhead(&failq);
+
+	_enter_critical_bh(&from_mpath->frame_queue.lock, &flags);
+	rtw_list_splice_init(&from_mpath->frame_queue.queue, &failq);
+	failq_len = from_mpath->frame_queue_len;
+	from_mpath->frame_queue_len = 0;
+	_exit_critical_bh(&from_mpath->frame_queue.lock, &flags);
+
+	head = &failq;
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		if (gate_mpath->frame_queue_len >= RTW_MESH_FRAME_QUEUE_LEN) {
+			RTW_MPATH_DBG(FUNC_ADPT_FMT" mpath queue for gate %pM is full!\n"
+				, FUNC_ADPT_ARG(gate_mpath->adapter), gate_mpath->dst);
+			break;
+		}
+
+		fskb = LIST_CONTAINOR(list, struct xmit_frame, list);
+		list = get_next(list);
+
+		rtw_list_delete(&fskb->list);
+		failq_len--;
+		rtw_prepare_for_gate(fskb, gate_mpath->dst, gate_mpath);
+		_enter_critical_bh(&gate_mpath->frame_queue.lock, &flags);
+		rtw_list_insert_tail(&fskb->list, get_list_head(&gate_mpath->frame_queue));
+		gate_mpath->frame_queue_len++;
+		_exit_critical_bh(&gate_mpath->frame_queue.lock, &flags);
+
+		#if 0 /* TODO: copy */
+		skb = rtw_skb_copy(fskb);
+		if (rtw_warn_on(!skb))
+			break;
+
+		rtw_prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
+		skb_queue_tail(&gate_mpath->frame_queue, skb);
+
+		if (copy)
+			continue;
+
+		__skb_unlink(fskb, &failq);
+		rtw_skb_free(fskb);
+		#endif
+	}
+
+	RTW_MPATH_DBG(FUNC_ADPT_FMT" mpath queue for gate %pM has %d frames\n"
+		, FUNC_ADPT_ARG(gate_mpath->adapter), gate_mpath->dst, gate_mpath->frame_queue_len);
+
+	if (!copy)
+		return;
+
+	_enter_critical_bh(&from_mpath->frame_queue.lock, &flags);
+	rtw_list_splice(&failq, &from_mpath->frame_queue.queue);
+	from_mpath->frame_queue_len += failq_len;
+	_exit_critical_bh(&from_mpath->frame_queue.lock, &flags);
+}
+
+
+static struct rtw_mesh_path *rtw_mpath_lookup(struct rtw_mesh_table *tbl, const u8 *dst)
+{
+	struct rtw_mesh_path *mpath;
+
+	if (!tbl)
+		return NULL;
+
+	mpath = rtw_rhashtable_lookup_fast(&tbl->rhead, dst, rtw_mesh_rht_params);
+
+	if (mpath && rtw_mpath_expired(mpath)) {
+		enter_critical_bh(&mpath->state_lock);
+		mpath->flags &= ~RTW_MESH_PATH_ACTIVE;
+		exit_critical_bh(&mpath->state_lock);
+	}
+	return mpath;
+}
+
+/**
+ * rtw_mesh_path_lookup - look up a path in the mesh path table
+ * @sdata: local subif
+ * @dst: hardware address (ETH_ALEN length) of destination
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct rtw_mesh_path *
+rtw_mesh_path_lookup(_adapter *adapter, const u8 *dst)
+{
+	return rtw_mpath_lookup(adapter->mesh_info.mesh_paths, dst);
+}
+
+struct rtw_mesh_path *
+rtw_mpp_path_lookup(_adapter *adapter, const u8 *dst)
+{
+	return rtw_mpath_lookup(adapter->mesh_info.mpp_paths, dst);
+}
+
+static struct rtw_mesh_path *
+__rtw_mesh_path_lookup_by_idx(struct rtw_mesh_table *tbl, int idx)
+{
+	int i = 0, ret;
+	struct rtw_mesh_path *mpath = NULL;
+	rtw_rhashtable_iter iter;
+
+	if (!tbl)
+		return NULL;
+
+	ret = rtw_rhashtable_walk_enter(&tbl->rhead, &iter);
+	if (ret)
+		return NULL;
+
+	ret = rtw_rhashtable_walk_start(&iter);
+	if (ret && ret != -EAGAIN)
+		goto err;
+
+	while ((mpath = rtw_rhashtable_walk_next(&iter))) {
+		if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
+			continue;
+		if (IS_ERR(mpath))
+			break;
+		if (i++ == idx)
+			break;
+	}
+err:
+	rtw_rhashtable_walk_stop(&iter);
+	rtw_rhashtable_walk_exit(&iter);
+
+	if (IS_ERR(mpath) || !mpath)
+		return NULL;
+
+	if (rtw_mpath_expired(mpath)) {
+		enter_critical_bh(&mpath->state_lock);
+		mpath->flags &= ~RTW_MESH_PATH_ACTIVE;
+		exit_critical_bh(&mpath->state_lock);
+	}
+	return mpath;
+}
+
+/**
+ * rtw_mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
+ * @idx: index
+ * @sdata: local subif, or NULL for all entries
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct rtw_mesh_path *
+rtw_mesh_path_lookup_by_idx(_adapter *adapter, int idx)
+{
+	return __rtw_mesh_path_lookup_by_idx(adapter->mesh_info.mesh_paths, idx);
+}
+
+/**
+ * rtw_mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
+ * @idx: index
+ * @sdata: local subif, or NULL for all entries
+ *
+ * Returns: pointer to the proxy path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct rtw_mesh_path *
+rtw_mpp_path_lookup_by_idx(_adapter *adapter, int idx)
+{
+	return __rtw_mesh_path_lookup_by_idx(adapter->mesh_info.mpp_paths, idx);
+}
+
+/**
+ * rtw_mesh_path_add_gate - add the given mpath to a mesh gate to our path table
+ * @mpath: gate path to add to table
+ */
+int rtw_mesh_path_add_gate(struct rtw_mesh_path *mpath)
+{
+	struct rtw_mesh_cfg *mcfg;
+	struct rtw_mesh_info *minfo;
+	struct rtw_mesh_table *tbl;
+	int err, ori_num_gates;
+
+	rtw_rcu_read_lock();
+	tbl = mpath->adapter->mesh_info.mesh_paths;
+	if (!tbl) {
+		err = -ENOENT;
+		goto err_rcu;
+	}
+
+	enter_critical_bh(&mpath->state_lock);
+	mcfg = &mpath->adapter->mesh_cfg;
+	mpath->gate_timeout = rtw_get_current_time() +
+			      rtw_ms_to_systime(mcfg->path_gate_timeout_factor *
+					        mpath->gate_ann_int);
+	if (mpath->is_gate) {
+		err = -EEXIST;
+		exit_critical_bh(&mpath->state_lock);
+		goto err_rcu;
+	}
+
+	minfo = &mpath->adapter->mesh_info;
+	mpath->is_gate = true;
+	_rtw_spinlock(&tbl->gates_lock);
+	ori_num_gates = minfo->num_gates;
+	minfo->num_gates++;
+	rtw_hlist_add_head_rcu(&mpath->gate_list, &tbl->known_gates);
+
+	if (ori_num_gates == 0
+		|| rtw_macaddr_is_larger(mpath->dst, minfo->max_addr_gate->dst)
+	) {
+		minfo->max_addr_gate = mpath;
+		minfo->max_addr_gate_is_larger_than_self =
+			rtw_macaddr_is_larger(mpath->dst, adapter_mac_addr(mpath->adapter));
+	}
+
+	_rtw_spinunlock(&tbl->gates_lock);
+
+	exit_critical_bh(&mpath->state_lock);
+
+	if (ori_num_gates == 0) {
+		update_beacon(mpath->adapter, WLAN_EID_MESH_CONFIG, NULL, _TRUE);
+		#if CONFIG_RTW_MESH_CTO_MGATE_CARRIER
+		if (!rtw_mesh_cto_mgate_required(mpath->adapter))
+			rtw_netif_carrier_on(mpath->adapter->pnetdev);
+		#endif
+	}
+
+	RTW_MPATH_DBG(
+		  FUNC_ADPT_FMT" Mesh path: Recorded new gate: %pM. %d known gates\n",
+		  FUNC_ADPT_ARG(mpath->adapter),
+		  mpath->dst, mpath->adapter->mesh_info.num_gates);
+	err = 0;
+err_rcu:
+	rtw_rcu_read_unlock();
+	return err;
+}
+
+/**
+ * rtw_mesh_gate_del - remove a mesh gate from the list of known gates
+ * @tbl: table which holds our list of known gates
+ * @mpath: gate mpath
+ */
+void rtw_mesh_gate_del(struct rtw_mesh_table *tbl, struct rtw_mesh_path *mpath)
+{
+	struct rtw_mesh_cfg *mcfg;
+	struct rtw_mesh_info *minfo;
+	int ori_num_gates;
+
+	rtw_lockdep_assert_held(&mpath->state_lock);
+	if (!mpath->is_gate)
+		return;
+
+	mcfg = &mpath->adapter->mesh_cfg;
+	minfo = &mpath->adapter->mesh_info;
+
+	mpath->is_gate = false;
+	enter_critical_bh(&tbl->gates_lock);
+	rtw_hlist_del_rcu(&mpath->gate_list);
+	ori_num_gates = minfo->num_gates;
+	minfo->num_gates--;
+
+	if (ori_num_gates == 1) {
+		minfo->max_addr_gate = NULL;
+		minfo->max_addr_gate_is_larger_than_self = 0;
+	} else if (minfo->max_addr_gate == mpath) {
+		struct rtw_mesh_path *gate, *max_addr_gate = NULL;
+		rtw_hlist_node *node;
+
+		rtw_hlist_for_each_entry_rcu(gate, node, &tbl->known_gates, gate_list) {
+			if (!max_addr_gate || rtw_macaddr_is_larger(gate->dst, max_addr_gate->dst))
+				max_addr_gate = gate;
+		}
+		minfo->max_addr_gate = max_addr_gate;
+		minfo->max_addr_gate_is_larger_than_self =
+			rtw_macaddr_is_larger(max_addr_gate->dst, adapter_mac_addr(mpath->adapter));
+	}
+
+	exit_critical_bh(&tbl->gates_lock);
+
+	if (ori_num_gates == 1) {
+		update_beacon(mpath->adapter, WLAN_EID_MESH_CONFIG, NULL, _TRUE);
+		#if CONFIG_RTW_MESH_CTO_MGATE_CARRIER
+		if (rtw_mesh_cto_mgate_required(mpath->adapter))
+			rtw_netif_carrier_off(mpath->adapter->pnetdev);
+		#endif
+	}
+
+	RTW_MPATH_DBG(
+		  FUNC_ADPT_FMT" Mesh path: Deleted gate: %pM. %d known gates\n",
+		  FUNC_ADPT_ARG(mpath->adapter),
+		  mpath->dst, mpath->adapter->mesh_info.num_gates);
+}
+
+/**
+ * rtw_mesh_gate_search - search a mesh gate from the list of known gates
+ * @tbl: table which holds our list of known gates
+ * @addr: address of gate
+ */
+bool rtw_mesh_gate_search(struct rtw_mesh_table *tbl, const u8 *addr)
+{
+	struct rtw_mesh_path *gate;
+	rtw_hlist_node *node;
+	bool exist = 0;
+
+	rtw_rcu_read_lock();
+	rtw_hlist_for_each_entry_rcu(gate, node, &tbl->known_gates, gate_list) {
+		if (_rtw_memcmp(gate->dst, addr, ETH_ALEN) == _TRUE) {
+			exist = 1;
+			break;
+		}
+	}
+
+	rtw_rcu_read_unlock();
+
+	return exist;
+}
+
+/**
+ * rtw_mesh_gate_num - number of gates known to this interface
+ * @sdata: subif data
+ */
+int rtw_mesh_gate_num(_adapter *adapter)
+{
+	return adapter->mesh_info.num_gates;
+}
+
+bool rtw_mesh_is_primary_gate(_adapter *adapter)
+{
+	struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+
+	return mcfg->dot11MeshGateAnnouncementProtocol
+		&& !minfo->max_addr_gate_is_larger_than_self;
+}
+
+void dump_known_gates(void *sel, _adapter *adapter)
+{
+	struct rtw_mesh_info *minfo = &adapter->mesh_info;
+	struct rtw_mesh_table *tbl;
+	struct rtw_mesh_path *gate;
+	rtw_hlist_node *node;
+
+	if (!rtw_mesh_gate_num(adapter))
+		goto exit;
+
+	rtw_rcu_read_lock();
+
+	tbl = minfo->mesh_paths;
+	if (!tbl)
+		goto unlock;
+
+	RTW_PRINT_SEL(sel, "num:%d\n", rtw_mesh_gate_num(adapter));
+
+	rtw_hlist_for_each_entry_rcu(gate, node, &tbl->known_gates, gate_list) {
+		RTW_PRINT_SEL(sel, "%c"MAC_FMT"\n"
+			, gate == minfo->max_addr_gate ? '*' : ' '
+			, MAC_ARG(gate->dst));
+	}
+
+unlock:
+	rtw_rcu_read_unlock();
+exit:
+	return;
+}
+
+static
+struct rtw_mesh_path *rtw_mesh_path_new(_adapter *adapter,
+				const u8 *dst)
+{
+	struct rtw_mesh_path *new_mpath;
+
+	new_mpath = rtw_zmalloc(sizeof(struct rtw_mesh_path));
+	if (!new_mpath)
+		return NULL;
+
+	_rtw_memcpy(new_mpath->dst, dst, ETH_ALEN);
+	_rtw_memset(new_mpath->rann_snd_addr, 0xFF, ETH_ALEN);
+	new_mpath->is_root = false;
+	new_mpath->adapter = adapter;
+	new_mpath->flags = 0;
+	new_mpath->gate_asked = false;
+	_rtw_init_queue(&new_mpath->frame_queue);
+	new_mpath->frame_queue_len = 0;
+	new_mpath->exp_time = rtw_get_current_time();
+	_rtw_spinlock_init(&new_mpath->state_lock);
+	rtw_init_timer(&new_mpath->timer, adapter, rtw_mesh_path_timer, new_mpath);
+
+	return new_mpath;
+}
+
+/**
+ * rtw_mesh_path_add - allocate and add a new path to the mesh path table
+ * @dst: destination address of the path (ETH_ALEN length)
+ * @sdata: local subif
+ *
+ * Returns: 0 on success
+ *
+ * State: the initial state of the new path is set to 0
+ */
+struct rtw_mesh_path *rtw_mesh_path_add(_adapter *adapter,
+				const u8 *dst)
+{
+	struct rtw_mesh_table *tbl = adapter->mesh_info.mesh_paths;
+	struct rtw_mesh_path *mpath, *new_mpath;
+	int ret;
+
+	if (!tbl)
+		return ERR_PTR(-ENOTSUPP);
+
+	if (_rtw_memcmp(dst, adapter_mac_addr(adapter), ETH_ALEN) == _TRUE)
+		/* never add ourselves as neighbours */
+		return ERR_PTR(-ENOTSUPP);
+
+	if (is_multicast_mac_addr(dst))
+		return ERR_PTR(-ENOTSUPP);
+
+	if (ATOMIC_INC_UNLESS(&adapter->mesh_info.mpaths, RTW_MESH_MAX_MPATHS) == 0)
+		return ERR_PTR(-ENOSPC);
+
+	new_mpath = rtw_mesh_path_new(adapter, dst);
+	if (!new_mpath)
+		return ERR_PTR(-ENOMEM);
+
+	do {
+		ret = rtw_rhashtable_lookup_insert_fast(&tbl->rhead,
+						    &new_mpath->rhash,
+						    rtw_mesh_rht_params);
+
+		if (ret == -EEXIST)
+			mpath = rtw_rhashtable_lookup_fast(&tbl->rhead,
+						       dst,
+						       rtw_mesh_rht_params);
+
+	} while (unlikely(ret == -EEXIST && !mpath));
+
+	if (ret && ret != -EEXIST)
+		return ERR_PTR(ret);
+
+	/* At this point either new_mpath was added, or we found a
+	 * matching entry already in the table; in the latter case
+	 * free the unnecessary new entry.
+	 */
+	if (ret == -EEXIST) {
+		rtw_mfree(new_mpath, sizeof(struct rtw_mesh_path));
+		new_mpath = mpath;
+	}
+	adapter->mesh_info.mesh_paths_generation++;
+	return new_mpath;
+}
+
+int rtw_mpp_path_add(_adapter *adapter,
+		 const u8 *dst, const u8 *mpp)
+{
+	struct rtw_mesh_table *tbl = adapter->mesh_info.mpp_paths;
+	struct rtw_mesh_path *new_mpath;
+	int ret;
+
+	if (!tbl)
+		return -ENOTSUPP;
+
+	if (_rtw_memcmp(dst, adapter_mac_addr(adapter), ETH_ALEN) == _TRUE)
+		/* never add ourselves as neighbours */
+		return -ENOTSUPP;
+
+	if (is_multicast_mac_addr(dst))
+		return -ENOTSUPP;
+
+	new_mpath = rtw_mesh_path_new(adapter, dst);
+
+	if (!new_mpath)
+		return -ENOMEM;
+
+	_rtw_memcpy(new_mpath->mpp, mpp, ETH_ALEN);
+	ret = rtw_rhashtable_lookup_insert_fast(&tbl->rhead,
+					    &new_mpath->rhash,
+					    rtw_mesh_rht_params);
+
+	adapter->mesh_info.mpp_paths_generation++;
+	return ret;
+}
+
+void dump_mpp(void *sel, _adapter *adapter)
+{
+	struct rtw_mesh_path *mpath;
+	int idx = 0;
+	char dst[ETH_ALEN];
+	char mpp[ETH_ALEN];
+
+	RTW_PRINT_SEL(sel, "%-17s %-17s\n", "dst", "mpp");
+
+	do {
+		rtw_rcu_read_lock();
+
+		mpath = rtw_mpp_path_lookup_by_idx(adapter, idx);
+		if (mpath) {
+			_rtw_memcpy(dst, mpath->dst, ETH_ALEN);
+			_rtw_memcpy(mpp, mpath->mpp, ETH_ALEN);
+		}
+
+		rtw_rcu_read_unlock();
+
+		if (mpath) {
+			RTW_PRINT_SEL(sel, MAC_FMT" "MAC_FMT"\n"
+				, MAC_ARG(dst), MAC_ARG(mpp));
+		}
+
+		idx++;
+	} while (mpath);
+}
+
+/**
+ * rtw_mesh_plink_broken - deactivates paths and sends perr when a link breaks
+ *
+ * @sta: broken peer link
+ *
+ * This function must be called from the rate control algorithm if enough
+ * delivery errors suggest that a peer link is no longer usable.
+ */
+void rtw_mesh_plink_broken(struct sta_info *sta)
+{
+	_adapter *adapter = sta->padapter;
+	struct rtw_mesh_table *tbl = adapter->mesh_info.mesh_paths;
+	static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	struct rtw_mesh_path *mpath;
+	rtw_rhashtable_iter iter;
+	int ret;
+
+	if (!tbl)
+		return;
+
+	ret = rtw_rhashtable_walk_enter(&tbl->rhead, &iter);
+	if (ret)
+		return;
+
+	ret = rtw_rhashtable_walk_start(&iter);
+	if (ret && ret != -EAGAIN)
+		goto out;
+
+	while ((mpath = rtw_rhashtable_walk_next(&iter))) {
+		if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
+			continue;
+		if (IS_ERR(mpath))
+			break;
+		if (rtw_rcu_access_pointer(mpath->next_hop) == sta &&
+		    mpath->flags & RTW_MESH_PATH_ACTIVE &&
+		    !(mpath->flags & RTW_MESH_PATH_FIXED)) {
+			enter_critical_bh(&mpath->state_lock);
+			mpath->flags &= ~RTW_MESH_PATH_ACTIVE;
+			++mpath->sn;
+			exit_critical_bh(&mpath->state_lock);
+			rtw_mesh_path_error_tx(adapter,
+				adapter->mesh_cfg.element_ttl,
+				mpath->dst, mpath->sn,
+				WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
+		}
+	}
+out:
+	rtw_rhashtable_walk_stop(&iter);
+	rtw_rhashtable_walk_exit(&iter);
+}
+
+static void rtw_mesh_path_free_rcu(struct rtw_mesh_table *tbl,
+			       struct rtw_mesh_path *mpath)
+{
+	_adapter *adapter = mpath->adapter;
+
+	enter_critical_bh(&mpath->state_lock);
+	mpath->flags |= RTW_MESH_PATH_RESOLVING | RTW_MESH_PATH_DELETED;
+	rtw_mesh_gate_del(tbl, mpath);
+	exit_critical_bh(&mpath->state_lock);
+	_cancel_timer_ex(&mpath->timer);
+	ATOMIC_DEC(&adapter->mesh_info.mpaths);
+	ATOMIC_DEC(&tbl->entries);
+	_rtw_spinlock_free(&mpath->state_lock);
+
+	rtw_mesh_path_flush_pending(mpath);
+
+	rtw_mpath_free_rcu(mpath);
+}
+
+static void __rtw_mesh_path_del(struct rtw_mesh_table *tbl, struct rtw_mesh_path *mpath)
+{
+	rtw_rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, rtw_mesh_rht_params);
+	rtw_mesh_path_free_rcu(tbl, mpath);
+}
+
+/**
+ * rtw_mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
+ *
+ * @sta: mesh peer to match
+ *
+ * RCU notes: this function is called when a mesh plink transitions from
+ * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that
+ * allows path creation. This will happen before the sta can be freed (because
+ * sta_info_destroy() calls this) so any reader in a rcu read block will be
+ * protected against the plink disappearing.
+ */
+void rtw_mesh_path_flush_by_nexthop(struct sta_info *sta)
+{
+	_adapter *adapter = sta->padapter;
+	struct rtw_mesh_table *tbl = adapter->mesh_info.mesh_paths;
+	struct rtw_mesh_path *mpath;
+	rtw_rhashtable_iter iter;
+	int ret;
+
+	if (!tbl)
+		return;
+
+	ret = rtw_rhashtable_walk_enter(&tbl->rhead, &iter);
+	if (ret)
+		return;
+
+	ret = rtw_rhashtable_walk_start(&iter);
+	if (ret && ret != -EAGAIN)
+		goto out;
+
+	while ((mpath = rtw_rhashtable_walk_next(&iter))) {
+		if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
+			continue;
+		if (IS_ERR(mpath))
+			break;
+
+		if (rtw_rcu_access_pointer(mpath->next_hop) == sta)
+			__rtw_mesh_path_del(tbl, mpath);
+	}
+out:
+	rtw_rhashtable_walk_stop(&iter);
+	rtw_rhashtable_walk_exit(&iter);
+}
+
+static void rtw_mpp_flush_by_proxy(_adapter *adapter,
+			       const u8 *proxy)
+{
+	struct rtw_mesh_table *tbl = adapter->mesh_info.mpp_paths;
+	struct rtw_mesh_path *mpath;
+	rtw_rhashtable_iter iter;
+	int ret;
+
+	if (!tbl)
+		return;
+
+	ret = rtw_rhashtable_walk_enter(&tbl->rhead, &iter);
+	if (ret)
+		return;
+
+	ret = rtw_rhashtable_walk_start(&iter);
+	if (ret && ret != -EAGAIN)
+		goto out;
+
+	while ((mpath = rtw_rhashtable_walk_next(&iter))) {
+		if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
+			continue;
+		if (IS_ERR(mpath))
+			break;
+
+		if (_rtw_memcmp(mpath->mpp, proxy, ETH_ALEN) == _TRUE)
+			__rtw_mesh_path_del(tbl, mpath);
+	}
+out:
+	rtw_rhashtable_walk_stop(&iter);
+	rtw_rhashtable_walk_exit(&iter);
+}
+
+static void rtw_table_flush_by_iface(struct rtw_mesh_table *tbl)
+{
+	struct rtw_mesh_path *mpath;
+	rtw_rhashtable_iter iter;
+	int ret;
+
+	if (!tbl)
+		return;
+	
+	ret = rtw_rhashtable_walk_enter(&tbl->rhead, &iter);
+	if (ret)
+		return;
+
+	ret = rtw_rhashtable_walk_start(&iter);
+	if (ret && ret != -EAGAIN)
+		goto out;
+
+	while ((mpath = rtw_rhashtable_walk_next(&iter))) {
+		if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
+			continue;
+		if (IS_ERR(mpath))
+			break;
+		__rtw_mesh_path_del(tbl, mpath);
+	}
+out:
+	rtw_rhashtable_walk_stop(&iter);
+	rtw_rhashtable_walk_exit(&iter);
+}
+
+/**
+ * rtw_mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface
+ *
+ * This function deletes both mesh paths as well as mesh portal paths.
+ *
+ * @sdata: interface data to match
+ *
+ */
+void rtw_mesh_path_flush_by_iface(_adapter *adapter)
+{
+	rtw_table_flush_by_iface(adapter->mesh_info.mesh_paths);
+	rtw_table_flush_by_iface(adapter->mesh_info.mpp_paths);
+}
+
+/**
+ * rtw_table_path_del - delete a path from the mesh or mpp table
+ *
+ * @tbl: mesh or mpp path table
+ * @sdata: local subif
+ * @addr: dst address (ETH_ALEN length)
+ *
+ * Returns: 0 if successful
+ */
+static int rtw_table_path_del(struct rtw_mesh_table *tbl,
+			  const u8 *addr)
+{
+	struct rtw_mesh_path *mpath;
+
+	if (!tbl)
+		return -ENXIO;
+
+	rtw_rcu_read_lock();
+	mpath = rtw_rhashtable_lookup_fast(&tbl->rhead, addr, rtw_mesh_rht_params);
+	if (!mpath) {
+		rtw_rcu_read_unlock();
+		return -ENXIO;
+	}
+
+	__rtw_mesh_path_del(tbl, mpath);
+	rtw_rcu_read_unlock();
+	return 0;
+}
+
+
+/**
+ * rtw_mesh_path_del - delete a mesh path from the table
+ *
+ * @addr: dst address (ETH_ALEN length)
+ * @sdata: local subif
+ *
+ * Returns: 0 if successful
+ */
+int rtw_mesh_path_del(_adapter *adapter, const u8 *addr)
+{
+	int err;
+
+	/* flush relevant mpp entries first */
+	rtw_mpp_flush_by_proxy(adapter, addr);
+
+	err = rtw_table_path_del(adapter->mesh_info.mesh_paths, addr);
+	adapter->mesh_info.mesh_paths_generation++;
+	return err;
+}
+
+/**
+ * rtw_mesh_path_tx_pending - sends pending frames in a mesh path queue
+ *
+ * @mpath: mesh path to activate
+ *
+ * Locking: the state_lock of the mpath structure must NOT be held when calling
+ * this function.
+ */
+void rtw_mesh_path_tx_pending(struct rtw_mesh_path *mpath)
+{
+	if (mpath->flags & RTW_MESH_PATH_ACTIVE) {
+		struct rtw_mesh_info *minfo = &mpath->adapter->mesh_info;
+		_list q;
+		u32 q_len = 0;
+
+		_rtw_init_listhead(&q);
+
+		/* move to local queue */
+		enter_critical_bh(&mpath->frame_queue.lock);
+		if (mpath->frame_queue_len) {
+			rtw_list_splice_init(&mpath->frame_queue.queue, &q);
+			q_len = mpath->frame_queue_len;
+			mpath->frame_queue_len = 0;
+		}
+		exit_critical_bh(&mpath->frame_queue.lock);
+
+		if (q_len) {
+			/* move to mpath_tx_queue */
+			enter_critical_bh(&minfo->mpath_tx_queue.lock);
+			rtw_list_splice_tail(&q, &minfo->mpath_tx_queue.queue);
+			minfo->mpath_tx_queue_len += q_len;
+			exit_critical_bh(&minfo->mpath_tx_queue.lock);
+
+			/* schedule mpath_tx_tasklet */
+			tasklet_hi_schedule(&minfo->mpath_tx_tasklet);
+		}
+	}
+}
+
+/**
+ * rtw_mesh_path_send_to_gates - sends pending frames to all known mesh gates
+ *
+ * @mpath: mesh path whose queue will be emptied
+ *
+ * If there is only one gate, the frames are transferred from the failed mpath
+ * queue to that gate's queue.  If there are more than one gates, the frames
+ * are copied from each gate to the next.  After frames are copied, the
+ * mpath queues are emptied onto the transmission queue.
+ */
+int rtw_mesh_path_send_to_gates(struct rtw_mesh_path *mpath)
+{
+	_adapter *adapter = mpath->adapter;
+	struct rtw_mesh_table *tbl;
+	struct rtw_mesh_path *from_mpath = mpath;
+	struct rtw_mesh_path *gate;
+	bool copy = false;
+	rtw_hlist_node *node;
+
+	tbl = adapter->mesh_info.mesh_paths;
+	if (!tbl)
+		return 0;
+
+	rtw_rcu_read_lock();
+	rtw_hlist_for_each_entry_rcu(gate, node, &tbl->known_gates, gate_list) {
+		if (gate->flags & RTW_MESH_PATH_ACTIVE) {
+			RTW_MPATH_DBG(FUNC_ADPT_FMT" Forwarding to %pM\n",
+				FUNC_ADPT_ARG(adapter), gate->dst);
+			rtw_mesh_path_move_to_queue(gate, from_mpath, copy);
+			from_mpath = gate;
+			copy = true;
+		} else {
+			RTW_MPATH_DBG(
+				  FUNC_ADPT_FMT" Not forwarding to %pM (flags %#x)\n",
+				  FUNC_ADPT_ARG(adapter), gate->dst, gate->flags);
+		}
+	}
+
+	rtw_hlist_for_each_entry_rcu(gate, node, &tbl->known_gates, gate_list) {
+		RTW_MPATH_DBG(FUNC_ADPT_FMT" Sending to %pM\n",
+			FUNC_ADPT_ARG(adapter), gate->dst);
+		rtw_mesh_path_tx_pending(gate);
+	}
+	rtw_rcu_read_unlock();
+
+	return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
+}
+
+/**
+ * rtw_mesh_path_discard_frame - discard a frame whose path could not be resolved
+ *
+ * @skb: frame to discard
+ * @sdata: network subif the frame was to be sent through
+ *
+ * Locking: the function must me called within a rcu_read_lock region
+ */
+void rtw_mesh_path_discard_frame(_adapter *adapter,
+			     struct xmit_frame *xframe)
+{
+	rtw_free_xmitframe(&adapter->xmitpriv, xframe);
+	adapter->mesh_info.mshstats.dropped_frames_no_route++;
+}
+
+/**
+ * rtw_mesh_path_flush_pending - free the pending queue of a mesh path
+ *
+ * @mpath: mesh path whose queue has to be freed
+ *
+ * Locking: the function must me called within a rcu_read_lock region
+ */
+void rtw_mesh_path_flush_pending(struct rtw_mesh_path *mpath)
+{
+	struct xmit_frame *xframe;
+	_list *list, *head;
+	_list tmp;
+
+	_rtw_init_listhead(&tmp);
+
+	enter_critical_bh(&mpath->frame_queue.lock);
+	rtw_list_splice_init(&mpath->frame_queue.queue, &tmp);
+	mpath->frame_queue_len = 0;
+	exit_critical_bh(&mpath->frame_queue.lock);
+
+	head = &tmp;
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		xframe = LIST_CONTAINOR(list, struct xmit_frame, list);
+		list = get_next(list);
+		rtw_list_delete(&xframe->list);
+		rtw_mesh_path_discard_frame(mpath->adapter, xframe);
+	}
+}
+
+/**
+ * rtw_mesh_path_fix_nexthop - force a specific next hop for a mesh path
+ *
+ * @mpath: the mesh path to modify
+ * @next_hop: the next hop to force
+ *
+ * Locking: this function must be called holding mpath->state_lock
+ */
+void rtw_mesh_path_fix_nexthop(struct rtw_mesh_path *mpath, struct sta_info *next_hop)
+{
+	enter_critical_bh(&mpath->state_lock);
+	rtw_mesh_path_assign_nexthop(mpath, next_hop);
+	mpath->sn = 0xffff;
+	mpath->metric = 0;
+	mpath->hop_count = 0;
+	mpath->exp_time = 0;
+	mpath->flags = RTW_MESH_PATH_FIXED | RTW_MESH_PATH_SN_VALID;
+	rtw_mesh_path_activate(mpath);
+	exit_critical_bh(&mpath->state_lock);
+	rtw_ewma_err_rate_init(&next_hop->metrics.err_rate);
+	/* init it at a low value - 0 start is tricky */
+	rtw_ewma_err_rate_add(&next_hop->metrics.err_rate, 1);
+	rtw_mesh_path_tx_pending(mpath);
+}
+
+int rtw_mesh_pathtbl_init(_adapter *adapter)
+{
+	struct rtw_mesh_table *tbl_path, *tbl_mpp;
+	int ret;
+
+	tbl_path = rtw_mesh_table_alloc();
+	if (!tbl_path)
+		return -ENOMEM;
+
+	tbl_mpp = rtw_mesh_table_alloc();
+	if (!tbl_mpp) {
+		ret = -ENOMEM;
+		goto free_path;
+	}
+
+	rtw_rhashtable_init(&tbl_path->rhead, &rtw_mesh_rht_params);
+	rtw_rhashtable_init(&tbl_mpp->rhead, &rtw_mesh_rht_params);
+
+	adapter->mesh_info.mesh_paths = tbl_path;
+	adapter->mesh_info.mpp_paths = tbl_mpp;
+
+	return 0;
+
+free_path:
+	rtw_mesh_table_free(tbl_path);
+	return ret;
+}
+
+static
+void rtw_mesh_path_tbl_expire(_adapter *adapter,
+			  struct rtw_mesh_table *tbl)
+{
+	struct rtw_mesh_path *mpath;
+	rtw_rhashtable_iter iter;
+	int ret;
+
+	if (!tbl)
+		return;
+
+	ret = rtw_rhashtable_walk_enter(&tbl->rhead, &iter);
+	if (ret)
+		return;
+
+	ret = rtw_rhashtable_walk_start(&iter);
+	if (ret && ret != -EAGAIN)
+		goto out;
+
+	while ((mpath = rtw_rhashtable_walk_next(&iter))) {
+		if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
+			continue;
+		if (IS_ERR(mpath))
+			break;
+		if ((!(mpath->flags & RTW_MESH_PATH_RESOLVING)) &&
+		    (!(mpath->flags & RTW_MESH_PATH_FIXED)) &&
+		     rtw_time_after(rtw_get_current_time(), mpath->exp_time + RTW_MESH_PATH_EXPIRE))
+			__rtw_mesh_path_del(tbl, mpath);
+
+		if (mpath->is_gate &&  /* need not to deal with non-gate case */
+		    rtw_time_after(rtw_get_current_time(), mpath->gate_timeout)) {
+			RTW_MPATH_DBG(FUNC_ADPT_FMT"mpath [%pM] expired systime is %lu systime is %lu\n",
+				      FUNC_ADPT_ARG(adapter), mpath->dst,
+				      mpath->gate_timeout, rtw_get_current_time());
+			enter_critical_bh(&mpath->state_lock);
+			if (mpath->gate_asked) { /* asked gate before */
+				rtw_mesh_gate_del(tbl, mpath);
+				exit_critical_bh(&mpath->state_lock);
+			} else {
+				mpath->gate_asked = true;
+				mpath->gate_timeout = rtw_get_current_time() + rtw_ms_to_systime(mpath->gate_ann_int);
+				exit_critical_bh(&mpath->state_lock);
+				rtw_mesh_queue_preq(mpath, RTW_PREQ_Q_F_START | RTW_PREQ_Q_F_REFRESH);
+				RTW_MPATH_DBG(FUNC_ADPT_FMT"mpath [%pM] ask mesh gate existence (is_root=%d)\n",
+				      FUNC_ADPT_ARG(adapter), mpath->dst, mpath->is_root);
+			}
+		}
+	}
+
+out:
+	rtw_rhashtable_walk_stop(&iter);
+	rtw_rhashtable_walk_exit(&iter);
+}
+
+void rtw_mesh_path_expire(_adapter *adapter)
+{
+	rtw_mesh_path_tbl_expire(adapter, adapter->mesh_info.mesh_paths);
+	rtw_mesh_path_tbl_expire(adapter, adapter->mesh_info.mpp_paths);
+}
+
+void rtw_mesh_pathtbl_unregister(_adapter *adapter)
+{
+	if (adapter->mesh_info.mesh_paths) {
+		rtw_mesh_table_free(adapter->mesh_info.mesh_paths);
+		adapter->mesh_info.mesh_paths = NULL;
+	}
+
+	if (adapter->mesh_info.mpp_paths) {
+		rtw_mesh_table_free(adapter->mesh_info.mpp_paths);
+		adapter->mesh_info.mpp_paths = NULL;
+	}
+}
+#endif /* CONFIG_RTW_MESH */
+

+ 206 - 0
core/mesh/rtw_mesh_pathtbl.h

@@ -0,0 +1,206 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+#ifndef __RTW_MESH_PATHTBL_H_
+#define __RTW_MESH_PATHTBL_H_
+
+#ifndef DBG_RTW_MPATH
+#define DBG_RTW_MPATH 1
+#endif
+#if DBG_RTW_MPATH
+#define RTW_MPATH_DBG(fmt, arg...) RTW_PRINT(fmt, ##arg)
+#else
+#define RTW_MPATH_DBG(fmt, arg...) do {} while (0)
+#endif
+
+/**
+ * enum rtw_mesh_path_flags - mesh path flags
+ *
+ * @RTW_MESH_PATH_ACTIVE: the mesh path can be used for forwarding
+ * @RTW_MESH_PATH_RESOLVING: the discovery process is running for this mesh path
+ * @RTW_MESH_PATH_SN_VALID: the mesh path contains a valid destination sequence
+ *	number
+ * @RTW_MESH_PATH_FIXED: the mesh path has been manually set and should not be
+ *	modified
+ * @RTW_MESH_PATH_RESOLVED: the mesh path can has been resolved
+ * @RTW_MESH_PATH_REQ_QUEUED: there is an unsent path request for this destination
+ *	already queued up, waiting for the discovery process to start.
+ * @RTW_MESH_PATH_DELETED: the mesh path has been deleted and should no longer
+ *	be used
+ * @RTW_MESH_PATH_ROOT_ADD_CHK: root additional check in root mode.
+ *	With this flag, It will try the last used rann_snd_addr
+ * @RTW_MESH_PATH_PEER_AKA: only used toward a peer, only used in active keep
+ *	alive mechanism. PREQ's da = path dst
+ * 
+ * RTW_MESH_PATH_RESOLVED is used by the mesh path timer to
+ * decide when to stop or cancel the mesh path discovery.
+ */
+enum rtw_mesh_path_flags {
+	RTW_MESH_PATH_ACTIVE =	BIT(0),
+	RTW_MESH_PATH_RESOLVING =	BIT(1),
+	RTW_MESH_PATH_SN_VALID =	BIT(2),
+	RTW_MESH_PATH_FIXED	=	BIT(3),
+	RTW_MESH_PATH_RESOLVED =	BIT(4),
+	RTW_MESH_PATH_REQ_QUEUED =	BIT(5),
+	RTW_MESH_PATH_DELETED =	BIT(6),
+	RTW_MESH_PATH_ROOT_ADD_CHK =	BIT(7),
+	RTW_MESH_PATH_PEER_AKA =	BIT(8),
+};
+
+/**
+ * struct rtw_mesh_path - mesh path structure
+ *
+ * @dst: mesh path destination mac address
+ * @mpp: mesh proxy mac address
+ * @rhash: rhashtable list pointer
+ * @gate_list: list pointer for known gates list
+ * @sdata: mesh subif
+ * @next_hop: mesh neighbor to which frames for this destination will be
+ *	forwarded
+ * @timer: mesh path discovery timer
+ * @frame_queue: pending queue for frames sent to this destination while the
+ *	path is unresolved
+ * @rcu: rcu head for freeing mesh path
+ * @sn: target sequence number
+ * @metric: current metric to this destination
+ * @hop_count: hops to destination
+ * @exp_time: in jiffies, when the path will expire or when it expired
+ * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery
+ *	retry
+ * @discovery_retries: number of discovery retries
+ * @flags: mesh path flags, as specified on &enum rtw_mesh_path_flags
+ * @state_lock: mesh path state lock used to protect changes to the
+ * mpath itself.  No need to take this lock when adding or removing
+ * an mpath to a hash bucket on a path table.
+ * @rann_snd_addr: the RANN sender address
+ * @rann_metric: the aggregated path metric towards the root node
+ * @last_preq_to_root: Timestamp of last PREQ sent to root
+ * @is_root: the destination station of this path is a root node
+ * @is_gate: the destination station of this path is a mesh gate
+ *
+ *
+ * The dst address is unique in the mesh path table. Since the mesh_path is
+ * protected by RCU, deleting the next_hop STA must remove / substitute the
+ * mesh_path structure and wait until that is no longer reachable before
+ * destroying the STA completely.
+ */
+struct rtw_mesh_path {
+	u8 dst[ETH_ALEN];
+	u8 mpp[ETH_ALEN];	/* used for MPP or MAP */
+	rtw_rhash_head rhash;
+	rtw_hlist_node gate_list;
+	_adapter *adapter;
+	struct sta_info __rcu *next_hop;
+	_timer timer;
+	_queue frame_queue;
+	u32 frame_queue_len;
+	rtw_rcu_head rcu;
+	u32 sn;
+	u32 metric;
+	u8 hop_count;
+	systime exp_time;
+	systime discovery_timeout;
+	systime gate_timeout;
+	u32 gate_ann_int;    /* gate announce interval */
+	u8 discovery_retries;
+	enum rtw_mesh_path_flags flags;
+	_lock state_lock;
+	u8 rann_snd_addr[ETH_ALEN];
+#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK
+	u8 add_chk_rann_snd_addr[ETH_ALEN];
+#endif
+	u32 rann_metric;
+	unsigned long last_preq_to_root;
+	bool is_root;
+	bool is_gate;
+	bool gate_asked;
+};
+
+/**
+ * struct rtw_mesh_table
+ *
+ * @known_gates: list of known mesh gates and their mpaths by the station. The
+ * gate's mpath may or may not be resolved and active.
+ * @gates_lock: protects updates to known_gates
+ * @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr
+ * @entries: number of entries in the table
+ */
+struct rtw_mesh_table {
+	rtw_hlist_head known_gates;
+	_lock gates_lock;
+	rtw_rhashtable rhead;
+	ATOMIC_T entries;
+};
+
+#define RTW_MESH_PATH_EXPIRE (600 * HZ)
+
+/* Maximum number of paths per interface */
+#define RTW_MESH_MAX_MPATHS		1024
+
+/* Number of frames buffered per destination for unresolved destinations */
+#define RTW_MESH_FRAME_QUEUE_LEN	10
+
+int rtw_mesh_nexthop_lookup(_adapter *adapter,
+	const u8 *mda, const u8 *msa, u8 *ra);
+int rtw_mesh_nexthop_resolve(_adapter *adapter,
+			 struct xmit_frame *xframe);
+
+struct rtw_mesh_path *rtw_mesh_path_lookup(_adapter *adapter,
+				   const u8 *dst);
+struct rtw_mesh_path *rtw_mpp_path_lookup(_adapter *adapter,
+				  const u8 *dst);
+int rtw_mpp_path_add(_adapter *adapter,
+		 const u8 *dst, const u8 *mpp);
+void dump_mpp(void *sel, _adapter *adapter);
+
+struct rtw_mesh_path *
+rtw_mesh_path_lookup_by_idx(_adapter *adapter, int idx);
+struct rtw_mesh_path *
+rtw_mpp_path_lookup_by_idx(_adapter *adapter, int idx);
+void rtw_mesh_path_fix_nexthop(struct rtw_mesh_path *mpath, struct sta_info *next_hop);
+void rtw_mesh_path_expire(_adapter *adapter);
+
+struct rtw_mesh_path *
+rtw_mesh_path_add(_adapter *adapter, const u8 *dst);
+
+int rtw_mesh_path_add_gate(struct rtw_mesh_path *mpath);
+void rtw_mesh_gate_del(struct rtw_mesh_table *tbl, struct rtw_mesh_path *mpath);
+bool rtw_mesh_gate_search(struct rtw_mesh_table *tbl, const u8 *addr);
+int rtw_mesh_path_send_to_gates(struct rtw_mesh_path *mpath);
+int rtw_mesh_gate_num(_adapter *adapter);
+bool rtw_mesh_is_primary_gate(_adapter *adapter);
+void dump_known_gates(void *sel, _adapter *adapter);
+
+void rtw_mesh_plink_broken(struct sta_info *sta);
+
+void rtw_mesh_path_assign_nexthop(struct rtw_mesh_path *mpath, struct sta_info *sta);
+void rtw_mesh_path_flush_pending(struct rtw_mesh_path *mpath);
+void rtw_mesh_path_tx_pending(struct rtw_mesh_path *mpath);
+int rtw_mesh_pathtbl_init(_adapter *adapter);
+void rtw_mesh_pathtbl_unregister(_adapter *adapter);
+int rtw_mesh_path_del(_adapter *adapter, const u8 *addr);
+
+void rtw_mesh_path_flush_by_nexthop(struct sta_info *sta);
+void rtw_mesh_path_discard_frame(_adapter *adapter,
+			     struct xmit_frame *xframe);
+
+static inline void rtw_mesh_path_activate(struct rtw_mesh_path *mpath)
+{
+	mpath->flags |= RTW_MESH_PATH_ACTIVE | RTW_MESH_PATH_RESOLVED;
+}
+
+void rtw_mesh_path_flush_by_iface(_adapter *adapter);
+
+#endif /* __RTW_MESH_PATHTBL_H_ */
+

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 466 - 187
core/rtw_ap.c


+ 67 - 64
core/rtw_beamforming.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_BEAMFORMING_C_
 
 #include <drv_types.h>
@@ -50,10 +45,10 @@ static void _get_txvector_parameter(PADAPTER adapter, struct sta_info *sta, u8 *
 		 * a DLS or TDLS peer STA
 		 */
 
-		aid = sta->aid;
+		aid = sta->cmn.aid;
 		bssid = adapter_mac_addr(adapter);
 		RTW_INFO("%s: AID=0x%x BSSID=" MAC_FMT "\n",
-			 __FUNCTION__, sta->aid, MAC_ARG(bssid));
+			 __FUNCTION__, sta->cmn.aid, MAC_ARG(bssid));
 
 		/* AID[0:8] */
 		aid &= 0x1FF;
@@ -75,7 +70,7 @@ static void _get_txvector_parameter(PADAPTER adapter, struct sta_info *sta, u8 *
 		*g_id = 63;
 	} else {
 		/* Addressed to AP */
-		bssid = sta->hwaddr;
+		bssid = sta->cmn.mac_addr;
 		RTW_INFO("%s: BSSID=" MAC_FMT "\n", __FUNCTION__, MAC_ARG(bssid));
 
 		/* BSSID[39:47] */
@@ -167,7 +162,7 @@ static void _get_sta_beamform_cap(PADAPTER adapter, struct sta_info *sta,
 #endif /* CONFIG_80211AC_VHT */
 }
 
-static u8 _send_ht_ndpa_packet(PADAPTER adapter, u8 *ra, CHANNEL_WIDTH bw)
+static u8 _send_ht_ndpa_packet(PADAPTER adapter, u8 *ra, enum channel_width bw)
 {
 	/* General */
 	struct xmit_priv		*pxmitpriv;
@@ -265,7 +260,7 @@ static u8 _send_ht_ndpa_packet(PADAPTER adapter, u8 *ra, CHANNEL_WIDTH bw)
 	return _TRUE;
 }
 
-static u8 _send_vht_ndpa_packet(PADAPTER adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw)
+static u8 _send_vht_ndpa_packet(PADAPTER adapter, u8 *ra, u16 aid, enum channel_width bw)
 {
 	/* General */
 	struct xmit_priv		*pxmitpriv;
@@ -371,7 +366,7 @@ static u8 _send_vht_ndpa_packet(PADAPTER adapter, u8 *ra, u16 aid, CHANNEL_WIDTH
 	return _TRUE;
 }
 
-static u8 _send_vht_mu_ndpa_packet(PADAPTER adapter, CHANNEL_WIDTH bw)
+static u8 _send_vht_mu_ndpa_packet(PADAPTER adapter, enum channel_width bw)
 {
 	/* General */
 	struct xmit_priv		*pxmitpriv;
@@ -1013,7 +1008,7 @@ static struct beamformer_entry *_bfer_add_entry(PADAPTER adapter,
 	mlme = &adapter->mlmepriv;
 	info = GET_BEAMFORM_INFO(adapter);
 
-	bfer = _bfer_get_entry_by_addr(adapter, sta->hwaddr);
+	bfer = _bfer_get_entry_by_addr(adapter, sta->cmn.mac_addr);
 	if (!bfer) {
 		bfer = _bfer_get_free_entry(adapter);
 		if (!bfer)
@@ -1022,14 +1017,14 @@ static struct beamformer_entry *_bfer_add_entry(PADAPTER adapter,
 
 	bfer->used = _TRUE;
 	_get_txvector_parameter(adapter, sta, &bfer->g_id, &bfer->p_aid);
-	_rtw_memcpy(bfer->mac_addr, sta->hwaddr, ETH_ALEN);
+	_rtw_memcpy(bfer->mac_addr, sta->cmn.mac_addr, ETH_ALEN);
 	bfer->cap = bf_cap;
 	bfer->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT;
 	bfer->NumofSoundingDim = sounding_dim;
 
 	if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_MU)) {
 		info->beamformer_mu_cnt += 1;
-		bfer->aid = sta->aid;
+		bfer->aid = sta->cmn.aid;
 	} else if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) {
 		info->beamformer_su_cnt += 1;
 
@@ -1073,22 +1068,20 @@ static void _bfer_remove_entry(PADAPTER adapter, struct beamformer_entry *entry)
 
 static u8 _bfer_set_entry_gid(PADAPTER adapter, u8 *addr, u8 *gid, u8 *position)
 {
-	struct beamformer_entry *bfer = NULL;
+	struct beamformer_entry bfer;
 
-
-	bfer = _bfer_get_entry_by_addr(adapter, addr);
-	if (!bfer) {
-		RTW_INFO("%s: Cannot find BFer entry!!\n", __FUNCTION__);
-		return _FAIL;
-	}
+	memset(&bfer, 0, sizeof(bfer));
+	memcpy(bfer.mac_addr, addr, ETH_ALEN);
 
 	/* Parsing Membership Status Array */
-	_rtw_memcpy(bfer->gid_valid, gid, 8);
+	memcpy(bfer.gid_valid, gid, 8);
+
 	/* Parsing User Position Array */
-	_rtw_memcpy(bfer->user_position, position, 16);
+	memcpy(bfer.user_position, position, 16);
 
 	/* Config HW GID table */
-	rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_GID_TABLE, (u8*)&bfer, sizeof(struct beamformer_entry *), 1);
+	rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_GID_TABLE, (u8 *) &bfer,
+			sizeof(bfer), 1);
 
 	return _SUCCESS;
 }
@@ -1200,7 +1193,7 @@ static struct beamformee_entry *_bfee_add_entry(PADAPTER adapter,
 	mlme = &adapter->mlmepriv;
 	info = GET_BEAMFORM_INFO(adapter);
 
-	bfee = _bfee_get_entry_by_addr(adapter, sta->hwaddr);
+	bfee = _bfee_get_entry_by_addr(adapter, sta->cmn.mac_addr);
 	if (!bfee) {
 		bfee = _bfee_get_free_entry(adapter);
 		if (!bfee)
@@ -1208,15 +1201,15 @@ static struct beamformee_entry *_bfee_add_entry(PADAPTER adapter,
 	}
 
 	bfee->used = _TRUE;
-	bfee->aid = sta->aid;
-	bfee->mac_id = sta->mac_id;
-	bfee->sound_bw = sta->bw_mode;
+	bfee->aid = sta->cmn.aid;
+	bfee->mac_id = sta->cmn.mac_id;
+	bfee->sound_bw = sta->cmn.bw_mode;
 
 	_get_txvector_parameter(adapter, sta, &bfee->g_id, &bfee->p_aid);
-	sta->txbf_gid = bfee->g_id;
-	sta->txbf_paid = bfee->p_aid;
+	sta->cmn.bf_info.g_id = bfee->g_id;
+	sta->cmn.bf_info.p_aid = bfee->p_aid;
 
-	_rtw_memcpy(bfee->mac_addr, sta->hwaddr, ETH_ALEN);
+	_rtw_memcpy(bfee->mac_addr, sta->cmn.mac_addr, ETH_ALEN);
 	bfee->txbf = _FALSE;
 	bfee->sounding = _FALSE;
 	bfee->sound_period = 40;
@@ -1387,15 +1380,15 @@ static void _beamforming_enter(PADAPTER adapter, void *p)
 	info = GET_BEAMFORM_INFO(adapter);
 
 	sta_copy = (struct sta_info *)p;
-	sta = rtw_get_stainfo(&adapter->stapriv, sta_copy->hwaddr);
+	sta = rtw_get_stainfo(&adapter->stapriv, sta_copy->cmn.mac_addr);
 	if (!sta) {
 		RTW_ERR("%s: Cann't find STA info for " MAC_FMT "\n",
-		        __FUNCTION__, MAC_ARG(sta_copy->hwaddr));
+			__FUNCTION__, MAC_ARG(sta_copy->cmn.mac_addr));
 		return;
 	}
 	if (sta != sta_copy) {
 		RTW_WARN("%s: Origin sta(fake)=%p realsta=%p for " MAC_FMT "\n",
-	        	 __FUNCTION__, sta_copy, sta, MAC_ARG(sta_copy->hwaddr));
+		__FUNCTION__, sta_copy, sta, MAC_ARG(sta_copy->cmn.mac_addr));
 	}
 
 	/* The current setting does not support Beaforming */
@@ -1799,6 +1792,7 @@ void rtw_bf_init(PADAPTER adapter)
 	info->beamformee_mu_reg_maping = 0;
 	info->first_mu_bfee_index = 0xFF;
 	info->mu_bfer_curidx = 0xFF;
+	info->cur_csi_rpt_rate = HALMAC_OFDM24;
 
 	_sounding_init(&info->sounding_info);
 	rtw_init_timer(&info->sounding_timer, adapter, _sounding_timer_handler, adapter);
@@ -1837,7 +1831,7 @@ void rtw_bf_cmd_hdl(PADAPTER adapter, u8 type, u8 *pbuf)
 		break;
 
 	case BEAMFORMING_CTRL_SET_GID_TABLE:
-		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_SET_GID_TABLE, *(void**)pbuf);
+		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_SET_GID_TABLE, pbuf);
 		break;
 
 	case BEAMFORMING_CTRL_SET_CSI_REPORT:
@@ -1907,8 +1901,8 @@ exit:
 void rtw_bf_update_attrib(PADAPTER adapter, struct pkt_attrib *attrib, struct sta_info *sta)
 {
 	if (sta) {
-		attrib->txbf_g_id = sta->txbf_gid;
-		attrib->txbf_p_aid = sta->txbf_paid;
+		attrib->txbf_g_id = sta->cmn.bf_info.g_id;
+		attrib->txbf_p_aid = sta->cmn.bf_info.p_aid;
 	}
 }
 
@@ -1932,7 +1926,8 @@ void rtw_bf_update_traffic(PADAPTER adapter)
 	u16 tp[MAX_BEAMFORMEE_ENTRY_NUM] = {0};
 	u8 tx_rate[MAX_BEAMFORMEE_ENTRY_NUM] = {0};
 	u64 tx_bytes, last_bytes;
-	u32 time, last_timestamp;
+	u32 time;
+	systime last_timestamp;
 	u8 set_timer = _FALSE;
 
 
@@ -1967,7 +1962,7 @@ void rtw_bf_update_traffic(PADAPTER adapter)
 			time = rtw_get_time_interval_ms(last_timestamp, bfee->tx_timestamp);
 			time = (time > 1000) ? time/1000 : 1;
 			tp[i] = toMbps(tx_bytes, time);
-			tx_rate[i] = rtw_get_current_tx_rate(adapter, bfee->mac_id);
+			tx_rate[i] = rtw_get_current_tx_rate(adapter, sta);
 			RTW_INFO("%s: BFee idx(%d), MadId(%d), TxTP=%lld bytes (%d Mbps), txrate=%d\n",
 				 __FUNCTION__, i, bfee->mac_id, tx_bytes, tp[i], tx_rate[i]);
 		}
@@ -2059,7 +2054,7 @@ struct beamforming_entry	*beamforming_get_free_entry(struct mlme_priv *pmlmepriv
 
 
 struct beamforming_entry	*beamforming_add_entry(PADAPTER adapter, u8 *ra, u16 aid,
-	u16 mac_id, CHANNEL_WIDTH bw, BEAMFORMING_CAP beamfrom_cap, u8 *idx)
+	u16 mac_id, enum channel_width bw, BEAMFORMING_CAP beamfrom_cap, u8 *idx)
 {
 	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
 	struct beamforming_entry	*pEntry = beamforming_get_free_entry(pmlmepriv, idx);
@@ -2121,8 +2116,10 @@ void	beamforming_dym_ndpa_rate(PADAPTER adapter)
 {
 	u16	NDPARate = MGN_6M;
 	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(adapter);
+	s8 min_rssi = 0;
 
-	if (pHalData->min_undecorated_pwdb_for_dm > 30) /* link RSSI > 30% */
+	min_rssi = rtw_phydm_get_min_rssi(adapter);
+	if (min_rssi > 30) /* link RSSI > 30% */
 		NDPARate = MGN_24M;
 	else
 		NDPARate = MGN_6M;
@@ -2175,7 +2172,7 @@ void beamforming_dym_period(PADAPTER Adapter)
 		rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&Idx);
 }
 
-BOOLEAN	issue_ht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx)
+BOOLEAN	issue_ht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, enum channel_width bw, u8 qidx)
 {
 	struct xmit_frame		*pmgntframe;
 	struct pkt_attrib		*pattrib;
@@ -2254,7 +2251,7 @@ BOOLEAN	issue_ht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 q
 
 
 }
-BOOLEAN	issue_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx)
+BOOLEAN	issue_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, enum channel_width bw, u8 qidx)
 {
 	struct xmit_frame		*pmgntframe;
 	struct pkt_attrib		*pattrib;
@@ -2329,11 +2326,11 @@ BOOLEAN	issue_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx
 	return _TRUE;
 }
 
-BOOLEAN	beamforming_send_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx)
+BOOLEAN	beamforming_send_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, enum channel_width bw, u8 qidx)
 {
 	return issue_ht_ndpa_packet(Adapter, ra, bw, qidx);
 }
-BOOLEAN	issue_vht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx)
+BOOLEAN	issue_vht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, enum channel_width bw, u8 qidx)
 {
 	struct xmit_frame		*pmgntframe;
 	struct pkt_attrib		*pattrib;
@@ -2427,7 +2424,7 @@ BOOLEAN	issue_vht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDT
 	return _TRUE;
 
 }
-BOOLEAN	issue_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx)
+BOOLEAN	issue_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, enum channel_width bw, u8 qidx)
 {
 	struct xmit_frame		*pmgntframe;
 	struct pkt_attrib		*pattrib;
@@ -2513,7 +2510,7 @@ BOOLEAN	issue_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH b
 	return _TRUE;
 }
 
-BOOLEAN	beamforming_send_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx)
+BOOLEAN	beamforming_send_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, enum channel_width bw, u8 qidx)
 {
 	return issue_vht_ndpa_packet(Adapter, ra, aid, bw, qidx);
 }
@@ -2571,9 +2568,9 @@ u16	beamforming_sounding_time(struct beamforming_info *pBeamInfo, SOUNDING_MODE
 	return sounding_time;
 }
 
-CHANNEL_WIDTH	beamforming_sounding_bw(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx)
+enum channel_width	beamforming_sounding_bw(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx)
 {
-	CHANNEL_WIDTH				sounding_bw = CHANNEL_WIDTH_20;
+	enum channel_width				sounding_bw = CHANNEL_WIDTH_20;
 	struct beamforming_entry		BeamEntry = pBeamInfo->beamforming_entry[idx];
 
 	sounding_bw = BeamEntry.sound_bw;
@@ -2710,7 +2707,7 @@ BOOLEAN	beamforming_init_entry(PADAPTER	adapter, struct sta_info *psta, u8 *idx)
 	u8	*ra;
 	u16	aid, mac_id;
 	u8	wireless_mode;
-	CHANNEL_WIDTH	bw = CHANNEL_WIDTH_20;
+	enum channel_width	bw = CHANNEL_WIDTH_20;
 	BEAMFORMING_CAP	beamform_cap = BEAMFORMING_CAP_NONE;
 
 	/* The current setting does not support Beaforming */
@@ -2723,11 +2720,11 @@ BOOLEAN	beamforming_init_entry(PADAPTER	adapter, struct sta_info *psta, u8 *idx)
 		return _FALSE;
 	}
 
-	aid = psta->aid;
-	ra = psta->hwaddr;
-	mac_id = psta->mac_id;
+	aid = psta->cmn.aid;
+	ra = psta->cmn.mac_addr;
+	mac_id = psta->cmn.mac_id;
 	wireless_mode = psta->wireless_mode;
-	bw = psta->bw_mode;
+	bw = psta->cmn.bw_mode;
 
 	if (is_supported_ht(wireless_mode) || is_supported_vht(wireless_mode)) {
 		/* 3 */ /* HT */
@@ -2779,8 +2776,8 @@ BOOLEAN	beamforming_init_entry(PADAPTER	adapter, struct sta_info *psta, u8 *idx)
 		}
 
 		pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
-		psta->txbf_paid = pBeamformEntry->p_aid;
-		psta->txbf_gid = pBeamformEntry->g_id;
+		psta->cmn.bf_info.p_aid = pBeamformEntry->p_aid;
+		psta->cmn.bf_info.g_id = pBeamformEntry->g_id;
 
 		RTW_INFO("%s Idx %d\n", __FUNCTION__, *idx);
 	} else
@@ -2919,7 +2916,7 @@ u32	rtw_beamforming_get_report_frame(PADAPTER	 Adapter, union recv_frame *precv_
 	u32	ret = _SUCCESS;
 #if (BEAMFORMING_SUPPORT == 1)
 	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(Adapter);
-	struct PHY_DM_STRUCT		*pDM_Odm = &(pHalData->odmpriv);
+	struct dm_struct		*pDM_Odm = &(pHalData->odmpriv);
 
 	ret = beamforming_get_report_frame(pDM_Odm, precv_frame);
 
@@ -2966,7 +2963,7 @@ void	rtw_beamforming_get_ndpa_frame(PADAPTER	 Adapter, union recv_frame *precv_f
 {
 #if (BEAMFORMING_SUPPORT == 1)
 	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(Adapter);
-	struct PHY_DM_STRUCT		*pDM_Odm = &(pHalData->odmpriv);
+	struct dm_struct		*pDM_Odm = &(pHalData->odmpriv);
 
 	beamforming_get_ndpa_frame(pDM_Odm, precv_frame);
 
@@ -3042,13 +3039,13 @@ void	rtw_beamforming_get_ndpa_frame(PADAPTER	 Adapter, union recv_frame *precv_f
 void	beamforming_wk_hdl(_adapter *padapter, u8 type, u8 *pbuf)
 {
 	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
-	struct PHY_DM_STRUCT		*pDM_Odm = &(pHalData->odmpriv);
+	struct dm_struct		*pDM_Odm = &(pHalData->odmpriv);
 
 #if (BEAMFORMING_SUPPORT == 1) /*(BEAMFORMING_SUPPORT == 1)- for PHYDM beamfoming*/
 	switch (type) {
 	case BEAMFORMING_CTRL_ENTER: {
 		struct sta_info	*psta = (PVOID)pbuf;
-		u16			staIdx = psta->mac_id;
+		u16			staIdx = psta->cmn.mac_id;
 
 		beamforming_enter(pDM_Odm, staIdx);
 		break;
@@ -3089,8 +3086,14 @@ u8	beamforming_wk_cmd(_adapter *padapter, s32 type, u8 *pbuf, s32 size, u8 enque
 	struct cmd_obj	*ph2c;
 	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
 	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 	u8	res = _SUCCESS;
 
+	/*20170214 ad_hoc mode and mp_mode not support BF*/
+	if ((padapter->registrypriv.mp_mode == 1)
+		|| (pmlmeinfo->state == WIFI_FW_ADHOC_STATE))
+		return res;
 
 	if (enqueue) {
 		u8	*wk_buf;
@@ -3143,8 +3146,8 @@ exit:
 void update_attrib_txbf_info(_adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta)
 {
 	if (psta) {
-		pattrib->txbf_g_id = psta->txbf_gid;
-		pattrib->txbf_p_aid = psta->txbf_paid;
+		pattrib->txbf_g_id = psta->cmn.bf_info.g_id;
+		pattrib->txbf_p_aid = psta->cmn.bf_info.p_aid;
 	}
 }
 #endif /* !RTW_BEAMFORMING_VERSION_2 */

+ 4 - 8
core/rtw_br_ext.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_BR_EXT_C_
 
 #ifdef __KERNEL__
@@ -306,7 +301,7 @@ static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char
 	return 0;
 }
 
-
+#ifdef SUPPORT_RX_UNI2MCAST
 static void convert_ipv6_mac_to_mc(struct sk_buff *skb)
 {
 	struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
@@ -324,6 +319,7 @@ static void convert_ipv6_mac_to_mc(struct sk_buff *skb)
 #endif
 }
 #endif /* CL_IPV6_PASS */
+#endif /* SUPPORT_RX_UNI2MCAST */
 
 
 static __inline__ int __nat25_network_hash(unsigned char *networkAddr)

+ 3 - 8
core/rtw_bt_mp.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 
 
 #include <drv_types.h>
@@ -471,7 +466,7 @@ MPTBT_FwC2hBtMpCtrl(
 	PMPT_CONTEXT	pMptCtx = &(Adapter->mppriv.mpt_ctx);
 	PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)tmpBuf;
 
-	if (Adapter->bBTFWReady == _FALSE || Adapter->registrypriv.mp_mode == 0) {
+	if (GET_HAL_DATA(Adapter)->bBTFWReady == _FALSE || Adapter->registrypriv.mp_mode == 0) {
 		/* RTW_INFO("Ignore C2H BT MP Info since not in MP mode\n"); */
 		return;
 	}

+ 38 - 11
core/rtw_btcoex.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2013 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2017 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
@@ -11,18 +11,11 @@
  * 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
- *
- *
- ******************************************************************************/
-#ifdef CONFIG_BT_COEXIST
-
+ *****************************************************************************/
 #include <drv_types.h>
-#include <hal_btcoex.h>
 #include <hal_data.h>
-
+#ifdef CONFIG_BT_COEXIST
+#include <hal_btcoex.h>
 
 void rtw_btcoex_Initialize(PADAPTER padapter)
 {
@@ -34,6 +27,11 @@ void rtw_btcoex_PowerOnSetting(PADAPTER padapter)
 	hal_btcoex_PowerOnSetting(padapter);
 }
 
+void rtw_btcoex_AntInfoSetting(PADAPTER padapter)
+{
+	hal_btcoex_AntInfoSetting(padapter);
+}
+
 void rtw_btcoex_PowerOffSetting(PADAPTER padapter)
 {
 	hal_btcoex_PowerOffSetting(padapter);
@@ -245,6 +243,16 @@ void rtw_btcoex_switchband_notify(u8 under_scan, u8 band_type)
 	hal_btcoex_switchband_notify(under_scan, band_type);
 }
 
+void rtw_btcoex_WlFwDbgInfoNotify(PADAPTER padapter, u8* tmpBuf, u8 length)
+{
+	hal_btcoex_WlFwDbgInfoNotify(padapter, tmpBuf, length);
+}
+
+void rtw_btcoex_rx_rate_change_notify(PADAPTER padapter, u8 is_data_frame, u8 rate_id)
+{
+	hal_btcoex_rx_rate_change_notify(padapter, is_data_frame, rate_id);
+}
+
 void rtw_btcoex_SwitchBtTRxMask(PADAPTER padapter)
 {
 	hal_btcoex_SwitchBtTRxMask(padapter);
@@ -1734,3 +1742,22 @@ void rtw_btcoex_SendScanNotify(PADAPTER padapter, u8 scanType)
 }
 #endif /* CONFIG_BT_COEXIST_SOCKET_TRX */
 #endif /* CONFIG_BT_COEXIST */
+
+void rtw_btcoex_set_ant_info(PADAPTER padapter)
+{
+#ifdef CONFIG_BT_COEXIST
+	PHAL_DATA_TYPE hal = GET_HAL_DATA(padapter);
+
+	if (hal->EEPROMBluetoothCoexist == _TRUE) {
+		u8 bMacPwrCtrlOn = _FALSE;
+
+		rtw_btcoex_AntInfoSetting(padapter);
+		rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+		if (bMacPwrCtrlOn == _TRUE)
+			rtw_btcoex_PowerOnSetting(padapter);
+	}
+	else
+#endif
+		rtw_btcoex_wifionly_AntInfoSetting(padapter);
+}
+

+ 12 - 7
core/rtw_btcoex_wifionly.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2013 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #include <drv_types.h>
 #include <hal_btcoex_wifionly.h>
 #include <hal_data.h>
@@ -31,6 +26,11 @@ void rtw_btcoex_wifionly_scan_notify(PADAPTER padapter)
 	hal_btcoex_wifionly_scan_notify(padapter);
 }
 
+void rtw_btcoex_wifionly_connect_notify(PADAPTER padapter)
+{
+	hal_btcoex_wifionly_connect_notify(padapter);
+}
+
 void rtw_btcoex_wifionly_hw_config(PADAPTER padapter)
 {
 	hal_btcoex_wifionly_hw_config(padapter);
@@ -40,3 +40,8 @@ void rtw_btcoex_wifionly_initialize(PADAPTER padapter)
 {
 	hal_btcoex_wifionly_initlizevariables(padapter);
 }
+
+void rtw_btcoex_wifionly_AntInfoSetting(PADAPTER padapter)
+{
+	hal_btcoex_wifionly_AntInfoSetting(padapter);
+}

+ 1184 - 0
core/rtw_chplan.c

@@ -0,0 +1,1184 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2018 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.
+ *
+ *****************************************************************************/
+#define _RTW_CHPLAN_C_
+
+#include <drv_types.h>
+
+#define RTW_DOMAIN_MAP_VER	"35e"
+#define RTW_COUNTRY_MAP_VER	"20"
+
+#ifdef LEGACY_CHANNEL_PLAN_REF
+/********************************************************
+ChannelPlan definitions
+*********************************************************/
+static RT_CHANNEL_PLAN legacy_channel_plan[] = {
+	/* 0x00, RTW_CHPLAN_FCC */						{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 32},
+	/* 0x01, RTW_CHPLAN_IC */						{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 31},
+	/* 0x02, RTW_CHPLAN_ETSI */						{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 32},
+	/* 0x03, RTW_CHPLAN_SPAIN */						{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
+	/* 0x04, RTW_CHPLAN_FRANCE */					{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
+	/* 0x05, RTW_CHPLAN_MKK */						{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
+	/* 0x06, RTW_CHPLAN_MKK1 */						{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
+	/* 0x07, RTW_CHPLAN_ISRAEL */					{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21},
+	/* 0x08, RTW_CHPLAN_TELEC */						{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, 56, 60, 64}, 22},
+	/* 0x09, RTW_CHPLAN_GLOBAL_DOAMIN */			{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14},
+	/* 0x0A, RTW_CHPLAN_WORLD_WIDE_13 */			{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
+	/* 0x0B, RTW_CHPLAN_TAIWAN */					{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 26},
+	/* 0x0C, RTW_CHPLAN_CHINA */					{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 149, 153, 157, 161, 165}, 18},
+	/* 0x0D, RTW_CHPLAN_SINGAPORE_INDIA_MEXICO */	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 24},
+	/* 0x0E, RTW_CHPLAN_KOREA */					{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165}, 31},
+	/* 0x0F, RTW_CHPLAN_TURKEY */					{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64}, 19},
+	/* 0x10, RTW_CHPLAN_JAPAN */						{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 32},
+	/* 0x11, RTW_CHPLAN_FCC_NO_DFS */				{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 149, 153, 157, 161, 165}, 20},
+	/* 0x12, RTW_CHPLAN_JAPAN_NO_DFS */				{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48}, 17},
+	/* 0x13, RTW_CHPLAN_WORLD_WIDE_5G */			{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 37},
+	/* 0x14, RTW_CHPLAN_TAIWAN_NO_DFS */			{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 56, 60, 64, 149, 153, 157, 161, 165}, 19},
+};
+#endif
+
+enum rtw_rd_2g {
+	RTW_RD_2G_NULL = 0,
+	RTW_RD_2G_WORLD = 1,	/* Worldwird 13 */
+	RTW_RD_2G_ETSI1 = 2,	/* Europe */
+	RTW_RD_2G_FCC1 = 3,		/* US */
+	RTW_RD_2G_MKK1 = 4,		/* Japan */
+	RTW_RD_2G_ETSI2 = 5,	/* France */
+	RTW_RD_2G_GLOBAL = 6,	/* Global domain */
+	RTW_RD_2G_MKK2 = 7,		/* Japan */
+	RTW_RD_2G_FCC2 = 8,		/* US */
+	RTW_RD_2G_IC1 = 9,		/* Canada */
+	RTW_RD_2G_WORLD1 = 10,	/* Worldwide 11 */
+	RTW_RD_2G_KCC1 = 11,	/* Korea */
+
+	RTW_RD_2G_MAX,
+};
+
+enum rtw_rd_5g {
+	RTW_RD_5G_NULL = 0,		/*	*/
+	RTW_RD_5G_ETSI1 = 1,	/* Europe */
+	RTW_RD_5G_ETSI2 = 2,	/* Australia, New Zealand */
+	RTW_RD_5G_ETSI3 = 3,	/* Russia */
+	RTW_RD_5G_FCC1 = 4,		/* US */
+	RTW_RD_5G_FCC2 = 5,		/* FCC w/o DFS Channels */
+	RTW_RD_5G_FCC3 = 6,		/* Bolivia, Chile, El Salvador, Venezuela */
+	RTW_RD_5G_FCC4 = 7,		/* Venezuela */
+	RTW_RD_5G_FCC5 = 8,		/* China */
+	RTW_RD_5G_FCC6 = 9,		/*	*/
+	RTW_RD_5G_FCC7 = 10,	/* US(w/o Weather radar) */
+	RTW_RD_5G_IC1 = 11,		/* Canada(w/o Weather radar) */
+	RTW_RD_5G_KCC1 = 12,	/* Korea */
+	RTW_RD_5G_MKK1 = 13,	/* Japan */
+	RTW_RD_5G_MKK2 = 14,	/* Japan (W52, W53) */
+	RTW_RD_5G_MKK3 = 15,	/* Japan (W56) */
+	RTW_RD_5G_NCC1 = 16,	/* Taiwan, (w/o Weather radar) */
+	RTW_RD_5G_NCC2 = 17,	/* Taiwan, Band2, Band4 */
+	RTW_RD_5G_NCC3 = 18,	/* Taiwan w/o DFS, Band4 only */
+	RTW_RD_5G_ETSI4 = 19,	/* Europe w/o DFS, Band1 only */
+	RTW_RD_5G_ETSI5 = 20,	/* Australia, New Zealand(w/o Weather radar) */
+	RTW_RD_5G_FCC8 = 21,	/* Latin America */
+	RTW_RD_5G_ETSI6 = 22,	/* Israel, Bahrain, Egypt, India, China, Malaysia */
+	RTW_RD_5G_ETSI7 = 23,	/* China */
+	RTW_RD_5G_ETSI8 = 24,	/* Jordan */
+	RTW_RD_5G_ETSI9 = 25,	/* Lebanon */
+	RTW_RD_5G_ETSI10 = 26,	/* Qatar */
+	RTW_RD_5G_ETSI11 = 27,	/* Russia */
+	RTW_RD_5G_NCC4 = 28,	/* Taiwan, (w/o Weather radar) */
+	RTW_RD_5G_ETSI12 = 29,	/* Indonesia */
+	RTW_RD_5G_FCC9 = 30,	/* (w/o Weather radar) */
+	RTW_RD_5G_ETSI13 = 31,	/* (w/o Weather radar) */
+	RTW_RD_5G_FCC10 = 32,	/* Argentina(w/o Weather radar) */
+	RTW_RD_5G_MKK4 = 33,	/* Japan (W52) */
+	RTW_RD_5G_ETSI14 = 34,	/* Russia */
+	RTW_RD_5G_FCC11 = 35,	/* US(include CH144) */
+	RTW_RD_5G_ETSI15 = 36,	/* Malaysia */
+	RTW_RD_5G_MKK5 = 37,	/* Japan */
+	RTW_RD_5G_ETSI16 = 38,	/* Europe */
+	RTW_RD_5G_ETSI17 = 39,	/* Europe */
+	RTW_RD_5G_FCC12 = 40,	/* FCC */
+	RTW_RD_5G_FCC13 = 41,	/* FCC */
+	RTW_RD_5G_FCC14 = 42,	/* FCC w/o Weather radar(w/o 5600~5650MHz) */
+	RTW_RD_5G_FCC15 = 43,	/* FCC w/o Band3 */
+	RTW_RD_5G_FCC16 = 44,	/* FCC w/o Band3 */
+	RTW_RD_5G_ETSI18 = 45,	/* ETSI w/o DFS Band2&3 */
+	RTW_RD_5G_ETSI19 = 46,	/* Europe */
+	RTW_RD_5G_FCC17 = 47,	/* FCC w/o Weather radar(w/o 5600~5650MHz) */
+	RTW_RD_5G_ETSI20 = 48,	/* Europe */
+	RTW_RD_5G_IC2 = 49,		/* Canada(w/o Weather radar), include ch144 */
+	RTW_RD_5G_ETSI21 = 50,	/* Australia, New Zealand(w/o Weather radar) */
+	RTW_RD_5G_FCC18 = 51,	/*  */
+	RTW_RD_5G_WORLD = 52,	/* Worldwide */
+	RTW_RD_5G_CHILE1 = 53,	/* Chile */
+	RTW_RD_5G_ACMA1 = 54,	/* Australia, New Zealand (w/o Weather radar) (w/o Ch120~Ch128) */
+	RTW_RD_5G_WORLD1 = 55,	/* 5G Worldwide Band1&2 */
+	RTW_RD_5G_CHILE2 = 56,	/* Chile (Band2,Band3) */
+	RTW_RD_5G_KCC2 = 57,	/* Korea (New standard) */
+
+	/* === Below are driver defined for legacy channel plan compatible, DON'T assign index ==== */
+	RTW_RD_5G_OLD_FCC1,
+	RTW_RD_5G_OLD_NCC1,
+	RTW_RD_5G_OLD_KCC1,
+
+	RTW_RD_5G_MAX,
+};
+
+struct ch_list_t {
+	u8 *len_ch;
+};
+
+#define CH_LIST_ENT(_len, arg...) \
+	{.len_ch = (u8[_len + 1]) {_len, ##arg}, }
+
+#define CH_LIST_LEN(_ch_list) (_ch_list.len_ch[0])
+#define CH_LIST_CH(_ch_list, _i) (_ch_list.len_ch[_i + 1])
+
+struct chplan_ent_t {
+	u8 rd_2g;
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+	u8 rd_5g;
+#endif
+	u8 regd; /* value of REGULATION_TXPWR_LMT */
+};
+
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+#define CHPLAN_ENT(i2g, i5g, regd) {i2g, i5g, regd}
+#else
+#define CHPLAN_ENT(i2g, i5g, regd) {i2g, regd}
+#endif
+
+static struct ch_list_t RTW_ChannelPlan2G[] = {
+	/* 0, RTW_RD_2G_NULL */		CH_LIST_ENT(0),
+	/* 1, RTW_RD_2G_WORLD */	CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+	/* 2, RTW_RD_2G_ETSI1 */		CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+	/* 3, RTW_RD_2G_FCC1 */		CH_LIST_ENT(11, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
+	/* 4, RTW_RD_2G_MKK1 */		CH_LIST_ENT(14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
+	/* 5, RTW_RD_2G_ETSI2 */		CH_LIST_ENT(4, 10, 11, 12, 13),
+	/* 6, RTW_RD_2G_GLOBAL */	CH_LIST_ENT(14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
+	/* 7, RTW_RD_2G_MKK2 */		CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+	/* 8, RTW_RD_2G_FCC2 */		CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+	/* 9, RTW_RD_2G_IC1 */		CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+	/* 10, RTW_RD_2G_WORLD1 */	CH_LIST_ENT(11, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
+	/* 11, RTW_RD_2G_KCC1 */	CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+};
+
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+static struct ch_list_t RTW_ChannelPlan5G[] = {
+	/* 0, RTW_RD_5G_NULL */		CH_LIST_ENT(0),
+	/* 1, RTW_RD_5G_ETSI1 */		CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140),
+	/* 2, RTW_RD_5G_ETSI2 */		CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 3, RTW_RD_5G_ETSI3 */		CH_LIST_ENT(22, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 149, 153, 157, 161, 165),
+	/* 4, RTW_RD_5G_FCC1 */		CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 5, RTW_RD_5G_FCC2 */		CH_LIST_ENT(9, 36, 40, 44, 48, 149, 153, 157, 161, 165),
+	/* 6, RTW_RD_5G_FCC3 */		CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 7, RTW_RD_5G_FCC4 */		CH_LIST_ENT(12, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161),
+	/* 8, RTW_RD_5G_FCC5 */		CH_LIST_ENT(5, 149, 153, 157, 161, 165),
+	/* 9, RTW_RD_5G_FCC6 */		CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64),
+	/* 10, RTW_RD_5G_FCC7 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 11, RTW_RD_5G_IC1 */		CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 12, RTW_RD_5G_KCC1 */	CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161),
+	/* 13, RTW_RD_5G_MKK1 */	CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140),
+	/* 14, RTW_RD_5G_MKK2 */	CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64),
+	/* 15, RTW_RD_5G_MKK3 */	CH_LIST_ENT(11, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140),
+	/* 16, RTW_RD_5G_NCC1 */	CH_LIST_ENT(16, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 17, RTW_RD_5G_NCC2 */	CH_LIST_ENT(8, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 18, RTW_RD_5G_NCC3 */	CH_LIST_ENT(5, 149, 153, 157, 161, 165),
+	/* 19, RTW_RD_5G_ETSI4 */	CH_LIST_ENT(4, 36, 40, 44, 48),
+	/* 20, RTW_RD_5G_ETSI5 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 21, RTW_RD_5G_FCC8 */	CH_LIST_ENT(4, 149, 153, 157, 161),
+	/* 22, RTW_RD_5G_ETSI6 */	CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64),
+	/* 23, RTW_RD_5G_ETSI7 */	CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 24, RTW_RD_5G_ETSI8 */	CH_LIST_ENT(9, 36, 40, 44, 48, 149, 153, 157, 161, 165),
+	/* 25, RTW_RD_5G_ETSI9 */	CH_LIST_ENT(11, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140),
+	/* 26, RTW_RD_5G_ETSI10 */	CH_LIST_ENT(5, 149, 153, 157, 161, 165),
+	/* 27, RTW_RD_5G_ETSI11 */	CH_LIST_ENT(16, 36, 40, 44, 48, 52, 56, 60, 64, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 28, RTW_RD_5G_NCC4 */	CH_LIST_ENT(17, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 29, RTW_RD_5G_ETSI12 */	CH_LIST_ENT(4, 149, 153, 157, 161),
+	/* 30, RTW_RD_5G_FCC9 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 31, RTW_RD_5G_ETSI13 */	CH_LIST_ENT(16, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140),
+	/* 32, RTW_RD_5G_FCC10 */	CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161),
+	/* 33, RTW_RD_5G_MKK4 */	CH_LIST_ENT(4, 36, 40, 44, 48),
+	/* 34, RTW_RD_5G_ETSI14 */	CH_LIST_ENT(11, 36, 40, 44, 48, 52, 56, 60, 64, 132, 136, 140),
+	/* 35, RTW_RD_5G_FCC11 */	CH_LIST_ENT(25, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165),
+	/* 36, RTW_RD_5G_ETSI15 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 149, 153, 157, 161, 165),
+	/* 37, RTW_RD_5G_MKK5 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 38, RTW_RD_5G_ETSI16 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 39, RTW_RD_5G_ETSI17 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 40, RTW_RD_5G_FCC12*/	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 41, RTW_RD_5G_FCC13 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 42, RTW_RD_5G_FCC14 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 43, RTW_RD_5G_FCC15 */	CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 44, RTW_RD_5G_FCC16 */	CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 45, RTW_RD_5G_ETSI18 */	CH_LIST_ENT(9, 36, 40, 44, 48, 149, 153, 157, 161, 165),
+	/* 46, RTW_RD_5G_ETSI19 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 47, RTW_RD_5G_FCC17 */	CH_LIST_ENT(16, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140),
+	/* 48, RTW_RD_5G_ETSI20 */	CH_LIST_ENT(9, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 49, RTW_RD_5G_IC2 */		CH_LIST_ENT(22, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 144, 149, 153, 157, 161, 165),
+	/* 50, RTW_RD_5G_ETSI21 */	CH_LIST_ENT(13, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 51, RTW_RD_5G_FCC18 */	CH_LIST_ENT(8, 100, 104, 108, 112, 116, 132, 136, 140),
+	/* 52, RTW_RD_5G_WORLD */	CH_LIST_ENT(25, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165),
+	/* 53, RTW_RD_5G_CHILE1 */	CH_LIST_ENT(25, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165),
+	/* 54, RTW_RD_5G_ACMA1 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 55, RTW_RD_5G_WORLD1 */	CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64),
+	/* 56, RTW_RD_5G_CHILE2 */	CH_LIST_ENT(16, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144),
+	/* 57, RTW_RD_5G_KCC2 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+
+	/* === Below are driver defined for legacy channel plan compatible, NO static index assigned ==== */
+	/* RTW_RD_5G_OLD_FCC1 */	CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165),
+	/* RTW_RD_5G_OLD_NCC1 */	CH_LIST_ENT(15, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165),
+	/* RTW_RD_5G_OLD_KCC1 */	CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165),
+};
+#endif /* CONFIG_IEEE80211_BAND_5GHZ */
+
+static struct chplan_ent_t RTW_ChannelPlanMap[RTW_CHPLAN_MAX] = {
+	/* ===== 0x00 ~ 0x1F, legacy channel plan ===== */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_KCC1,		TXPWR_LMT_FCC),		/* 0x00, RTW_CHPLAN_FCC */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_OLD_FCC1,	TXPWR_LMT_FCC),		/* 0x01, RTW_CHPLAN_IC */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI1,	TXPWR_LMT_ETSI),	/* 0x02, RTW_CHPLAN_ETSI */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_NULL,		TXPWR_LMT_ETSI),	/* 0x03, RTW_CHPLAN_SPAIN */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_NULL,		TXPWR_LMT_ETSI),	/* 0x04, RTW_CHPLAN_FRANCE */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_NULL,		TXPWR_LMT_MKK),		/* 0x05, RTW_CHPLAN_MKK */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_NULL,		TXPWR_LMT_MKK),		/* 0x06, RTW_CHPLAN_MKK1 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_FCC6,		TXPWR_LMT_ETSI),	/* 0x07, RTW_CHPLAN_ISRAEL */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_FCC6,		TXPWR_LMT_MKK),		/* 0x08, RTW_CHPLAN_TELEC */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x09, RTW_CHPLAN_GLOBAL_DOAMIN */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x0A, RTW_CHPLAN_WORLD_WIDE_13 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_OLD_NCC1,	TXPWR_LMT_FCC),		/* 0x0B, RTW_CHPLAN_TAIWAN */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_FCC5,		TXPWR_LMT_ETSI),	/* 0x0C, RTW_CHPLAN_CHINA */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC3,		TXPWR_LMT_WW),		/* 0x0D, RTW_CHPLAN_SINGAPORE_INDIA_MEXICO */ /* ETSI:Singapore, India. FCC:Mexico => WW */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_OLD_KCC1,	TXPWR_LMT_ETSI),	/* 0x0E, RTW_CHPLAN_KOREA */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC6,		TXPWR_LMT_ETSI),	/* 0x0F, RTW_CHPLAN_TURKEY */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI1,	TXPWR_LMT_MKK),		/* 0x10, RTW_CHPLAN_JAPAN */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC2,		TXPWR_LMT_FCC),		/* 0x11, RTW_CHPLAN_FCC_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_FCC7,		TXPWR_LMT_MKK),		/* 0x12, RTW_CHPLAN_JAPAN_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC1,		TXPWR_LMT_WW),		/* 0x13, RTW_CHPLAN_WORLD_WIDE_5G */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC2,		TXPWR_LMT_FCC),		/* 0x14, RTW_CHPLAN_TAIWAN_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC7,		TXPWR_LMT_ETSI),	/* 0x15, RTW_CHPLAN_ETSI_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_NCC1,		TXPWR_LMT_ETSI),	/* 0x16, RTW_CHPLAN_KOREA_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_FCC7,		TXPWR_LMT_MKK),		/* 0x17, RTW_CHPLAN_JAPAN_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_FCC5,		TXPWR_LMT_ETSI),	/* 0x18, RTW_CHPLAN_PAKISTAN_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC5,		TXPWR_LMT_FCC),		/* 0x19, RTW_CHPLAN_TAIWAN2_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1A, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1B, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1C, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1D, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1E, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_FCC1,		TXPWR_LMT_WW),		/* 0x1F, RTW_CHPLAN_WORLD_WIDE_ONLY_5G */
+
+	/* ===== 0x20 ~ 0x7F, new channel plan ===== */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x20, RTW_CHPLAN_WORLD_NULL */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_NULL,		TXPWR_LMT_ETSI),	/* 0x21, RTW_CHPLAN_ETSI1_NULL */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NULL,		TXPWR_LMT_FCC),		/* 0x22, RTW_CHPLAN_FCC1_NULL */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_NULL,		TXPWR_LMT_MKK),		/* 0x23, RTW_CHPLAN_MKK1_NULL */
+	CHPLAN_ENT(RTW_RD_2G_ETSI2,		RTW_RD_5G_NULL,		TXPWR_LMT_ETSI),	/* 0x24, RTW_CHPLAN_ETSI2_NULL */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC1,		TXPWR_LMT_FCC),		/* 0x25, RTW_CHPLAN_FCC1_FCC1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI1,	TXPWR_LMT_ETSI),	/* 0x26, RTW_CHPLAN_WORLD_ETSI1 */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_MKK1,		TXPWR_LMT_MKK),		/* 0x27, RTW_CHPLAN_MKK1_MKK1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_KCC1,		TXPWR_LMT_KCC),		/* 0x28, RTW_CHPLAN_WORLD_KCC1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC2,		TXPWR_LMT_FCC),		/* 0x29, RTW_CHPLAN_WORLD_FCC2 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_NULL,		TXPWR_LMT_FCC),		/* 0x2A, RTW_CHPLAN_FCC2_NULL */
+	CHPLAN_ENT(RTW_RD_2G_IC1,		RTW_RD_5G_IC2,		TXPWR_LMT_IC),		/* 0x2B, RTW_CHPLAN_IC1_IC2 */
+	CHPLAN_ENT(RTW_RD_2G_MKK2,		RTW_RD_5G_NULL,		TXPWR_LMT_MKK),		/* 0x2C, RTW_CHPLAN_MKK2_NULL */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_CHILE1,	TXPWR_LMT_CHILE),	/* 0x2D, RTW_CHPLAN_WORLD_CHILE1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD1,	RTW_RD_5G_WORLD1,	TXPWR_LMT_WW),		/* 0x2E, RTW_CHPLAN_WORLD1_WORLD1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_CHILE2,	TXPWR_LMT_CHILE),	/* 0x2F, RTW_CHPLAN_WORLD_CHILE2 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC3,		TXPWR_LMT_FCC),		/* 0x30, RTW_CHPLAN_WORLD_FCC3 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC4,		TXPWR_LMT_FCC),		/* 0x31, RTW_CHPLAN_WORLD_FCC4 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC5,		TXPWR_LMT_FCC),		/* 0x32, RTW_CHPLAN_WORLD_FCC5 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC6,		TXPWR_LMT_FCC),		/* 0x33, RTW_CHPLAN_WORLD_FCC6 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC7,		TXPWR_LMT_FCC),		/* 0x34, RTW_CHPLAN_FCC1_FCC7 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI2,	TXPWR_LMT_ETSI),	/* 0x35, RTW_CHPLAN_WORLD_ETSI2 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI3,	TXPWR_LMT_ETSI),	/* 0x36, RTW_CHPLAN_WORLD_ETSI3 */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_MKK2,		TXPWR_LMT_MKK),		/* 0x37, RTW_CHPLAN_MKK1_MKK2 */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_MKK3,		TXPWR_LMT_MKK),		/* 0x38, RTW_CHPLAN_MKK1_MKK3 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC1,		TXPWR_LMT_FCC),		/* 0x39, RTW_CHPLAN_FCC1_NCC1 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI1,	TXPWR_LMT_ETSI),	/* 0x3A, RTW_CHPLAN_ETSI1_ETSI1 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ACMA1,	TXPWR_LMT_ACMA),	/* 0x3B, RTW_CHPLAN_ETSI1_ACMA1 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI6,	TXPWR_LMT_ETSI),	/* 0x3C, RTW_CHPLAN_ETSI1_ETSI6 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI12,	TXPWR_LMT_ETSI),	/* 0x3D, RTW_CHPLAN_ETSI1_ETSI12 */
+	CHPLAN_ENT(RTW_RD_2G_KCC1,		RTW_RD_5G_KCC2,		TXPWR_LMT_KCC),		/* 0x3E, RTW_CHPLAN_KCC1_KCC2 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x3F, */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC2,		TXPWR_LMT_FCC),		/* 0x40, RTW_CHPLAN_FCC1_NCC2 */
+	CHPLAN_ENT(RTW_RD_2G_GLOBAL,	RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x41, RTW_CHPLAN_GLOBAL_NULL */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI4,	TXPWR_LMT_ETSI),	/* 0x42, RTW_CHPLAN_ETSI1_ETSI4 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC2,		TXPWR_LMT_FCC),		/* 0x43, RTW_CHPLAN_FCC1_FCC2 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC3,		TXPWR_LMT_FCC),		/* 0x44, RTW_CHPLAN_FCC1_NCC3 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ACMA1,	TXPWR_LMT_ACMA),	/* 0x45, RTW_CHPLAN_WORLD_ACMA1 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC8,		TXPWR_LMT_FCC),		/* 0x46, RTW_CHPLAN_FCC1_FCC8 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI6,	TXPWR_LMT_ETSI),	/* 0x47, RTW_CHPLAN_WORLD_ETSI6 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI7,	TXPWR_LMT_ETSI),	/* 0x48, RTW_CHPLAN_WORLD_ETSI7 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI8,	TXPWR_LMT_ETSI),	/* 0x49, RTW_CHPLAN_WORLD_ETSI8 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4A, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4B, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4C, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4D, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4E, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4F, */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI9,	TXPWR_LMT_ETSI),	/* 0x50, RTW_CHPLAN_WORLD_ETSI9 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI10,	TXPWR_LMT_ETSI),	/* 0x51, RTW_CHPLAN_WORLD_ETSI10 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI11,	TXPWR_LMT_ETSI),	/* 0x52, RTW_CHPLAN_WORLD_ETSI11 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC4,		TXPWR_LMT_FCC),		/* 0x53, RTW_CHPLAN_FCC1_NCC4 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI12,	TXPWR_LMT_ETSI),	/* 0x54, RTW_CHPLAN_WORLD_ETSI12 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC9,		TXPWR_LMT_FCC),		/* 0x55, RTW_CHPLAN_FCC1_FCC9 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI13,	TXPWR_LMT_ETSI),	/* 0x56, RTW_CHPLAN_WORLD_ETSI13 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC10,	TXPWR_LMT_FCC),		/* 0x57, RTW_CHPLAN_FCC1_FCC10 */
+	CHPLAN_ENT(RTW_RD_2G_MKK2,		RTW_RD_5G_MKK4,		TXPWR_LMT_MKK),		/* 0x58, RTW_CHPLAN_MKK2_MKK4 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI14,	TXPWR_LMT_ETSI),	/* 0x59, RTW_CHPLAN_WORLD_ETSI14 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5A, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5B, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5C, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5D, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5E, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5F, */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC5,		TXPWR_LMT_FCC),		/* 0x60, RTW_CHPLAN_FCC1_FCC5 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC7,		TXPWR_LMT_FCC),		/* 0x61, RTW_CHPLAN_FCC2_FCC7 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC1,		TXPWR_LMT_FCC),		/* 0x62, RTW_CHPLAN_FCC2_FCC1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI15,	TXPWR_LMT_ETSI),	/* 0x63, RTW_CHPLAN_WORLD_ETSI15 */
+	CHPLAN_ENT(RTW_RD_2G_MKK2,		RTW_RD_5G_MKK5,		TXPWR_LMT_MKK),		/* 0x64, RTW_CHPLAN_MKK2_MKK5 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI16,	TXPWR_LMT_ETSI),	/* 0x65, RTW_CHPLAN_ETSI1_ETSI16 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC14,	TXPWR_LMT_FCC),		/* 0x66, RTW_CHPLAN_FCC1_FCC14 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC12,	TXPWR_LMT_FCC),		/* 0x67, RTW_CHPLAN_FCC1_FCC12 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC14,	TXPWR_LMT_FCC),		/* 0x68, RTW_CHPLAN_FCC2_FCC14 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC12,	TXPWR_LMT_FCC),		/* 0x69, RTW_CHPLAN_FCC2_FCC12 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI17,	TXPWR_LMT_ETSI),	/* 0x6A, RTW_CHPLAN_ETSI1_ETSI17 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC16,	TXPWR_LMT_FCC),		/* 0x6B, RTW_CHPLAN_WORLD_FCC16 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC13,	TXPWR_LMT_FCC),		/* 0x6C, RTW_CHPLAN_WORLD_FCC13 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC15,	TXPWR_LMT_FCC),		/* 0x6D, RTW_CHPLAN_FCC2_FCC15 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC12,	TXPWR_LMT_FCC),		/* 0x6E, RTW_CHPLAN_WORLD_FCC12 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_ETSI8,	TXPWR_LMT_ETSI),	/* 0x6F, RTW_CHPLAN_NULL_ETSI8 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_ETSI18,	TXPWR_LMT_ETSI),	/* 0x70, RTW_CHPLAN_NULL_ETSI18 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_ETSI17,	TXPWR_LMT_ETSI),	/* 0x71, RTW_CHPLAN_NULL_ETSI17 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_ETSI19,	TXPWR_LMT_ETSI),	/* 0x72, RTW_CHPLAN_NULL_ETSI19 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC7,		TXPWR_LMT_FCC),		/* 0x73, RTW_CHPLAN_WORLD_FCC7 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC17,	TXPWR_LMT_FCC),		/* 0x74, RTW_CHPLAN_FCC2_FCC17 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI20,	TXPWR_LMT_ETSI),	/* 0x75, RTW_CHPLAN_WORLD_ETSI20 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC11,	TXPWR_LMT_FCC),		/* 0x76, RTW_CHPLAN_FCC2_FCC11 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI21,	TXPWR_LMT_ETSI),	/* 0x77, RTW_CHPLAN_WORLD_ETSI21 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC18,	TXPWR_LMT_FCC),		/* 0x78, RTW_CHPLAN_FCC1_FCC18 */
+	CHPLAN_ENT(RTW_RD_2G_MKK2,		RTW_RD_5G_MKK1,		TXPWR_LMT_MKK),		/* 0x79, RTW_CHPLAN_MKK2_MKK1 */
+};
+
+static struct chplan_ent_t RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE =
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC1,		TXPWR_LMT_FCC);		/* 0x7F, Realtek Define */
+
+u8 rtw_chplan_get_default_regd(u8 id)
+{
+	u8 regd;
+
+	if (id == RTW_CHPLAN_REALTEK_DEFINE)
+		regd = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.regd;
+	else
+		regd = RTW_ChannelPlanMap[id].regd;
+
+	return regd;
+}
+
+bool rtw_chplan_is_empty(u8 id)
+{
+	struct chplan_ent_t *chplan_map;
+
+	if (id == RTW_CHPLAN_REALTEK_DEFINE)
+		chplan_map = &RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE;
+	else
+		chplan_map = &RTW_ChannelPlanMap[id];
+
+	if (chplan_map->rd_2g == RTW_RD_2G_NULL
+		#ifdef CONFIG_IEEE80211_BAND_5GHZ
+		&& chplan_map->rd_5g == RTW_RD_5G_NULL
+		#endif
+	)
+		return _TRUE;
+
+	return _FALSE;
+}
+
+bool rtw_regsty_is_excl_chs(struct registry_priv *regsty, u8 ch)
+{
+	int i;
+
+	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+		if (regsty->excl_chs[i] == 0)
+			break;
+		if (regsty->excl_chs[i] == ch)
+			return _TRUE;
+	}
+	return _FALSE;
+}
+
+inline static u8 rtw_rd_5g_band1_passive(u8 rtw_rd_5g)
+{
+	u8 passive = 0;
+
+	switch (rtw_rd_5g) {
+	case RTW_RD_5G_FCC13:
+	case RTW_RD_5G_FCC16:
+	case RTW_RD_5G_ETSI18:
+	case RTW_RD_5G_ETSI19:
+	case RTW_RD_5G_WORLD:
+	case RTW_RD_5G_WORLD1:
+		passive = 1;
+	};
+
+	return passive;
+}
+
+inline static u8 rtw_rd_5g_band4_passive(u8 rtw_rd_5g)
+{
+	u8 passive = 0;
+
+	switch (rtw_rd_5g) {
+	case RTW_RD_5G_MKK5:
+	case RTW_RD_5G_ETSI16:
+	case RTW_RD_5G_ETSI18:
+	case RTW_RD_5G_ETSI19:
+	case RTW_RD_5G_WORLD:
+		passive = 1;
+	};
+
+	return passive;
+}
+
+u8 init_channel_set(_adapter *padapter, u8 ChannelPlan, RT_CHANNEL_INFO *channel_set)
+{
+	struct registry_priv *regsty = adapter_to_regsty(padapter);
+	u8	index, chanset_size = 0;
+	u8	b5GBand = _FALSE, b2_4GBand = _FALSE;
+	u8	rd_2g = 0, rd_5g = 0;
+#ifdef CONFIG_DFS_MASTER
+	int i;
+#endif
+
+	if (!rtw_is_channel_plan_valid(ChannelPlan)) {
+		RTW_ERR("ChannelPlan ID 0x%02X error !!!!!\n", ChannelPlan);
+		return chanset_size;
+	}
+
+	_rtw_memset(channel_set, 0, sizeof(RT_CHANNEL_INFO) * MAX_CHANNEL_NUM);
+
+	if (IsSupported24G(regsty->wireless_mode) && hal_chk_band_cap(padapter, BAND_CAP_2G))
+		b2_4GBand = _TRUE;
+
+	if (is_supported_5g(regsty->wireless_mode) && hal_chk_band_cap(padapter, BAND_CAP_5G))
+		b5GBand = _TRUE;
+
+	if (b2_4GBand == _FALSE && b5GBand == _FALSE) {
+		RTW_WARN("HW band_cap has no intersection with SW wireless_mode setting\n");
+		return chanset_size;
+	}
+
+	if (b2_4GBand) {
+		if (ChannelPlan == RTW_CHPLAN_REALTEK_DEFINE)
+			rd_2g = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.rd_2g;
+		else
+			rd_2g = RTW_ChannelPlanMap[ChannelPlan].rd_2g;
+
+		for (index = 0; index < CH_LIST_LEN(RTW_ChannelPlan2G[rd_2g]); index++) {
+			if (rtw_regsty_is_excl_chs(regsty, CH_LIST_CH(RTW_ChannelPlan2G[rd_2g], index)) == _TRUE)
+				continue;
+
+			if (chanset_size >= MAX_CHANNEL_NUM) {
+				RTW_WARN("chset size can't exceed MAX_CHANNEL_NUM(%u)\n", MAX_CHANNEL_NUM);
+				break;
+			}
+
+			channel_set[chanset_size].ChannelNum = CH_LIST_CH(RTW_ChannelPlan2G[rd_2g], index);
+
+			if (ChannelPlan == RTW_CHPLAN_GLOBAL_DOAMIN
+				|| rd_2g == RTW_RD_2G_GLOBAL
+			) {
+				/* Channel 1~11 is active, and 12~14 is passive */
+				if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11)
+					channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+				else if ((channel_set[chanset_size].ChannelNum  >= 12 && channel_set[chanset_size].ChannelNum  <= 14))
+					channel_set[chanset_size].ScanType  = SCAN_PASSIVE;
+			} else if (ChannelPlan == RTW_CHPLAN_WORLD_WIDE_13
+				|| ChannelPlan == RTW_CHPLAN_WORLD_WIDE_5G
+				|| rd_2g == RTW_RD_2G_WORLD
+			) {
+				/* channel 12~13, passive scan */
+				if (channel_set[chanset_size].ChannelNum <= 11)
+					channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+				else
+					channel_set[chanset_size].ScanType = SCAN_PASSIVE;
+			} else
+				channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+
+			chanset_size++;
+		}
+	}
+
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+	if (b5GBand) {
+		if (ChannelPlan == RTW_CHPLAN_REALTEK_DEFINE)
+			rd_5g = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.rd_5g;
+		else
+			rd_5g = RTW_ChannelPlanMap[ChannelPlan].rd_5g;
+
+		for (index = 0; index < CH_LIST_LEN(RTW_ChannelPlan5G[rd_5g]); index++) {
+			if (rtw_regsty_is_excl_chs(regsty, CH_LIST_CH(RTW_ChannelPlan5G[rd_5g], index)) == _TRUE)
+				continue;
+			#ifndef CONFIG_DFS
+			if (rtw_is_dfs_ch(CH_LIST_CH(RTW_ChannelPlan5G[rd_5g], index)))
+				continue;
+			#endif
+
+			if (chanset_size >= MAX_CHANNEL_NUM) {
+				RTW_WARN("chset size can't exceed MAX_CHANNEL_NUM(%u)\n", MAX_CHANNEL_NUM);
+				break;
+			}
+
+			channel_set[chanset_size].ChannelNum = CH_LIST_CH(RTW_ChannelPlan5G[rd_5g], index);
+
+			if ((ChannelPlan == RTW_CHPLAN_WORLD_WIDE_5G) /* all channels passive */
+				|| (rtw_is_5g_band1(channel_set[chanset_size].ChannelNum)
+					&& rtw_rd_5g_band1_passive(rd_5g)) /* band1 passive */
+				|| (rtw_is_5g_band4(channel_set[chanset_size].ChannelNum)
+					&& rtw_rd_5g_band4_passive(rd_5g)) /* band4 passive */
+				|| (rtw_is_dfs_ch(channel_set[chanset_size].ChannelNum)) /* DFS channel(band2, 3) passive */
+			)
+				channel_set[chanset_size].ScanType = SCAN_PASSIVE;
+			else
+				channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+
+			chanset_size++;
+		}
+	}
+
+	#ifdef CONFIG_DFS_MASTER
+	for (i = 0; i < chanset_size; i++)
+		channel_set[i].non_ocp_end_time = rtw_get_current_time();
+	#endif
+#endif /* CONFIG_IEEE80211_BAND_5GHZ */
+
+	if (chanset_size)
+		RTW_INFO(FUNC_ADPT_FMT" ChannelPlan ID:0x%02x, ch num:%d\n"
+			, FUNC_ADPT_ARG(padapter), ChannelPlan, chanset_size);
+	else
+		RTW_WARN(FUNC_ADPT_FMT" ChannelPlan ID:0x%02x, final chset has no channel\n"
+			, FUNC_ADPT_ARG(padapter), ChannelPlan);
+
+	return chanset_size;
+}
+
+#ifdef CONFIG_80211AC_VHT
+#define COUNTRY_CHPLAN_ASSIGN_EN_11AC(_val) , .en_11ac = (_val)
+#else
+#define COUNTRY_CHPLAN_ASSIGN_EN_11AC(_val)
+#endif
+
+#if RTW_DEF_MODULE_REGULATORY_CERT
+#define COUNTRY_CHPLAN_ASSIGN_DEF_MODULE_FLAGS(_val) , .def_module_flags = (_val)
+#else
+#define COUNTRY_CHPLAN_ASSIGN_DEF_MODULE_FLAGS(_val)
+#endif
+
+/* has def_module_flags specified, used by common map and HAL dfference map */
+#define COUNTRY_CHPLAN_ENT(_alpha2, _chplan, _en_11ac, _def_module_flags) \
+	{.alpha2 = (_alpha2), .chplan = (_chplan) \
+		COUNTRY_CHPLAN_ASSIGN_EN_11AC(_en_11ac) \
+		COUNTRY_CHPLAN_ASSIGN_DEF_MODULE_FLAGS(_def_module_flags) \
+	}
+
+#ifdef CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP
+
+#include "../platform/custom_country_chplan.h"
+
+#elif RTW_DEF_MODULE_REGULATORY_CERT
+
+/* leave def_module_flags empty, def_module_flags check is done on country_chplan_map */
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8821AE_HMC_M2) /* 2013 certify */
+static const struct country_chplan RTL8821AE_HMC_M2_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("CA", 0x34, 1, 0), /* Canada */
+	COUNTRY_CHPLAN_ENT("CL", 0x30, 1, 0), /* Chile */
+	COUNTRY_CHPLAN_ENT("CN", 0x51, 1, 0), /* China */
+	COUNTRY_CHPLAN_ENT("CO", 0x34, 1, 0), /* Colombia */
+	COUNTRY_CHPLAN_ENT("CR", 0x34, 1, 0), /* Costa Rica */
+	COUNTRY_CHPLAN_ENT("DO", 0x34, 1, 0), /* Dominican Republic */
+	COUNTRY_CHPLAN_ENT("EC", 0x34, 1, 0), /* Ecuador */
+	COUNTRY_CHPLAN_ENT("GT", 0x34, 1, 0), /* Guatemala */
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+	COUNTRY_CHPLAN_ENT("MX", 0x34, 1, 0), /* Mexico */
+	COUNTRY_CHPLAN_ENT("MY", 0x47, 1, 0), /* Malaysia */
+	COUNTRY_CHPLAN_ENT("NI", 0x34, 1, 0), /* Nicaragua */
+	COUNTRY_CHPLAN_ENT("PA", 0x34, 1, 0), /* Panama */
+	COUNTRY_CHPLAN_ENT("PE", 0x34, 1, 0), /* Peru */
+	COUNTRY_CHPLAN_ENT("PR", 0x34, 1, 0), /* Puerto Rico */
+	COUNTRY_CHPLAN_ENT("PY", 0x34, 1, 0), /* Paraguay */
+	COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("UA", 0x36, 0, 0), /* Ukraine */
+	COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0), /* United States of America (USA) */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8821AU) /* 2014 certify */
+static const struct country_chplan RTL8821AU_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("CA", 0x34, 1, 0), /* Canada */
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+	COUNTRY_CHPLAN_ENT("RU", 0x59, 0, 0), /* Russia(fac/gost), Kaliningrad */
+	COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("UA", 0x36, 0, 0), /* Ukraine */
+	COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0), /* United States of America (USA) */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8812AENF_NGFF) /* 2014 certify */
+static const struct country_chplan RTL8812AENF_NGFF_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0), /* United States of America (USA) */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8812AEBT_HMC) /* 2013 certify */
+static const struct country_chplan RTL8812AEBT_HMC_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("CA", 0x34, 1, 0), /* Canada */
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+	COUNTRY_CHPLAN_ENT("RU", 0x59, 0, 0), /* Russia(fac/gost), Kaliningrad */
+	COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("UA", 0x36, 0, 0), /* Ukraine */
+	COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0), /* United States of America (USA) */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8188EE_HMC_M2) /* 2012 certify */
+static const struct country_chplan RTL8188EE_HMC_M2_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("AW", 0x34, 1, 0), /* Aruba */
+	COUNTRY_CHPLAN_ENT("BB", 0x34, 1, 0), /* Barbados */
+	COUNTRY_CHPLAN_ENT("CA", 0x20, 1, 0), /* Canada */
+	COUNTRY_CHPLAN_ENT("CO", 0x34, 1, 0), /* Colombia */
+	COUNTRY_CHPLAN_ENT("CR", 0x34, 1, 0), /* Costa Rica */
+	COUNTRY_CHPLAN_ENT("DO", 0x34, 1, 0), /* Dominican Republic */
+	COUNTRY_CHPLAN_ENT("EC", 0x34, 1, 0), /* Ecuador */
+	COUNTRY_CHPLAN_ENT("GT", 0x34, 1, 0), /* Guatemala */
+	COUNTRY_CHPLAN_ENT("HT", 0x34, 1, 0), /* Haiti */
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+	COUNTRY_CHPLAN_ENT("MX", 0x34, 1, 0), /* Mexico */
+	COUNTRY_CHPLAN_ENT("NI", 0x34, 1, 0), /* Nicaragua */
+	COUNTRY_CHPLAN_ENT("PA", 0x34, 1, 0), /* Panama */
+	COUNTRY_CHPLAN_ENT("PE", 0x34, 1, 0), /* Peru */
+	COUNTRY_CHPLAN_ENT("PR", 0x34, 1, 0), /* Puerto Rico */
+	COUNTRY_CHPLAN_ENT("PY", 0x34, 1, 0), /* Paraguay */
+	COUNTRY_CHPLAN_ENT("SC", 0x34, 1, 0), /* Seychelles */
+	COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0), /* United States of America (USA) */
+	COUNTRY_CHPLAN_ENT("VC", 0x34, 1, 0), /* Saint Vincent and the Grenadines */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8723BE_HMC_M2) /* 2013 certify */
+static const struct country_chplan RTL8723BE_HMC_M2_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("AW", 0x34, 1, 0), /* Aruba */
+	COUNTRY_CHPLAN_ENT("BS", 0x34, 1, 0), /* Bahamas */
+	COUNTRY_CHPLAN_ENT("CA", 0x20, 1, 0), /* Canada */
+	COUNTRY_CHPLAN_ENT("CO", 0x34, 1, 0), /* Colombia */
+	COUNTRY_CHPLAN_ENT("CR", 0x34, 1, 0), /* Costa Rica */
+	COUNTRY_CHPLAN_ENT("DO", 0x34, 1, 0), /* Dominican Republic */
+	COUNTRY_CHPLAN_ENT("EC", 0x34, 1, 0), /* Ecuador */
+	COUNTRY_CHPLAN_ENT("GT", 0x34, 1, 0), /* Guatemala */
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+	COUNTRY_CHPLAN_ENT("MX", 0x34, 1, 0), /* Mexico */
+	COUNTRY_CHPLAN_ENT("NI", 0x34, 1, 0), /* Nicaragua */
+	COUNTRY_CHPLAN_ENT("PA", 0x34, 1, 0), /* Panama */
+	COUNTRY_CHPLAN_ENT("PE", 0x34, 1, 0), /* Peru */
+	COUNTRY_CHPLAN_ENT("PR", 0x34, 1, 0), /* Puerto Rico */
+	COUNTRY_CHPLAN_ENT("PY", 0x34, 1, 0), /* Paraguay */
+	COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0), /* United States of America (USA) */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8723BS_NGFF1216) /* 2014 certify */
+static const struct country_chplan RTL8723BS_NGFF1216_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("BB", 0x34, 1, 0), /* Barbados */
+	COUNTRY_CHPLAN_ENT("CA", 0x20, 1, 0), /* Canada */
+	COUNTRY_CHPLAN_ENT("CO", 0x34, 1, 0), /* Colombia */
+	COUNTRY_CHPLAN_ENT("CR", 0x34, 1, 0), /* Costa Rica */
+	COUNTRY_CHPLAN_ENT("DO", 0x34, 1, 0), /* Dominican Republic */
+	COUNTRY_CHPLAN_ENT("EC", 0x34, 1, 0), /* Ecuador */
+	COUNTRY_CHPLAN_ENT("GT", 0x34, 1, 0), /* Guatemala */
+	COUNTRY_CHPLAN_ENT("HT", 0x34, 1, 0), /* Haiti */
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+	COUNTRY_CHPLAN_ENT("MX", 0x34, 1, 0), /* Mexico */
+	COUNTRY_CHPLAN_ENT("NI", 0x34, 1, 0), /* Nicaragua */
+	COUNTRY_CHPLAN_ENT("PA", 0x34, 1, 0), /* Panama */
+	COUNTRY_CHPLAN_ENT("PE", 0x34, 1, 0), /* Peru */
+	COUNTRY_CHPLAN_ENT("PR", 0x34, 1, 0), /* Puerto Rico */
+	COUNTRY_CHPLAN_ENT("PY", 0x34, 1, 0), /* Paraguay */
+	COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0), /* United States of America (USA) */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8192EEBT_HMC_M2) /* 2013 certify */
+static const struct country_chplan RTL8192EEBT_HMC_M2_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("AW", 0x34, 1, 0), /* Aruba */
+	COUNTRY_CHPLAN_ENT("CA", 0x20, 1, 0), /* Canada */
+	COUNTRY_CHPLAN_ENT("CO", 0x34, 1, 0), /* Colombia */
+	COUNTRY_CHPLAN_ENT("CR", 0x34, 1, 0), /* Costa Rica */
+	COUNTRY_CHPLAN_ENT("DO", 0x34, 1, 0), /* Dominican Republic */
+	COUNTRY_CHPLAN_ENT("EC", 0x34, 1, 0), /* Ecuador */
+	COUNTRY_CHPLAN_ENT("GT", 0x34, 1, 0), /* Guatemala */
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+	COUNTRY_CHPLAN_ENT("MX", 0x34, 1, 0), /* Mexico */
+	COUNTRY_CHPLAN_ENT("NI", 0x34, 1, 0), /* Nicaragua */
+	COUNTRY_CHPLAN_ENT("PA", 0x34, 1, 0), /* Panama */
+	COUNTRY_CHPLAN_ENT("PE", 0x34, 1, 0), /* Peru */
+	COUNTRY_CHPLAN_ENT("PR", 0x34, 1, 0), /* Puerto Rico */
+	COUNTRY_CHPLAN_ENT("PY", 0x34, 1, 0), /* Paraguay */
+	COUNTRY_CHPLAN_ENT("SC", 0x34, 1, 0), /* Seychelles */
+	COUNTRY_CHPLAN_ENT("ST", 0x34, 1, 0), /* Sao Tome and Principe */
+	COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0), /* United States of America (USA) */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8723DE_NGFF1630) /* 2016 certify */
+static const struct country_chplan RTL8723DE_NGFF1630_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("CA", 0x2A, 1, 0), /* Canada */
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+	COUNTRY_CHPLAN_ENT("MX", 0x34, 1, 0), /* Mexico */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8822BE) /* 2016 certify */
+static const struct country_chplan RTL8822BE_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+};
+#endif
+
+#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8821CE) /* 2016 certify */
+static const struct country_chplan RTL8821CE_country_chplan_exc_map[] = {
+	COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0), /* South Korea */
+};
+#endif
+
+/**
+ * rtw_def_module_get_chplan_from_country -
+ * @country_code: string of country code
+ * @return:
+ * Return NULL for case referring to common map
+ */
+static const struct country_chplan *rtw_def_module_get_chplan_from_country(const char *country_code)
+{
+	const struct country_chplan *ent = NULL;
+	const struct country_chplan *hal_map = NULL;
+	u16 hal_map_sz = 0;
+	int i;
+
+	/* TODO: runtime selection for multi driver */
+#if (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8821AE_HMC_M2)
+	hal_map = RTL8821AE_HMC_M2_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8821AE_HMC_M2_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8821AU)
+	hal_map = RTL8821AU_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8821AU_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8812AENF_NGFF)
+	hal_map = RTL8812AENF_NGFF_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8812AENF_NGFF_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8812AEBT_HMC)
+	hal_map = RTL8812AEBT_HMC_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8812AEBT_HMC_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8188EE_HMC_M2)
+	hal_map = RTL8188EE_HMC_M2_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8188EE_HMC_M2_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8723BE_HMC_M2)
+	hal_map = RTL8723BE_HMC_M2_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8723BE_HMC_M2_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8723BS_NGFF1216)
+	hal_map = RTL8723BS_NGFF1216_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8723BS_NGFF1216_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8192EEBT_HMC_M2)
+	hal_map = RTL8192EEBT_HMC_M2_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8192EEBT_HMC_M2_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8723DE_NGFF1630)
+	hal_map = RTL8723DE_NGFF1630_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8723DE_NGFF1630_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8822BE)
+	hal_map = RTL8822BE_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8822BE_country_chplan_exc_map) / sizeof(struct country_chplan);
+#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8821CE)
+	hal_map = RTL8821CE_country_chplan_exc_map;
+	hal_map_sz = sizeof(RTL8821CE_country_chplan_exc_map) / sizeof(struct country_chplan);
+#endif
+
+	if (hal_map == NULL || hal_map_sz == 0)
+		goto exit;
+
+	for (i = 0; i < hal_map_sz; i++) {
+		if (strncmp(country_code, hal_map[i].alpha2, 2) == 0) {
+			ent = &hal_map[i];
+			break;
+		}
+	}
+
+exit:
+	return ent;
+}
+#endif /* CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP or RTW_DEF_MODULE_REGULATORY_CERT */
+
+static const struct country_chplan country_chplan_map[] = {
+	COUNTRY_CHPLAN_ENT("AD", 0x26, 1, 0x000), /* Andorra */
+	COUNTRY_CHPLAN_ENT("AE", 0x26, 1, 0x7FB), /* United Arab Emirates */
+	COUNTRY_CHPLAN_ENT("AF", 0x42, 1, 0x000), /* Afghanistan */
+	COUNTRY_CHPLAN_ENT("AG", 0x26, 1, 0x000), /* Antigua & Barbuda */
+	COUNTRY_CHPLAN_ENT("AI", 0x26, 1, 0x000), /* Anguilla(UK) */
+	COUNTRY_CHPLAN_ENT("AL", 0x26, 1, 0x7F1), /* Albania */
+	COUNTRY_CHPLAN_ENT("AM", 0x26, 1, 0x6B0), /* Armenia */
+	COUNTRY_CHPLAN_ENT("AN", 0x26, 1, 0x7F1), /* Netherlands Antilles */
+	COUNTRY_CHPLAN_ENT("AO", 0x47, 1, 0x6E0), /* Angola */
+	COUNTRY_CHPLAN_ENT("AQ", 0x26, 1, 0x000), /* Antarctica */
+	COUNTRY_CHPLAN_ENT("AR", 0x61, 1, 0x7F3), /* Argentina */
+	COUNTRY_CHPLAN_ENT("AS", 0x76, 1, 0x000), /* American Samoa */
+	COUNTRY_CHPLAN_ENT("AT", 0x26, 1, 0x7FB), /* Austria */
+	COUNTRY_CHPLAN_ENT("AU", 0x45, 1, 0x7FB), /* Australia */
+	COUNTRY_CHPLAN_ENT("AW", 0x76, 1, 0x0B0), /* Aruba */
+	COUNTRY_CHPLAN_ENT("AZ", 0x26, 1, 0x7F1), /* Azerbaijan */
+	COUNTRY_CHPLAN_ENT("BA", 0x26, 1, 0x7F1), /* Bosnia & Herzegovina */
+	COUNTRY_CHPLAN_ENT("BB", 0x76, 1, 0x650), /* Barbados */
+	COUNTRY_CHPLAN_ENT("BD", 0x26, 1, 0x7F1), /* Bangladesh */
+	COUNTRY_CHPLAN_ENT("BE", 0x26, 1, 0x7FB), /* Belgium */
+	COUNTRY_CHPLAN_ENT("BF", 0x26, 1, 0x6B0), /* Burkina Faso */
+	COUNTRY_CHPLAN_ENT("BG", 0x26, 1, 0x7F1), /* Bulgaria */
+	COUNTRY_CHPLAN_ENT("BH", 0x47, 1, 0x7F1), /* Bahrain */
+	COUNTRY_CHPLAN_ENT("BI", 0x26, 1, 0x6B0), /* Burundi */
+	COUNTRY_CHPLAN_ENT("BJ", 0x26, 1, 0x6B0), /* Benin */
+	COUNTRY_CHPLAN_ENT("BN", 0x47, 1, 0x610), /* Brunei */
+	COUNTRY_CHPLAN_ENT("BO", 0x73, 1, 0x7F1), /* Bolivia */
+	COUNTRY_CHPLAN_ENT("BR", 0x62, 1, 0x7F1), /* Brazil */
+	COUNTRY_CHPLAN_ENT("BS", 0x76, 1, 0x620), /* Bahamas */
+	COUNTRY_CHPLAN_ENT("BW", 0x26, 1, 0x6F1), /* Botswana */
+	COUNTRY_CHPLAN_ENT("BY", 0x26, 1, 0x7F1), /* Belarus */
+	COUNTRY_CHPLAN_ENT("BZ", 0x76, 1, 0x000), /* Belize */
+	COUNTRY_CHPLAN_ENT("CA", 0x2B, 1, 0x7FB), /* Canada */
+	COUNTRY_CHPLAN_ENT("CC", 0x26, 1, 0x000), /* Cocos (Keeling) Islands (Australia) */
+	COUNTRY_CHPLAN_ENT("CD", 0x26, 1, 0x6B0), /* Congo, Republic of the */
+	COUNTRY_CHPLAN_ENT("CF", 0x26, 1, 0x6B0), /* Central African Republic */
+	COUNTRY_CHPLAN_ENT("CG", 0x26, 1, 0x6B0), /* Congo, Democratic Republic of the. Zaire */
+	COUNTRY_CHPLAN_ENT("CH", 0x26, 1, 0x7FB), /* Switzerland */
+	COUNTRY_CHPLAN_ENT("CI", 0x26, 1, 0x7F1), /* Cote d'Ivoire */
+	COUNTRY_CHPLAN_ENT("CK", 0x26, 1, 0x000), /* Cook Islands */
+	COUNTRY_CHPLAN_ENT("CL", 0x2D, 1, 0x7F1), /* Chile */
+	COUNTRY_CHPLAN_ENT("CM", 0x26, 1, 0x6B0), /* Cameroon */
+	COUNTRY_CHPLAN_ENT("CN", 0x48, 1, 0x7FB), /* China */
+	COUNTRY_CHPLAN_ENT("CO", 0x76, 1, 0x7F1), /* Colombia */
+	COUNTRY_CHPLAN_ENT("CR", 0x76, 1, 0x7F1), /* Costa Rica */
+	COUNTRY_CHPLAN_ENT("CV", 0x26, 1, 0x6B0), /* Cape Verde */
+	COUNTRY_CHPLAN_ENT("CX", 0x45, 1, 0x000), /* Christmas Island (Australia) */
+	COUNTRY_CHPLAN_ENT("CY", 0x26, 1, 0x7FB), /* Cyprus */
+	COUNTRY_CHPLAN_ENT("CZ", 0x26, 1, 0x7FB), /* Czech Republic */
+	COUNTRY_CHPLAN_ENT("DE", 0x26, 1, 0x7FB), /* Germany */
+	COUNTRY_CHPLAN_ENT("DJ", 0x26, 1, 0x680), /* Djibouti */
+	COUNTRY_CHPLAN_ENT("DK", 0x26, 1, 0x7FB), /* Denmark */
+	COUNTRY_CHPLAN_ENT("DM", 0x76, 1, 0x000), /* Dominica */
+	COUNTRY_CHPLAN_ENT("DO", 0x76, 1, 0x7F1), /* Dominican Republic */
+	COUNTRY_CHPLAN_ENT("DZ", 0x26, 1, 0x7F1), /* Algeria */
+	COUNTRY_CHPLAN_ENT("EC", 0x76, 1, 0x7F1), /* Ecuador */
+	COUNTRY_CHPLAN_ENT("EE", 0x26, 1, 0x7FB), /* Estonia */
+	COUNTRY_CHPLAN_ENT("EG", 0x47, 1, 0x7F1), /* Egypt */
+	COUNTRY_CHPLAN_ENT("EH", 0x47, 1, 0x680), /* Western Sahara */
+	COUNTRY_CHPLAN_ENT("ER", 0x26, 1, 0x000), /* Eritrea */
+	COUNTRY_CHPLAN_ENT("ES", 0x26, 1, 0x7FB), /* Spain, Canary Islands, Ceuta, Melilla */
+	COUNTRY_CHPLAN_ENT("ET", 0x26, 1, 0x4B0), /* Ethiopia */
+	COUNTRY_CHPLAN_ENT("FI", 0x26, 1, 0x7FB), /* Finland */
+	COUNTRY_CHPLAN_ENT("FJ", 0x76, 1, 0x600), /* Fiji */
+	COUNTRY_CHPLAN_ENT("FK", 0x26, 1, 0x000), /* Falkland Islands (Islas Malvinas) (UK) */
+	COUNTRY_CHPLAN_ENT("FM", 0x76, 1, 0x000), /* Micronesia, Federated States of (USA) */
+	COUNTRY_CHPLAN_ENT("FO", 0x26, 1, 0x000), /* Faroe Islands (Denmark) */
+	COUNTRY_CHPLAN_ENT("FR", 0x26, 1, 0x7FB), /* France */
+	COUNTRY_CHPLAN_ENT("GA", 0x26, 1, 0x6B0), /* Gabon */
+	COUNTRY_CHPLAN_ENT("GB", 0x26, 1, 0x7FB), /* Great Britain (United Kingdom; England) */
+	COUNTRY_CHPLAN_ENT("GD", 0x34, 1, 0x0B0), /* Grenada */
+	COUNTRY_CHPLAN_ENT("GE", 0x26, 1, 0x600), /* Georgia */
+	COUNTRY_CHPLAN_ENT("GF", 0x26, 1, 0x080), /* French Guiana */
+	COUNTRY_CHPLAN_ENT("GG", 0x26, 1, 0x000), /* Guernsey (UK) */
+	COUNTRY_CHPLAN_ENT("GH", 0x26, 1, 0x7F1), /* Ghana */
+	COUNTRY_CHPLAN_ENT("GI", 0x26, 1, 0x600), /* Gibraltar (UK) */
+	COUNTRY_CHPLAN_ENT("GL", 0x26, 1, 0x600), /* Greenland (Denmark) */
+	COUNTRY_CHPLAN_ENT("GM", 0x26, 1, 0x6B0), /* Gambia */
+	COUNTRY_CHPLAN_ENT("GN", 0x26, 1, 0x610), /* Guinea */
+	COUNTRY_CHPLAN_ENT("GP", 0x26, 1, 0x600), /* Guadeloupe (France) */
+	COUNTRY_CHPLAN_ENT("GQ", 0x26, 1, 0x6B0), /* Equatorial Guinea */
+	COUNTRY_CHPLAN_ENT("GR", 0x26, 1, 0x7FB), /* Greece */
+	COUNTRY_CHPLAN_ENT("GS", 0x26, 1, 0x000), /* South Georgia and the Sandwich Islands (UK) */
+	COUNTRY_CHPLAN_ENT("GT", 0x61, 1, 0x7F1), /* Guatemala */
+	COUNTRY_CHPLAN_ENT("GU", 0x76, 1, 0x600), /* Guam (USA) */
+	COUNTRY_CHPLAN_ENT("GW", 0x26, 1, 0x6B0), /* Guinea-Bissau */
+	COUNTRY_CHPLAN_ENT("GY", 0x44, 1, 0x000), /* Guyana */
+	COUNTRY_CHPLAN_ENT("HK", 0x26, 1, 0x7FB), /* Hong Kong */
+	COUNTRY_CHPLAN_ENT("HM", 0x45, 1, 0x000), /* Heard and McDonald Islands (Australia) */
+	COUNTRY_CHPLAN_ENT("HN", 0x32, 1, 0x7F1), /* Honduras */
+	COUNTRY_CHPLAN_ENT("HR", 0x26, 1, 0x7F9), /* Croatia */
+	COUNTRY_CHPLAN_ENT("HT", 0x76, 1, 0x650), /* Haiti */
+	COUNTRY_CHPLAN_ENT("HU", 0x26, 1, 0x7FB), /* Hungary */
+	COUNTRY_CHPLAN_ENT("ID", 0x3D, 0, 0x7F3), /* Indonesia */
+	COUNTRY_CHPLAN_ENT("IE", 0x26, 1, 0x7FB), /* Ireland */
+	COUNTRY_CHPLAN_ENT("IL", 0x47, 1, 0x7F1), /* Israel */
+	COUNTRY_CHPLAN_ENT("IM", 0x26, 1, 0x000), /* Isle of Man (UK) */
+	COUNTRY_CHPLAN_ENT("IN", 0x48, 1, 0x7F1), /* India */
+	COUNTRY_CHPLAN_ENT("IQ", 0x26, 1, 0x000), /* Iraq */
+	COUNTRY_CHPLAN_ENT("IR", 0x26, 0, 0x000), /* Iran */
+	COUNTRY_CHPLAN_ENT("IS", 0x26, 1, 0x7FB), /* Iceland */
+	COUNTRY_CHPLAN_ENT("IT", 0x26, 1, 0x7FB), /* Italy */
+	COUNTRY_CHPLAN_ENT("JE", 0x26, 1, 0x000), /* Jersey (UK) */
+	COUNTRY_CHPLAN_ENT("JM", 0x51, 1, 0x7F1), /* Jamaica */
+	COUNTRY_CHPLAN_ENT("JO", 0x49, 1, 0x7FB), /* Jordan */
+	COUNTRY_CHPLAN_ENT("JP", 0x27, 1, 0x7FF), /* Japan- Telec */
+	COUNTRY_CHPLAN_ENT("KE", 0x47, 1, 0x7F9), /* Kenya */
+	COUNTRY_CHPLAN_ENT("KG", 0x26, 1, 0x7F1), /* Kyrgyzstan */
+	COUNTRY_CHPLAN_ENT("KH", 0x26, 1, 0x7F1), /* Cambodia */
+	COUNTRY_CHPLAN_ENT("KI", 0x26, 1, 0x000), /* Kiribati */
+	COUNTRY_CHPLAN_ENT("KN", 0x76, 1, 0x000), /* Saint Kitts and Nevis */
+	COUNTRY_CHPLAN_ENT("KR", 0x3E, 1, 0x7FB), /* South Korea */
+	COUNTRY_CHPLAN_ENT("KW", 0x47, 1, 0x7FB), /* Kuwait */
+	COUNTRY_CHPLAN_ENT("KY", 0x76, 1, 0x000), /* Cayman Islands (UK) */
+	COUNTRY_CHPLAN_ENT("KZ", 0x26, 1, 0x700), /* Kazakhstan */
+	COUNTRY_CHPLAN_ENT("LA", 0x26, 1, 0x000), /* Laos */
+	COUNTRY_CHPLAN_ENT("LB", 0x26, 1, 0x7F1), /* Lebanon */
+	COUNTRY_CHPLAN_ENT("LC", 0x76, 1, 0x000), /* Saint Lucia */
+	COUNTRY_CHPLAN_ENT("LI", 0x26, 1, 0x7FB), /* Liechtenstein */
+	COUNTRY_CHPLAN_ENT("LK", 0x26, 1, 0x7F1), /* Sri Lanka */
+	COUNTRY_CHPLAN_ENT("LR", 0x26, 1, 0x6B0), /* Liberia */
+	COUNTRY_CHPLAN_ENT("LS", 0x26, 1, 0x7F1), /* Lesotho */
+	COUNTRY_CHPLAN_ENT("LT", 0x26, 1, 0x7FB), /* Lithuania */
+	COUNTRY_CHPLAN_ENT("LU", 0x26, 1, 0x7FB), /* Luxembourg */
+	COUNTRY_CHPLAN_ENT("LV", 0x26, 1, 0x7FB), /* Latvia */
+	COUNTRY_CHPLAN_ENT("LY", 0x26, 1, 0x000), /* Libya */
+	COUNTRY_CHPLAN_ENT("MA", 0x47, 1, 0x7F1), /* Morocco */
+	COUNTRY_CHPLAN_ENT("MC", 0x26, 1, 0x7FB), /* Monaco */
+	COUNTRY_CHPLAN_ENT("MD", 0x26, 1, 0x7F1), /* Moldova */
+	COUNTRY_CHPLAN_ENT("ME", 0x26, 1, 0x7F1), /* Montenegro */
+	COUNTRY_CHPLAN_ENT("MF", 0x76, 1, 0x000), /* Saint Martin */
+	COUNTRY_CHPLAN_ENT("MG", 0x26, 1, 0x620), /* Madagascar */
+	COUNTRY_CHPLAN_ENT("MH", 0x76, 1, 0x000), /* Marshall Islands (USA) */
+	COUNTRY_CHPLAN_ENT("MK", 0x26, 1, 0x7F1), /* Republic of Macedonia (FYROM) */
+	COUNTRY_CHPLAN_ENT("ML", 0x26, 1, 0x6B0), /* Mali */
+	COUNTRY_CHPLAN_ENT("MM", 0x26, 1, 0x000), /* Burma (Myanmar) */
+	COUNTRY_CHPLAN_ENT("MN", 0x26, 1, 0x000), /* Mongolia */
+	COUNTRY_CHPLAN_ENT("MO", 0x26, 1, 0x600), /* Macau */
+	COUNTRY_CHPLAN_ENT("MP", 0x76, 1, 0x000), /* Northern Mariana Islands (USA) */
+	COUNTRY_CHPLAN_ENT("MQ", 0x26, 1, 0x640), /* Martinique (France) */
+	COUNTRY_CHPLAN_ENT("MR", 0x26, 1, 0x6A0), /* Mauritania */
+	COUNTRY_CHPLAN_ENT("MS", 0x26, 1, 0x000), /* Montserrat (UK) */
+	COUNTRY_CHPLAN_ENT("MT", 0x26, 1, 0x7FB), /* Malta */
+	COUNTRY_CHPLAN_ENT("MU", 0x26, 1, 0x6B0), /* Mauritius */
+	COUNTRY_CHPLAN_ENT("MV", 0x47, 1, 0x000), /* Maldives */
+	COUNTRY_CHPLAN_ENT("MW", 0x26, 1, 0x6B0), /* Malawi */
+	COUNTRY_CHPLAN_ENT("MX", 0x61, 1, 0x7F1), /* Mexico */
+	COUNTRY_CHPLAN_ENT("MY", 0x63, 1, 0x7F1), /* Malaysia */
+	COUNTRY_CHPLAN_ENT("MZ", 0x26, 1, 0x7F1), /* Mozambique */
+	COUNTRY_CHPLAN_ENT("NA", 0x26, 1, 0x700), /* Namibia */
+	COUNTRY_CHPLAN_ENT("NC", 0x26, 1, 0x000), /* New Caledonia */
+	COUNTRY_CHPLAN_ENT("NE", 0x26, 1, 0x6B0), /* Niger */
+	COUNTRY_CHPLAN_ENT("NF", 0x45, 1, 0x000), /* Norfolk Island (Australia) */
+	COUNTRY_CHPLAN_ENT("NG", 0x75, 1, 0x7F9), /* Nigeria */
+	COUNTRY_CHPLAN_ENT("NI", 0x76, 1, 0x7F1), /* Nicaragua */
+	COUNTRY_CHPLAN_ENT("NL", 0x26, 1, 0x7FB), /* Netherlands */
+	COUNTRY_CHPLAN_ENT("NO", 0x26, 1, 0x7FB), /* Norway */
+	COUNTRY_CHPLAN_ENT("NP", 0x47, 1, 0x6F0), /* Nepal */
+	COUNTRY_CHPLAN_ENT("NR", 0x26, 1, 0x000), /* Nauru */
+	COUNTRY_CHPLAN_ENT("NU", 0x45, 1, 0x000), /* Niue */
+	COUNTRY_CHPLAN_ENT("NZ", 0x45, 1, 0x7FB), /* New Zealand */
+	COUNTRY_CHPLAN_ENT("OM", 0x26, 1, 0x7F9), /* Oman */
+	COUNTRY_CHPLAN_ENT("PA", 0x76, 1, 0x7F1), /* Panama */
+	COUNTRY_CHPLAN_ENT("PE", 0x76, 1, 0x7F1), /* Peru */
+	COUNTRY_CHPLAN_ENT("PF", 0x26, 1, 0x000), /* French Polynesia (France) */
+	COUNTRY_CHPLAN_ENT("PG", 0x26, 1, 0x7F1), /* Papua New Guinea */
+	COUNTRY_CHPLAN_ENT("PH", 0x26, 1, 0x7F1), /* Philippines */
+	COUNTRY_CHPLAN_ENT("PK", 0x51, 1, 0x7F1), /* Pakistan */
+	COUNTRY_CHPLAN_ENT("PL", 0x26, 1, 0x7FB), /* Poland */
+	COUNTRY_CHPLAN_ENT("PM", 0x26, 1, 0x000), /* Saint Pierre and Miquelon (France) */
+	COUNTRY_CHPLAN_ENT("PR", 0x76, 1, 0x7F1), /* Puerto Rico */
+	COUNTRY_CHPLAN_ENT("PT", 0x26, 1, 0x7FB), /* Portugal */
+	COUNTRY_CHPLAN_ENT("PW", 0x76, 1, 0x000), /* Palau */
+	COUNTRY_CHPLAN_ENT("PY", 0x76, 1, 0x7F1), /* Paraguay */
+	COUNTRY_CHPLAN_ENT("QA", 0x51, 1, 0x7F9), /* Qatar */
+	COUNTRY_CHPLAN_ENT("RE", 0x26, 1, 0x000), /* Reunion (France) */
+	COUNTRY_CHPLAN_ENT("RO", 0x26, 1, 0x7F1), /* Romania */
+	COUNTRY_CHPLAN_ENT("RS", 0x26, 1, 0x7F1), /* Serbia, Kosovo */
+	COUNTRY_CHPLAN_ENT("RU", 0x59, 1, 0x7FB), /* Russia(fac/gost), Kaliningrad */
+	COUNTRY_CHPLAN_ENT("RW", 0x26, 1, 0x0B0), /* Rwanda */
+	COUNTRY_CHPLAN_ENT("SA", 0x26, 1, 0x7FB), /* Saudi Arabia */
+	COUNTRY_CHPLAN_ENT("SB", 0x26, 1, 0x000), /* Solomon Islands */
+	COUNTRY_CHPLAN_ENT("SC", 0x76, 1, 0x690), /* Seychelles */
+	COUNTRY_CHPLAN_ENT("SE", 0x26, 1, 0x7FB), /* Sweden */
+	COUNTRY_CHPLAN_ENT("SG", 0x35, 1, 0x7FB), /* Singapore */
+	COUNTRY_CHPLAN_ENT("SH", 0x26, 1, 0x000), /* Saint Helena (UK) */
+	COUNTRY_CHPLAN_ENT("SI", 0x26, 1, 0x7FB), /* Slovenia */
+	COUNTRY_CHPLAN_ENT("SJ", 0x26, 1, 0x000), /* Svalbard (Norway) */
+	COUNTRY_CHPLAN_ENT("SK", 0x26, 1, 0x7FB), /* Slovakia */
+	COUNTRY_CHPLAN_ENT("SL", 0x26, 1, 0x6B0), /* Sierra Leone */
+	COUNTRY_CHPLAN_ENT("SM", 0x26, 1, 0x000), /* San Marino */
+	COUNTRY_CHPLAN_ENT("SN", 0x26, 1, 0x7F1), /* Senegal */
+	COUNTRY_CHPLAN_ENT("SO", 0x26, 1, 0x000), /* Somalia */
+	COUNTRY_CHPLAN_ENT("SR", 0x74, 1, 0x000), /* Suriname */
+	COUNTRY_CHPLAN_ENT("ST", 0x76, 1, 0x680), /* Sao Tome and Principe */
+	COUNTRY_CHPLAN_ENT("SV", 0x30, 1, 0x7F1), /* El Salvador */
+	COUNTRY_CHPLAN_ENT("SX", 0x76, 1, 0x000), /* Sint Marteen */
+	COUNTRY_CHPLAN_ENT("SZ", 0x26, 1, 0x020), /* Swaziland */
+	COUNTRY_CHPLAN_ENT("TC", 0x26, 1, 0x000), /* Turks and Caicos Islands (UK) */
+	COUNTRY_CHPLAN_ENT("TD", 0x26, 1, 0x6B0), /* Chad */
+	COUNTRY_CHPLAN_ENT("TF", 0x26, 1, 0x680), /* French Southern and Antarctic Lands (FR Southern Territories) */
+	COUNTRY_CHPLAN_ENT("TG", 0x26, 1, 0x6B0), /* Togo */
+	COUNTRY_CHPLAN_ENT("TH", 0x26, 1, 0x7F1), /* Thailand */
+	COUNTRY_CHPLAN_ENT("TJ", 0x26, 1, 0x640), /* Tajikistan */
+	COUNTRY_CHPLAN_ENT("TK", 0x45, 1, 0x000), /* Tokelau */
+	COUNTRY_CHPLAN_ENT("TM", 0x26, 1, 0x000), /* Turkmenistan */
+	COUNTRY_CHPLAN_ENT("TN", 0x47, 1, 0x7F1), /* Tunisia */
+	COUNTRY_CHPLAN_ENT("TO", 0x26, 1, 0x000), /* Tonga */
+	COUNTRY_CHPLAN_ENT("TR", 0x26, 1, 0x7F1), /* Turkey, Northern Cyprus */
+	COUNTRY_CHPLAN_ENT("TT", 0x42, 1, 0x3F1), /* Trinidad & Tobago */
+	COUNTRY_CHPLAN_ENT("TW", 0x76, 1, 0x7FF), /* Taiwan */
+	COUNTRY_CHPLAN_ENT("TZ", 0x26, 1, 0x6F0), /* Tanzania */
+	COUNTRY_CHPLAN_ENT("UA", 0x36, 1, 0x7FB), /* Ukraine */
+	COUNTRY_CHPLAN_ENT("UG", 0x26, 1, 0x6F1), /* Uganda */
+	COUNTRY_CHPLAN_ENT("US", 0x76, 1, 0x7FF), /* United States of America (USA) */
+	COUNTRY_CHPLAN_ENT("UY", 0x30, 1, 0x7F1), /* Uruguay */
+	COUNTRY_CHPLAN_ENT("UZ", 0x47, 1, 0x6F0), /* Uzbekistan */
+	COUNTRY_CHPLAN_ENT("VA", 0x26, 1, 0x000), /* Holy See (Vatican City) */
+	COUNTRY_CHPLAN_ENT("VC", 0x76, 1, 0x010), /* Saint Vincent and the Grenadines */
+	COUNTRY_CHPLAN_ENT("VE", 0x30, 1, 0x7F1), /* Venezuela */
+	COUNTRY_CHPLAN_ENT("VI", 0x76, 1, 0x000), /* United States Virgin Islands (USA) */
+	COUNTRY_CHPLAN_ENT("VN", 0x26, 1, 0x7F1), /* Vietnam */
+	COUNTRY_CHPLAN_ENT("VU", 0x26, 1, 0x000), /* Vanuatu */
+	COUNTRY_CHPLAN_ENT("WF", 0x26, 1, 0x000), /* Wallis and Futuna (France) */
+	COUNTRY_CHPLAN_ENT("WS", 0x76, 1, 0x000), /* Samoa */
+	COUNTRY_CHPLAN_ENT("YE", 0x26, 1, 0x040), /* Yemen */
+	COUNTRY_CHPLAN_ENT("YT", 0x26, 1, 0x680), /* Mayotte (France) */
+	COUNTRY_CHPLAN_ENT("ZA", 0x26, 1, 0x7F1), /* South Africa */
+	COUNTRY_CHPLAN_ENT("ZM", 0x26, 1, 0x6B0), /* Zambia */
+	COUNTRY_CHPLAN_ENT("ZW", 0x26, 1, 0x7F1), /* Zimbabwe */
+};
+
+/*
+* rtw_get_chplan_from_country -
+* @country_code: string of country code
+*
+* Return pointer of struct country_chplan entry or NULL when unsupported country_code is given
+*/
+const struct country_chplan *rtw_get_chplan_from_country(const char *country_code)
+{
+#if RTW_DEF_MODULE_REGULATORY_CERT
+	const struct country_chplan *exc_ent = NULL;
+#endif
+	const struct country_chplan *ent = NULL;
+	const struct country_chplan *map = NULL;
+	u16 map_sz = 0;
+	char code[2];
+	int i;
+
+	code[0] = alpha_to_upper(country_code[0]);
+	code[1] = alpha_to_upper(country_code[1]);
+
+#ifdef CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP
+	map = CUSTOMIZED_country_chplan_map;
+	map_sz = sizeof(CUSTOMIZED_country_chplan_map) / sizeof(struct country_chplan);
+#else
+	#if RTW_DEF_MODULE_REGULATORY_CERT
+	exc_ent = rtw_def_module_get_chplan_from_country(code);
+	#endif
+	map = country_chplan_map;
+	map_sz = sizeof(country_chplan_map) / sizeof(struct country_chplan);
+#endif
+
+	for (i = 0; i < map_sz; i++) {
+		if (strncmp(code, map[i].alpha2, 2) == 0) {
+			ent = &map[i];
+			break;
+		}
+	}
+
+	#if RTW_DEF_MODULE_REGULATORY_CERT
+	if (!ent || !(COUNTRY_CHPLAN_DEF_MODULE_FALGS(ent) & RTW_DEF_MODULE_REGULATORY_CERT))
+		exc_ent = ent = NULL;
+	if (exc_ent)
+		ent = exc_ent;
+	#endif
+
+	return ent;
+}
+
+void dump_country_chplan(void *sel, const struct country_chplan *ent)
+{
+	RTW_PRINT_SEL(sel, "\"%c%c\", 0x%02X%s\n"
+		, ent->alpha2[0], ent->alpha2[1], ent->chplan
+		, COUNTRY_CHPLAN_EN_11AC(ent) ? " ac" : ""
+	);
+}
+
+void dump_country_chplan_map(void *sel)
+{
+	const struct country_chplan *ent;
+	u8 code[2];
+
+#if RTW_DEF_MODULE_REGULATORY_CERT
+	RTW_PRINT_SEL(sel, "RTW_DEF_MODULE_REGULATORY_CERT:0x%x\n", RTW_DEF_MODULE_REGULATORY_CERT);
+#endif
+#ifdef CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP
+	RTW_PRINT_SEL(sel, "CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP\n");
+#endif
+
+	for (code[0] = 'A'; code[0] <= 'Z'; code[0]++) {
+		for (code[1] = 'A'; code[1] <= 'Z'; code[1]++) {
+			ent = rtw_get_chplan_from_country(code);
+			if (!ent)
+				continue;
+
+			dump_country_chplan(sel, ent);
+		}
+	}
+}
+
+void dump_chplan_id_list(void *sel)
+{
+	u8 first = 1;
+	int i;
+
+	for (i = 0; i < RTW_CHPLAN_MAX; i++) {
+		if (!rtw_is_channel_plan_valid(i))
+			continue;
+
+		if (first) {
+			RTW_PRINT_SEL(sel, "0x%02X ", i);
+			first = 0;
+		} else
+			_RTW_PRINT_SEL(sel, "0x%02X ", i);
+	}
+
+	_RTW_PRINT_SEL(sel, "0x7F\n");
+}
+
+void dump_chplan_test(void *sel)
+{
+	int i, j;
+
+	/* check invalid channel */
+	for (i = 0; i < RTW_RD_2G_MAX; i++) {
+		for (j = 0; j < CH_LIST_LEN(RTW_ChannelPlan2G[i]); j++) {
+			if (rtw_ch2freq(CH_LIST_CH(RTW_ChannelPlan2G[i], j)) == 0)
+				RTW_PRINT_SEL(sel, "invalid ch:%u at (%d,%d)\n", CH_LIST_CH(RTW_ChannelPlan2G[i], j), i, j);
+		}
+	}
+
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+	for (i = 0; i < RTW_RD_5G_MAX; i++) {
+		for (j = 0; j < CH_LIST_LEN(RTW_ChannelPlan5G[i]); j++) {
+			if (rtw_ch2freq(CH_LIST_CH(RTW_ChannelPlan5G[i], j)) == 0)
+				RTW_PRINT_SEL(sel, "invalid ch:%u at (%d,%d)\n", CH_LIST_CH(RTW_ChannelPlan5G[i], j), i, j);
+		}
+	}
+#endif
+}
+
+void dump_chplan_ver(void *sel)
+{
+	RTW_PRINT_SEL(sel, "%s-%s\n", RTW_DOMAIN_MAP_VER, RTW_COUNTRY_MAP_VER);
+}

+ 179 - 0
core/rtw_chplan.h

@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2018 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.
+ *
+ *****************************************************************************/
+#ifndef __RTW_CHPLAN_H__
+#define __RTW_CHPLAN_H__
+
+enum rtw_chplan_id {
+	/* ===== 0x00 ~ 0x1F, legacy channel plan ===== */
+	RTW_CHPLAN_FCC = 0x00,
+	RTW_CHPLAN_IC = 0x01,
+	RTW_CHPLAN_ETSI = 0x02,
+	RTW_CHPLAN_SPAIN = 0x03,
+	RTW_CHPLAN_FRANCE = 0x04,
+	RTW_CHPLAN_MKK = 0x05,
+	RTW_CHPLAN_MKK1 = 0x06,
+	RTW_CHPLAN_ISRAEL = 0x07,
+	RTW_CHPLAN_TELEC = 0x08,
+	RTW_CHPLAN_GLOBAL_DOAMIN = 0x09,
+	RTW_CHPLAN_WORLD_WIDE_13 = 0x0A,
+	RTW_CHPLAN_TAIWAN = 0x0B,
+	RTW_CHPLAN_CHINA = 0x0C,
+	RTW_CHPLAN_SINGAPORE_INDIA_MEXICO = 0x0D,
+	RTW_CHPLAN_KOREA = 0x0E,
+	RTW_CHPLAN_TURKEY = 0x0F,
+	RTW_CHPLAN_JAPAN = 0x10,
+	RTW_CHPLAN_FCC_NO_DFS = 0x11,
+	RTW_CHPLAN_JAPAN_NO_DFS = 0x12,
+	RTW_CHPLAN_WORLD_WIDE_5G = 0x13,
+	RTW_CHPLAN_TAIWAN_NO_DFS = 0x14,
+
+	/* ===== 0x20 ~ 0x7F, new channel plan ===== */
+	RTW_CHPLAN_WORLD_NULL = 0x20,
+	RTW_CHPLAN_ETSI1_NULL = 0x21,
+	RTW_CHPLAN_FCC1_NULL = 0x22,
+	RTW_CHPLAN_MKK1_NULL = 0x23,
+	RTW_CHPLAN_ETSI2_NULL = 0x24,
+	RTW_CHPLAN_FCC1_FCC1 = 0x25,
+	RTW_CHPLAN_WORLD_ETSI1 = 0x26,
+	RTW_CHPLAN_MKK1_MKK1 = 0x27,
+	RTW_CHPLAN_WORLD_KCC1 = 0x28,
+	RTW_CHPLAN_WORLD_FCC2 = 0x29,
+	RTW_CHPLAN_FCC2_NULL = 0x2A,
+	RTW_CHPLAN_IC1_IC2 = 0x2B,
+	RTW_CHPLAN_MKK2_NULL = 0x2C,
+	RTW_CHPLAN_WORLD_CHILE1= 0x2D,
+	RTW_CHPLAN_WORLD1_WORLD1 = 0x2E,
+	RTW_CHPLAN_WORLD_CHILE2 = 0x2F,
+	RTW_CHPLAN_WORLD_FCC3 = 0x30,
+	RTW_CHPLAN_WORLD_FCC4 = 0x31,
+	RTW_CHPLAN_WORLD_FCC5 = 0x32,
+	RTW_CHPLAN_WORLD_FCC6 = 0x33,
+	RTW_CHPLAN_FCC1_FCC7 = 0x34,
+	RTW_CHPLAN_WORLD_ETSI2 = 0x35,
+	RTW_CHPLAN_WORLD_ETSI3 = 0x36,
+	RTW_CHPLAN_MKK1_MKK2 = 0x37,
+	RTW_CHPLAN_MKK1_MKK3 = 0x38,
+	RTW_CHPLAN_FCC1_NCC1 = 0x39,
+	RTW_CHPLAN_ETSI1_ETSI1 = 0x3A,
+	RTW_CHPLAN_ETSI1_ACMA1 = 0x3B,
+	RTW_CHPLAN_ETSI1_ETSI6 = 0x3C,
+	RTW_CHPLAN_ETSI1_ETSI12 = 0x3D,
+	RTW_CHPLAN_KCC1_KCC2 = 0x3E,
+	RTW_CHPLAN_FCC1_NCC2 = 0x40,
+	RTW_CHPLAN_GLOBAL_NULL = 0x41,
+	RTW_CHPLAN_ETSI1_ETSI4 = 0x42,
+	RTW_CHPLAN_FCC1_FCC2 = 0x43,
+	RTW_CHPLAN_FCC1_NCC3 = 0x44,
+	RTW_CHPLAN_WORLD_ACMA1 = 0x45,
+	RTW_CHPLAN_FCC1_FCC8 = 0x46,
+	RTW_CHPLAN_WORLD_ETSI6 = 0x47,
+	RTW_CHPLAN_WORLD_ETSI7 = 0x48,
+	RTW_CHPLAN_WORLD_ETSI8 = 0x49,
+	RTW_CHPLAN_WORLD_ETSI9 = 0x50,
+	RTW_CHPLAN_WORLD_ETSI10 = 0x51,
+	RTW_CHPLAN_WORLD_ETSI11 = 0x52,
+	RTW_CHPLAN_FCC1_NCC4 = 0x53,
+	RTW_CHPLAN_WORLD_ETSI12 = 0x54,
+	RTW_CHPLAN_FCC1_FCC9 = 0x55,
+	RTW_CHPLAN_WORLD_ETSI13 = 0x56,
+	RTW_CHPLAN_FCC1_FCC10 = 0x57,
+	RTW_CHPLAN_MKK2_MKK4 = 0x58,
+	RTW_CHPLAN_WORLD_ETSI14 = 0x59,
+	RTW_CHPLAN_FCC1_FCC5 = 0x60,
+	RTW_CHPLAN_FCC2_FCC7 = 0x61,
+	RTW_CHPLAN_FCC2_FCC1 = 0x62,
+	RTW_CHPLAN_WORLD_ETSI15 = 0x63,
+	RTW_CHPLAN_MKK2_MKK5 = 0x64,
+	RTW_CHPLAN_ETSI1_ETSI16 = 0x65,
+	RTW_CHPLAN_FCC1_FCC14 = 0x66,
+	RTW_CHPLAN_FCC1_FCC12 = 0x67,
+	RTW_CHPLAN_FCC2_FCC14 = 0x68,
+	RTW_CHPLAN_FCC2_FCC12 = 0x69,
+	RTW_CHPLAN_ETSI1_ETSI17 = 0x6A,
+	RTW_CHPLAN_WORLD_FCC16 = 0x6B,
+	RTW_CHPLAN_WORLD_FCC13 = 0x6C,
+	RTW_CHPLAN_FCC2_FCC15 = 0x6D,
+	RTW_CHPLAN_WORLD_FCC12 = 0x6E,
+	RTW_CHPLAN_NULL_ETSI8 = 0x6F,
+	RTW_CHPLAN_NULL_ETSI18 = 0x70,
+	RTW_CHPLAN_NULL_ETSI17 = 0x71,
+	RTW_CHPLAN_NULL_ETSI19 = 0x72,
+	RTW_CHPLAN_WORLD_FCC7 = 0x73,
+	RTW_CHPLAN_FCC2_FCC17 = 0x74,
+	RTW_CHPLAN_WORLD_ETSI20 = 0x75,
+	RTW_CHPLAN_FCC2_FCC11 = 0x76,
+	RTW_CHPLAN_WORLD_ETSI21 = 0x77,
+	RTW_CHPLAN_FCC1_FCC18 = 0x78,
+	RTW_CHPLAN_MKK2_MKK1 = 0x79,
+
+	RTW_CHPLAN_MAX,
+	RTW_CHPLAN_REALTEK_DEFINE = 0x7F,
+	RTW_CHPLAN_UNSPECIFIED = 0xFF,
+};
+
+u8 rtw_chplan_get_default_regd(u8 id);
+bool rtw_chplan_is_empty(u8 id);
+#define rtw_is_channel_plan_valid(chplan) (((chplan) < RTW_CHPLAN_MAX || (chplan) == RTW_CHPLAN_REALTEK_DEFINE) && !rtw_chplan_is_empty(chplan))
+#define rtw_is_legacy_channel_plan(chplan) ((chplan) < 0x20)
+
+struct _RT_CHANNEL_INFO;
+u8 init_channel_set(_adapter *padapter, u8 ChannelPlan, struct _RT_CHANNEL_INFO *channel_set);
+
+#define IS_ALPHA2_NO_SPECIFIED(_alpha2) ((*((u16 *)(_alpha2))) == 0xFFFF)
+
+#define RTW_MODULE_RTL8821AE_HMC_M2		BIT0	/* RTL8821AE(HMC + M.2) */
+#define RTW_MODULE_RTL8821AU			BIT1	/* RTL8821AU */
+#define RTW_MODULE_RTL8812AENF_NGFF		BIT2	/* RTL8812AENF(8812AE+8761)_NGFF */
+#define RTW_MODULE_RTL8812AEBT_HMC		BIT3	/* RTL8812AEBT(8812AE+8761)_HMC */
+#define RTW_MODULE_RTL8188EE_HMC_M2		BIT4	/* RTL8188EE(HMC + M.2) */
+#define RTW_MODULE_RTL8723BE_HMC_M2		BIT5	/* RTL8723BE(HMC + M.2) */
+#define RTW_MODULE_RTL8723BS_NGFF1216	BIT6	/* RTL8723BS(NGFF1216) */
+#define RTW_MODULE_RTL8192EEBT_HMC_M2	BIT7	/* RTL8192EEBT(8192EE+8761AU)_(HMC + M.2) */
+#define RTW_MODULE_RTL8723DE_NGFF1630	BIT8	/* RTL8723DE(NGFF1630) */
+#define RTW_MODULE_RTL8822BE			BIT9	/* RTL8822BE */
+#define RTW_MODULE_RTL8821CE			BIT10	/* RTL8821CE */
+
+struct country_chplan {
+	char alpha2[2];
+	u8 chplan;
+#ifdef CONFIG_80211AC_VHT
+	u8 en_11ac;
+#endif
+#if RTW_DEF_MODULE_REGULATORY_CERT
+	u16 def_module_flags; /* RTW_MODULE_RTLXXX */
+#endif
+};
+
+#ifdef CONFIG_80211AC_VHT
+#define COUNTRY_CHPLAN_EN_11AC(_ent) ((_ent)->en_11ac)
+#else
+#define COUNTRY_CHPLAN_EN_11AC(_ent) 0
+#endif
+
+#if RTW_DEF_MODULE_REGULATORY_CERT
+#define COUNTRY_CHPLAN_DEF_MODULE_FALGS(_ent) ((_ent)->def_module_flags)
+#else
+#define COUNTRY_CHPLAN_DEF_MODULE_FALGS(_ent) 0
+#endif
+
+const struct country_chplan *rtw_get_chplan_from_country(const char *country_code);
+
+void dump_country_chplan(void *sel, const struct country_chplan *ent);
+void dump_country_chplan_map(void *sel);
+void dump_chplan_id_list(void *sel);
+void dump_chplan_test(void *sel);
+void dump_chplan_ver(void *sel);
+
+#endif /* __RTW_CHPLAN_H__ */

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 499 - 260
core/rtw_cmd.c


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 407 - 213
core/rtw_debug.c


+ 2 - 7
core/rtw_eeprom.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_EEPROM_C_
 
 #include <drv_conf.h>

+ 314 - 141
core/rtw_ieee80211.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _IEEE80211_C
 
 #ifdef CONFIG_PLATFORM_INTEL_BYT
@@ -132,6 +127,19 @@ int rtw_get_bit_value_from_ieee_value(u8 val)
 	}
 	return 0;
 }
+uint rtw_get_cckrate_size(u8 *rate, u32 rate_length)
+{
+	int i = 0;
+	while(i < rate_length){
+		RTW_DBG("%s, rate[%d]=%u\n", __FUNCTION__, i, rate[i]);
+		if (((rate[i] & 0x7f) == 2) || ((rate[i] & 0x7f) == 4) ||
+			((rate[i] & 0x7f) == 11)  || ((rate[i] & 0x7f) == 22))
+			i++;
+		else
+			break;
+	}
+	return i;
+}
 
 uint	rtw_is_cckrates_included(u8 *rate)
 {
@@ -196,7 +204,7 @@ u8 *rtw_set_ie
 	u8 *pbuf,
 	sint index,
 	uint len,
-	u8 *source,
+	const u8 *source,
 	uint *frlen /* frame length */
 )
 {
@@ -207,7 +215,8 @@ u8 *rtw_set_ie
 	if (len > 0)
 		_rtw_memcpy((void *)(pbuf + 2), (void *)source, len);
 
-	*frlen = *frlen + (len + 2);
+	if (frlen)
+		*frlen = *frlen + (len + 2);
 
 	return pbuf + len + 2;
 }
@@ -228,9 +237,9 @@ inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset)
 	if (ch_offset == SCN)
 		return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
 	else if (ch_offset == SCA)
-		return HAL_PRIME_CHNL_OFFSET_UPPER;
-	else if (ch_offset == SCB)
 		return HAL_PRIME_CHNL_OFFSET_LOWER;
+	else if (ch_offset == SCB)
+		return HAL_PRIME_CHNL_OFFSET_UPPER;
 
 	return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
 }
@@ -240,9 +249,9 @@ inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset)
 	if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
 		return SCN;
 	else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
-		return SCB;
-	else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
 		return SCA;
+	else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+		return SCB;
 
 	return SCN;
 }
@@ -268,10 +277,10 @@ inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
 /*----------------------------------------------------------------------------
 index: the information element id index, limit is the limit for search
 -----------------------------------------------------------------------------*/
-u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit)
+u8 *rtw_get_ie(const u8 *pbuf, sint index, sint *len, sint limit)
 {
 	sint tmp, i;
-	u8 *p;
+	const u8 *p;
 	if (limit < 1) {
 		return NULL;
 	}
@@ -282,7 +291,7 @@ u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit)
 	while (1) {
 		if (*p == index) {
 			*len = *(p + 1);
-			return p;
+			return (u8 *)p;
 		} else {
 			tmp = *(p + 1);
 			p += (tmp + 2);
@@ -306,17 +315,17 @@ u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit)
  *
  * Returns: The address of the specific IE found, or NULL
  */
-u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen)
+u8 *rtw_get_ie_ex(const u8 *in_ie, uint in_len, u8 eid, const u8 *oui, u8 oui_len, u8 *ie, uint *ielen)
 {
 	uint cnt;
-	u8 *target_ie = NULL;
+	const u8 *target_ie = NULL;
 
 
 	if (ielen)
 		*ielen = 0;
 
 	if (!in_ie || in_len <= 0)
-		return target_ie;
+		return (u8 *)target_ie;
 
 	cnt = 0;
 
@@ -338,7 +347,7 @@ u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, u
 
 	}
 
-	return target_ie;
+	return (u8 *)target_ie;
 }
 
 /**
@@ -385,6 +394,52 @@ exit:
 	return ret;
 }
 
+ /* Returns:  remove size OR  _FAIL: not updated*/
+int rtw_remove_ie_g_rate(u8 *ie, uint *ie_len, uint offset, u8 eid)
+{
+	int ret = _FAIL;
+	u8 *tem_target_ie;
+	u8 *target_ie;
+	u32 target_ielen,temp_target_ielen,cck_rate_size,rm_size;
+	u8 *start;
+	uint search_len;
+	u8 *remain_ies;
+	uint remain_len;
+	if (!ie || !ie_len || *ie_len <= offset)
+		goto exit;
+
+	start = ie + offset;
+	search_len = *ie_len - offset;
+
+	while (1) {
+		tem_target_ie=rtw_get_ie(start,eid,&temp_target_ielen,search_len);
+		
+		/*if(tem_target_ie)
+			RTW_INFO("%s, tem_target_ie=%u\n", __FUNCTION__,*tem_target_ie);*/
+		if (tem_target_ie && temp_target_ielen) {
+			cck_rate_size = rtw_get_cckrate_size((tem_target_ie+2), temp_target_ielen);
+			rm_size = temp_target_ielen - cck_rate_size;
+			RTW_DBG("%s,cck_rate_size=%u rm_size=%u\n", __FUNCTION__, cck_rate_size, rm_size);
+			temp_target_ielen=temp_target_ielen + 2;/*org size of  Supposrted Rates(include id + length)*/
+			/*RTW_INFO("%s, temp_target_ielen=%u\n", __FUNCTION__,temp_target_ielen);*/
+			remain_ies = tem_target_ie + temp_target_ielen;
+			remain_len = search_len - (remain_ies - start);
+			target_ielen=cck_rate_size;/*discount g mode rate 6, 9 12,18Mbps,id , length*/
+			*(tem_target_ie+1)=target_ielen;/*set new length to Supposrted Rates*/
+			target_ie=tem_target_ie+target_ielen + 2;/*set target ie to address of rate 6Mbps */
+	
+			_rtw_memmove(target_ie, remain_ies, remain_len);
+			*ie_len = *ie_len - rm_size;
+			ret = rm_size;
+
+			start = target_ie;
+			search_len = remain_len;
+		} else
+			break;
+	}
+exit:
+	return ret;
+}
 void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
 {
 
@@ -500,7 +555,7 @@ int rtw_generate_ie(struct registry_priv *pregistrypriv)
 
 #ifdef CONFIG_80211N_HT
 	/* HT Cap. */
-	if (((pregistrypriv->wireless_mode & WIRELESS_11_5N) || (pregistrypriv->wireless_mode & WIRELESS_11_24N))
+	if (is_supported_ht(pregistrypriv->wireless_mode)
 	    && (pregistrypriv->ht_enable == _TRUE)) {
 		/* todo: */
 	}
@@ -679,79 +734,150 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis
 
 }
 
-int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
+int rtw_rsne_info_parse(const u8 *ie, uint ie_len, struct rsne_info *info)
 {
-	int i, ret = _SUCCESS;
-	int left, count;
-	u8 *pos;
-	u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01};
+	const u8 *pos = ie;
+	u16 cnt;
 
-	if (rsn_ie_len <= 0) {
-		/* No RSN IE - fail silently */
-		return _FAIL;
-	}
+	_rtw_memset(info, 0, sizeof(struct rsne_info));
 
+	if (ie + ie_len < pos + 4)
+		goto err;
 
-	if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2)))
-		return _FAIL;
+	if (*ie != WLAN_EID_RSN || *(ie + 1) != ie_len - 2)
+		goto err;
+	pos += 2 + 2;
 
-	pos = rsn_ie;
+	/* Group CS */
+	if (ie + ie_len < pos + 4) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
+	}
+	info->gcs = (u8 *)pos;
 	pos += 4;
-	left = rsn_ie_len - 4;
 
-	/* group_cipher */
-	if (left >= RSN_SELECTOR_LEN) {
+	/* Pairwise CS */
+	if (ie + ie_len < pos + 2) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
+	}
+	cnt = RTW_GET_LE16(pos);
+	pos += 2;
+	if (ie + ie_len < pos + 4 * cnt) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
+	}
+	info->pcs_cnt = cnt;
+	info->pcs_list = (u8 *)pos;
+	pos += 4 * cnt;
 
-		*group_cipher = rtw_get_wpa2_cipher_suite(pos);
+	/* AKM */
+	if (ie + ie_len < pos + 2) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
+	}
+	cnt = RTW_GET_LE16(pos);
+	pos += 2;
+	if (ie + ie_len < pos + 4 * cnt) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
+	}
+	info->akm_cnt = cnt;
+	info->akm_list = (u8 *)pos;
+	pos += 4 * cnt;
 
-		pos += RSN_SELECTOR_LEN;
-		left -= RSN_SELECTOR_LEN;
+	/* RSN cap */
+	if (ie + ie_len < pos + 2) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
+	}
+	info->cap = (u8 *)pos;
+	pos += 2;
 
-	} else if (left > 0) {
-		return _FAIL;
+	/* PMKID */
+	if (ie + ie_len < pos + 2) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
+	}
+	cnt = RTW_GET_LE16(pos);
+	pos += 2;
+	if (ie + ie_len < pos + 16 * cnt) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
 	}
+	info->pmkid_cnt = cnt;
+	info->pmkid_list = (u8 *)pos;
+	pos += 16 * cnt;
 
-	/* pairwise_cipher */
-	if (left >= 2) {
-		/* count = le16_to_cpu(*(u16*)pos); */
-		count = RTW_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
+	/* Group Mgmt CS */
+	if (ie + ie_len < pos + 4) {
+		if (ie + ie_len != pos)
+			goto err;
+		goto exit;
+	}
+	info->gmcs = (u8 *)pos;
 
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
-			return _FAIL;
-		}
+exit:
+	return _SUCCESS;
 
-		for (i = 0; i < count; i++) {
-			*pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
+err:
+	info->err = 1;
+	return _FAIL;
+}
 
-			pos += RSN_SELECTOR_LEN;
-			left -= RSN_SELECTOR_LEN;
-		}
+int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x, u8 *mfp_opt)
+{
+	struct rsne_info info;
+	int i, ret = _SUCCESS;
+	u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01};
 
-	} else if (left == 1) {
+	ret = rtw_rsne_info_parse(rsn_ie, rsn_ie_len, &info);
+	if (ret != _SUCCESS)
+		goto exit;
 
-		return _FAIL;
+	if (group_cipher) {
+		if (info.gcs)
+			*group_cipher = rtw_get_wpa2_cipher_suite(info.gcs);
+		else
+			*group_cipher = 0;
+	}
+
+	if (pairwise_cipher) {
+		*pairwise_cipher = 0;
+		for (i = 0; i < info.pcs_cnt; i++)
+			*pairwise_cipher |= rtw_get_wpa2_cipher_suite(info.pcs_list + 4 * i);
 	}
 
 	if (is_8021x) {
-		if (left >= 6) {
-			pos += 2;
-			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
-				*is_8021x = 1;
-			}
-		}
+		*is_8021x = 0;
+		/* here only check the first AKM suite */
+		if (info.akm_cnt && _rtw_memcmp(SUITE_1X, info.akm_list, 4) == _TRUE)
+			*is_8021x = 1;
 	}
 
-	return ret;
+	if (mfp_opt) {
+		*mfp_opt = MFP_NO;
+		if (info.cap)
+			*mfp_opt = GET_RSN_CAP_MFP_OPTION(info.cap);
+	}
 
+exit:
+	return ret;
 }
 
 /* #ifdef CONFIG_WAPI_SUPPORT */
 int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len)
 {
 	int len = 0;
-	u8 authmode, i;
+	u8 authmode;
 	uint	cnt;
 	u8 wapi_oui1[4] = {0x0, 0x14, 0x72, 0x01};
 	u8 wapi_oui2[4] = {0x0, 0x14, 0x72, 0x02};
@@ -794,7 +920,7 @@ int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len)
 
 int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
 {
-	u8 authmode, sec_idx, i;
+	u8 authmode, sec_idx;
 	u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
 	uint	cnt;
 
@@ -853,23 +979,26 @@ u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
 	return match;
 }
 
-u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen, u8 frame_type)
+u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen, enum bss_type frame_type)
 {
 	u8	*wps = NULL;
 
 	RTW_INFO("[%s] frame_type = %d\n", __FUNCTION__, frame_type);
 	switch (frame_type) {
-	case 1:
-	case 3: {
+	case BSS_TYPE_BCN:
+	case BSS_TYPE_PROB_RSP: {
 		/*	Beacon or Probe Response */
 		wps = rtw_get_wps_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, wps_ie, wps_ielen);
 		break;
 	}
-	case 2: {
+	case BSS_TYPE_PROB_REQ: {
 		/*	Probe Request */
 		wps = rtw_get_wps_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , wps_ie, wps_ielen);
 		break;
 	}
+	default:
+	case BSS_TYPE_UNDEF:
+		break;
 	}
 	return wps;
 }
@@ -883,10 +1012,10 @@ u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps
  *
  * Returns: The address of the WPS IE found, or NULL
  */
-u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
+u8 *rtw_get_wps_ie(const u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
 {
 	uint cnt;
-	u8 *wpsie_ptr = NULL;
+	const u8 *wpsie_ptr = NULL;
 	u8 eid, wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
 
 	if (wps_ielen)
@@ -894,11 +1023,11 @@ u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
 
 	if (!in_ie) {
 		rtw_warn_on(1);
-		return wpsie_ptr;
+		return (u8 *)wpsie_ptr;
 	}
 
 	if (in_len <= 0)
-		return wpsie_ptr;
+		return (u8 *)wpsie_ptr;
 
 	cnt = 0;
 
@@ -925,7 +1054,7 @@ u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
 
 	}
 
-	return wpsie_ptr;
+	return (u8 *)wpsie_ptr;
 }
 
 /**
@@ -1236,6 +1365,28 @@ ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len,
 			elems->vht_op_mode_notify = pos;
 			elems->vht_op_mode_notify_len = elen;
 			break;
+		case _EID_RRM_EN_CAP_IE_:
+			elems->rm_en_cap = pos;
+			elems->rm_en_cap_len = elen;
+			break;
+#ifdef CONFIG_RTW_MESH
+		case WLAN_EID_PREQ:
+			elems->preq = pos;
+			elems->preq_len = elen;
+			break;
+		case WLAN_EID_PREP:
+			elems->prep = pos;
+			elems->prep_len = elen;
+			break;
+		case WLAN_EID_PERR:
+			elems->perr = pos;
+			elems->perr_len = elen;
+			break;
+		case WLAN_EID_RANN:
+			elems->rann = pos;
+			elems->rann_len = elen;
+			break;
+#endif
 		default:
 			unknown++;
 			if (!show_errors)
@@ -1433,40 +1584,70 @@ err_chk:
 }
 
 #ifdef CONFIG_80211N_HT
-void dump_ht_cap_ie_content(void *sel, u8 *buf, u32 buf_len)
+void dump_ht_cap_ie_content(void *sel, const u8 *buf, u32 buf_len)
 {
-	if (buf_len != 26) {
-		RTW_PRINT_SEL(sel, "Invalid HT capability IE len:%d != %d\n", buf_len, 26);
+	if (buf_len != HT_CAP_IE_LEN) {
+		RTW_PRINT_SEL(sel, "Invalid HT capability IE len:%d != %d\n", buf_len, HT_CAP_IE_LEN);
 		return;
 	}
 
-	RTW_PRINT_SEL(sel, "HT Capabilities Info:%02x%02x\n", *(buf), *(buf + 1));
+	RTW_PRINT_SEL(sel, "cap_info:%02x%02x:%s\n", *(buf), *(buf + 1)
+		, GET_HT_CAP_ELE_CHL_WIDTH(buf) ? " 40MHz" : " 20MHz");
 	RTW_PRINT_SEL(sel, "A-MPDU Parameters:"HT_AMPDU_PARA_FMT"\n"
 		      , HT_AMPDU_PARA_ARG(HT_CAP_ELE_AMPDU_PARA(buf)));
 	RTW_PRINT_SEL(sel, "Supported MCS Set:"HT_SUP_MCS_SET_FMT"\n"
 		      , HT_SUP_MCS_SET_ARG(HT_CAP_ELE_SUP_MCS_SET(buf)));
 }
 
-void dump_ht_cap_ie(void *sel, u8 *ie, u32 ie_len)
+void dump_ht_cap_ie(void *sel, const u8 *ie, u32 ie_len)
 {
-	u8 *pos = (u8 *)ie;
-	u16 id;
-	u16 len;
-
-	u8 *ht_cap_ie;
+	const u8 *ht_cap_ie;
 	sint ht_cap_ielen;
 
-	ht_cap_ie = rtw_get_ie(ie, _HT_CAPABILITY_IE_, &ht_cap_ielen, ie_len);
+	ht_cap_ie = rtw_get_ie(ie, WLAN_EID_HT_CAP, &ht_cap_ielen, ie_len);
 	if (!ie || ht_cap_ie != ie)
 		return;
 
 	dump_ht_cap_ie_content(sel, ht_cap_ie + 2, ht_cap_ielen);
 }
+
+const char *const _ht_sc_offset_str[] = {
+	"SCN",
+	"SCA",
+	"SC-RSVD",
+	"SCB",
+};
+
+void dump_ht_op_ie_content(void *sel, const u8 *buf, u32 buf_len)
+{
+	if (buf_len != HT_OP_IE_LEN) {
+		RTW_PRINT_SEL(sel, "Invalid HT operation IE len:%d != %d\n", buf_len, HT_OP_IE_LEN);
+		return;
+	}
+
+	RTW_PRINT_SEL(sel, "ch:%u%s %s\n"
+		, GET_HT_OP_ELE_PRI_CHL(buf)
+		, GET_HT_OP_ELE_STA_CHL_WIDTH(buf) ? "" : " 20MHz only"
+		, ht_sc_offset_str(GET_HT_OP_ELE_2ND_CHL_OFFSET(buf))
+	);
+}
+
+void dump_ht_op_ie(void *sel, const u8 *ie, u32 ie_len)
+{
+	const u8 *ht_op_ie;
+	sint ht_op_ielen;
+
+	ht_op_ie = rtw_get_ie(ie, WLAN_EID_HT_OPERATION, &ht_op_ielen, ie_len);
+	if (!ie || ht_op_ie != ie)
+		return;
+
+	dump_ht_op_ie_content(sel, ht_op_ie + 2, ht_op_ielen);
+}
 #endif /* CONFIG_80211N_HT */
 
-void dump_ies(void *sel, u8 *buf, u32 buf_len)
+void dump_ies(void *sel, const u8 *buf, u32 buf_len)
 {
-	u8 *pos = (u8 *)buf;
+	const u8 *pos = buf;
 	u8 id, len;
 
 	while (pos - buf + 1 < buf_len) {
@@ -1476,6 +1657,11 @@ void dump_ies(void *sel, u8 *buf, u32 buf_len)
 		RTW_PRINT_SEL(sel, "%s ID:%u, LEN:%u\n", __FUNCTION__, id, len);
 #ifdef CONFIG_80211N_HT
 		dump_ht_cap_ie(sel, pos, len + 2);
+		dump_ht_op_ie(sel, pos, len + 2);
+#endif
+#ifdef CONFIG_80211AC_VHT
+		dump_vht_cap_ie(sel, pos, len + 2);
+		dump_vht_op_ie(sel, pos, len + 2);
 #endif
 		dump_wps_ie(sel, pos, len + 2);
 #ifdef CONFIG_P2P
@@ -1489,13 +1675,13 @@ void dump_ies(void *sel, u8 *buf, u32 buf_len)
 	}
 }
 
-void dump_wps_ie(void *sel, u8 *ie, u32 ie_len)
+void dump_wps_ie(void *sel, const u8 *ie, u32 ie_len)
 {
-	u8 *pos = (u8 *)ie;
+	const u8 *pos = ie;
 	u16 id;
 	u16 len;
 
-	u8 *wps_ie;
+	const u8 *wps_ie;
 	uint wps_ielen;
 
 	wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen);
@@ -1521,8 +1707,10 @@ void dump_wps_ie(void *sel, u8 *ie, u32 ie_len)
  * @ch: pointer of ch, used as output
  * @bw: pointer of bw, used as output
  * @offset: pointer of offset, used as output
+ * @ht: check HT IEs
+ * @vht: check VHT IEs, if true imply ht is true
  */
-void rtw_ies_get_chbw(u8 *ies, int ies_len, u8 *ch, u8 *bw, u8 *offset)
+void rtw_ies_get_chbw(u8 *ies, int ies_len, u8 *ch, u8 *bw, u8 *offset, u8 ht, u8 vht)
 {
 	u8 *p;
 	int	ie_len;
@@ -1536,7 +1724,7 @@ void rtw_ies_get_chbw(u8 *ies, int ies_len, u8 *ch, u8 *bw, u8 *offset)
 		*ch = *(p + 2);
 
 #ifdef CONFIG_80211N_HT
-	{
+	if (ht || vht) {
 		u8 *ht_cap_ie, *ht_op_ie;
 		int ht_cap_ielen, ht_op_ielen;
 
@@ -1569,44 +1757,29 @@ void rtw_ies_get_chbw(u8 *ies, int ies_len, u8 *ch, u8 *bw, u8 *offset)
 				}
 			}
 		}
-	}
-#endif /* CONFIG_80211N_HT */
+
 #ifdef CONFIG_80211AC_VHT
-	{
-		u8 *vht_op_ie;
-		int vht_op_ielen;
-
-		vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len);
-		if (vht_op_ie && vht_op_ielen) {
-			/* enable VHT 80 before check enable HT40 or not */
-			if (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2)  >=  1) {
-				/* for HT40, enable VHT80 */
-				if (*bw == CHANNEL_WIDTH_40)
+		if (vht) {
+			u8 *vht_op_ie;
+			int vht_op_ielen;
+
+			vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len);
+			if (vht_op_ie && vht_op_ielen) {
+				if (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2) >= 1)
 					*bw = CHANNEL_WIDTH_80;
-				/* for HT20, enable VHT20 */
-				else if (*bw == CHANNEL_WIDTH_20) {
-					/* modify VHT OP IE */
-					SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0);
-					/* reset to 0 for VHT20 */
-					SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0);
-					SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
-				}
-			} else {
-				/*
-				  VHT OP WIDTH = 0  under HT20/HT40
-				  if REGSTY_BW_5G(pregistrypriv) < CHANNEL_WIDTH_80 in rtw_build_vht_operation_ie
-				*/
 			}
 		}
+#endif /* CONFIG_80211AC_VHT */
+
 	}
-#endif
+#endif /* CONFIG_80211N_HT */
 }
 
-void rtw_bss_get_chbw(WLAN_BSSID_EX *bss, u8 *ch, u8 *bw, u8 *offset)
+void rtw_bss_get_chbw(WLAN_BSSID_EX *bss, u8 *ch, u8 *bw, u8 *offset, u8 ht, u8 vht)
 {
 	rtw_ies_get_chbw(bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)
 		, bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)
-		, ch, bw, offset);
+		, ch, bw, offset, ht, vht);
 
 	if (*ch == 0)
 		*ch = bss->Configuration.DSConfig;
@@ -1673,7 +1846,7 @@ void rtw_sync_chbw(u8 *req_ch, u8 *req_bw, u8 *req_offset
 		if (*g_bw == CHANNEL_WIDTH_40 || *g_bw == CHANNEL_WIDTH_80)
 			*req_offset = *g_offset;
 		else if (*g_bw == CHANNEL_WIDTH_20)
-			*req_offset = rtw_get_offset_by_ch(*req_ch);
+			rtw_get_offset_by_chbw(*req_ch, *req_bw, req_offset);
 
 		if (*req_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {
 			RTW_ERR("%s req 80MHz BW without offset, down to 20MHz\n", __func__);
@@ -1685,7 +1858,7 @@ void rtw_sync_chbw(u8 *req_ch, u8 *req_bw, u8 *req_offset
 		if (*g_bw == CHANNEL_WIDTH_40 || *g_bw == CHANNEL_WIDTH_80)
 			*req_offset = *g_offset;
 		else if (*g_bw == CHANNEL_WIDTH_20)
-			*req_offset = rtw_get_offset_by_ch(*req_ch);
+			rtw_get_offset_by_chbw(*req_ch, *req_bw, req_offset);
 
 		if (*req_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {
 			RTW_ERR("%s req 40MHz BW without offset, down to 20MHz\n", __func__);
@@ -1718,7 +1891,7 @@ u32 rtw_get_p2p_merged_ies_len(u8 *in_ie, u32 in_len)
 	PNDIS_802_11_VARIABLE_IEs	pIE;
 	u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 };
 	int i = 0;
-	int j = 0, len = 0;
+	int len = 0;
 
 	while (i < in_len) {
 		pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie + i);
@@ -1773,13 +1946,13 @@ int rtw_p2p_merge_ies(u8 *in_ie, u32 in_len, u8 *merge_ie)
 	return 0;
 }
 
-void dump_p2p_ie(void *sel, u8 *ie, u32 ie_len)
+void dump_p2p_ie(void *sel, const u8 *ie, u32 ie_len)
 {
-	u8 *pos = (u8 *)ie;
+	const u8 *pos = ie;
 	u8 id;
 	u16 len;
 
-	u8 *p2p_ie;
+	const u8 *p2p_ie;
 	uint p2p_ielen;
 
 	p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen);
@@ -1807,10 +1980,10 @@ void dump_p2p_ie(void *sel, u8 *ie, u32 ie_len)
  *
  * Returns: The address of the P2P IE found, or NULL
  */
-u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
+u8 *rtw_get_p2p_ie(const u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
 {
 	uint cnt;
-	u8 *p2p_ie_ptr = NULL;
+	const u8 *p2p_ie_ptr = NULL;
 	u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
 
 	if (p2p_ielen)
@@ -1818,11 +1991,11 @@ u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
 
 	if (!in_ie || in_len < 0) {
 		rtw_warn_on(1);
-		return p2p_ie_ptr;
+		return (u8 *)p2p_ie_ptr;
 	}
 
 	if (in_len <= 0)
-		return p2p_ie_ptr;
+		return (u8 *)p2p_ie_ptr;
 
 	cnt = 0;
 
@@ -1849,7 +2022,7 @@ u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
 
 	}
 
-	return p2p_ie_ptr;
+	return (u8 *)p2p_ie_ptr;
 }
 
 /**
@@ -2117,13 +2290,13 @@ void rtw_bss_ex_del_p2p_attr(WLAN_BSSID_EX *bss_ex, u8 attr_id)
 	}
 }
 
-void dump_wfd_ie(void *sel, u8 *ie, u32 ie_len)
+void dump_wfd_ie(void *sel, const u8 *ie, u32 ie_len)
 {
-	u8 *pos = (u8 *)ie;
+	const u8 *pos = ie;
 	u8 id;
 	u16 len;
 
-	u8 *wfd_ie;
+	const u8 *wfd_ie;
 	uint wfd_ielen;
 
 	wfd_ie = rtw_get_wfd_ie(ie, ie_len, NULL, &wfd_ielen);
@@ -2151,10 +2324,10 @@ void dump_wfd_ie(void *sel, u8 *ie, u32 ie_len)
  *
  * Returns: The address of the P2P IE found, or NULL
  */
-u8 *rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen)
+u8 *rtw_get_wfd_ie(const u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen)
 {
 	uint cnt;
-	u8 *wfd_ie_ptr = NULL;
+	const u8 *wfd_ie_ptr = NULL;
 	u8 eid, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A};
 
 	if (wfd_ielen)
@@ -2162,11 +2335,11 @@ u8 *rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen)
 
 	if (!in_ie || in_len < 0) {
 		rtw_warn_on(1);
-		return wfd_ie_ptr;
+		return (u8 *)wfd_ie_ptr;
 	}
 
 	if (in_len <= 0)
-		return wfd_ie_ptr;
+		return (u8 *)wfd_ie_ptr;
 
 	cnt = 0;
 
@@ -2193,7 +2366,7 @@ u8 *rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen)
 
 	}
 
-	return wfd_ie_ptr;
+	return (u8 *)wfd_ie_ptr;
 }
 
 /**
@@ -2508,7 +2681,7 @@ int rtw_get_cipher_info(struct wlan_network *pnetwork)
 		pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
 
 		if (pbuf && (wpa_ielen > 0)) {
-			if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) {
+			if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x, NULL)) {
 				pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
 				pnetwork->BcnInfo.group_cipher = group_cipher;
 				pnetwork->BcnInfo.is_8021x = is8021x;

+ 255 - 53
core/rtw_io.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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 purpose of rtw_io.c
@@ -424,9 +419,13 @@ u32 _rtw_write_port_and_wait(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem, int
 
 	ret = _rtw_write_port(adapter, addr, cnt, pmem);
 
-	if (ret == _SUCCESS)
+	if (ret == _SUCCESS) {
 		ret = rtw_sctx_wait(&sctx, __func__);
 
+		if (ret != _SUCCESS)
+			pxmitbuf->sctx = NULL;
+	}
+
 	return ret;
 }
 
@@ -489,39 +488,192 @@ void rtw_reset_continual_io_error(struct dvobj_priv *dvobj)
 }
 
 #ifdef DBG_IO
+#define RTW_IO_SNIFF_TYPE_RANGE	0 /* specific address range is accessed */
+#define RTW_IO_SNIFF_TYPE_EN	1 /* part or all sniffed range is enabled */
+#define RTW_IO_SNIFF_TYPE_DIS	2 /* part or all sniffed range is disabled */
+
+struct rtw_io_sniff_ent {
+	u8 chip;
+	u8 hci;
+	u32 addr;
+	u8 type;
+	union {
+		u32 end_addr;
+		u32 mask;
+	} u;
+	char *tag;
+};
+
+const char *rtw_io_sniff_ent_get_tag(const struct rtw_io_sniff_ent *ent)
+{
+	return ent->tag;
+}
 
-u32 read_sniff_ranges[][2] = {
-	/* {0x520, 0x523}, */
+#define RTW_IO_SNIFF_RANGE_ENT(_chip, _hci, _addr, _end_addr, _tag) \
+	{.chip = _chip, .hci = _hci, .addr = _addr, .u.end_addr = _end_addr, .tag = _tag, .type = RTW_IO_SNIFF_TYPE_RANGE,}
+
+#define RTW_IO_SNIFF_EN_ENT(_chip, _hci, _addr, _mask, _tag) \
+	{.chip = _chip, .hci = _hci, .addr = _addr, .u.mask = _mask, .tag = _tag, .type = RTW_IO_SNIFF_TYPE_EN,}
+
+#define RTW_IO_SNIFF_DIS_ENT(_chip, _hci, _addr, _mask, _tag) \
+	{.chip = _chip, .hci = _hci, .addr = _addr, .u.mask = _mask, .tag = _tag, .type = RTW_IO_SNIFF_TYPE_DIS,}
+
+const struct rtw_io_sniff_ent read_sniff[] = {
+#ifdef DBG_IO_HCI_EN_CHK
+	RTW_IO_SNIFF_EN_ENT(MAX_CHIP_TYPE, RTW_SDIO, 0x02, 0x1FC, "SDIO 0x02[8:2] not all 0"),
+	RTW_IO_SNIFF_EN_ENT(MAX_CHIP_TYPE, RTW_USB, 0x02, 0x1E0, "USB 0x02[8:5] not all 0"),
+	RTW_IO_SNIFF_EN_ENT(MAX_CHIP_TYPE, RTW_PCIE, 0x02, 0x01C, "PCI 0x02[4:2] not all 0"),
+#endif
+#ifdef DBG_IO_SNIFF_EXAMPLE
+	RTW_IO_SNIFF_RANGE_ENT(MAX_CHIP_TYPE, 0, 0x522, 0x522, "read TXPAUSE"),
+	RTW_IO_SNIFF_DIS_ENT(MAX_CHIP_TYPE, 0, 0x02, 0x3, "0x02[1:0] not all 1"),
+#endif
 };
 
-u32 write_sniff_ranges[][2] = {
-	/* {0x520, 0x523}, */
-	/* {0x4c, 0x4c}, */
+const int read_sniff_num = sizeof(read_sniff) / sizeof(struct rtw_io_sniff_ent);
+
+const struct rtw_io_sniff_ent write_sniff[] = {
+#ifdef DBG_IO_HCI_EN_CHK
+	RTW_IO_SNIFF_EN_ENT(MAX_CHIP_TYPE, RTW_SDIO, 0x02, 0x1FC, "SDIO 0x02[8:2] not all 0"),
+	RTW_IO_SNIFF_EN_ENT(MAX_CHIP_TYPE, RTW_USB, 0x02, 0x1E0, "USB 0x02[8:5] not all 0"),
+	RTW_IO_SNIFF_EN_ENT(MAX_CHIP_TYPE, RTW_PCIE, 0x02, 0x01C, "PCI 0x02[4:2] not all 0"),
+#endif
+#ifdef DBG_IO_SNIFF_EXAMPLE
+	RTW_IO_SNIFF_RANGE_ENT(MAX_CHIP_TYPE, 0, 0x522, 0x522, "write TXPAUSE"),
+	RTW_IO_SNIFF_DIS_ENT(MAX_CHIP_TYPE, 0, 0x02, 0x3, "0x02[1:0] not all 1"),
+#endif
 };
 
-int read_sniff_num = sizeof(read_sniff_ranges) / sizeof(u32) / 2;
-int write_sniff_num = sizeof(write_sniff_ranges) / sizeof(u32) / 2;
+const int write_sniff_num = sizeof(write_sniff) / sizeof(struct rtw_io_sniff_ent);
+
+static bool match_io_sniff_ranges(_adapter *adapter
+	, const struct rtw_io_sniff_ent *sniff, int i, u32 addr, u16 len)
+{
+
+	/* check if IO range after sniff end address */
+	if (addr > sniff->u.end_addr)
+		return 0;
+
+	return 1;
+}
+
+static bool match_io_sniff_en(_adapter *adapter
+	, const struct rtw_io_sniff_ent *sniff, int i, u32 addr, u8 len, u32 val)
+{
+	u8 sniff_len;
+	u8 shift;
+	u32 mask;
+	bool ret = 0;
+
+	/* check if IO range after sniff end address */
+	sniff_len = 4;
+	while (!(sniff->u.mask & (0xFF << ((sniff_len - 1) * 8)))) {
+		sniff_len--;
+		if (sniff_len == 0)
+			goto exit;
+	}
+	if (sniff->addr + sniff_len <= addr)
+		goto exit;
+
+	if (sniff->addr > addr) {
+		shift = (sniff->addr - addr) * 8;
+		mask = sniff->u.mask << shift;
+	} else if (sniff->addr < addr) {
+		shift = (addr - sniff->addr) * 8;
+		mask = sniff->u.mask >> shift;
+	} else {
+		shift = 0;
+		mask = sniff->u.mask;
+	}
+
+	if (sniff->type == RTW_IO_SNIFF_TYPE_DIS) {
+		if (len == 4)
+			mask &= 0xFFFFFFFF;
+		else if (len == 3)
+			mask &= 0x00FFFFFF;
+		else if (len == 2)
+			mask &= 0x0000FFFF;
+		else if (len == 1)
+			mask &= 0x000000FF;
+		else
+			mask &= 0x00000000;
+	}
+	
+	if ((sniff->type == RTW_IO_SNIFF_TYPE_EN && (mask & val))
+		|| (sniff->type == RTW_IO_SNIFF_TYPE_DIS && (mask & val) != mask)
+	) {
+		ret = 1;
+		if (0)
+			RTW_INFO(FUNC_ADPT_FMT" addr:0x%x len:%u val:0x%x i:%d sniff_len:%u shift:%u mask:0x%x\n"
+				, FUNC_ADPT_ARG(adapter), addr, len, val, i, sniff_len, shift, mask);
+	}
+
+exit:
+	return ret;
+}
+
+static bool match_io_sniff(_adapter *adapter
+	, const struct rtw_io_sniff_ent *sniff, int i, u32 addr, u8 len, u32 val)
+{
+	bool ret = 0;
+
+	if (sniff->chip != MAX_CHIP_TYPE
+		&& sniff->chip != rtw_get_chip_type(adapter))
+		goto exit;
+	if (sniff->hci
+		&& !(sniff->hci & rtw_get_intf_type(adapter)))
+		goto exit;
+	if (sniff->addr >= addr + len) /* IO range below sniff start address */
+		goto exit;
+
+	switch (sniff->type) {
+	case RTW_IO_SNIFF_TYPE_RANGE:
+		ret = match_io_sniff_ranges(adapter, sniff, i, addr, len);
+		break;
+	case RTW_IO_SNIFF_TYPE_EN:
+	case RTW_IO_SNIFF_TYPE_DIS:
+		if (len == 1 || len == 2 || len == 4)
+			ret = match_io_sniff_en(adapter, sniff, i, addr, len, val);
+		break;
+	default:
+		rtw_warn_on(1);
+		break;
+	}
+
+exit:
+	return ret;
+}
 
-bool match_read_sniff_ranges(u32 addr, u16 len)
+const struct rtw_io_sniff_ent *match_read_sniff(_adapter *adapter
+	, u32 addr, u16 len, u32 val)
 {
 	int i;
+	bool ret = 0;
+
 	for (i = 0; i < read_sniff_num; i++) {
-		if (addr + len > read_sniff_ranges[i][0] && addr <= read_sniff_ranges[i][1])
-			return _TRUE;
+		ret = match_io_sniff(adapter, &read_sniff[i], i, addr, len, val);
+		if (ret)
+			goto exit;
 	}
 
-	return _FALSE;
+exit:
+	return ret ? &read_sniff[i] : NULL;
 }
 
-bool match_write_sniff_ranges(u32 addr, u16 len)
+const struct rtw_io_sniff_ent *match_write_sniff(_adapter *adapter
+	, u32 addr, u16 len, u32 val)
 {
 	int i;
+	bool ret = 0;
+
 	for (i = 0; i < write_sniff_num; i++) {
-		if (addr + len > write_sniff_ranges[i][0] && addr <= write_sniff_ranges[i][1])
-			return _TRUE;
+		ret = match_io_sniff(adapter, &write_sniff[i], i, addr, len, val);
+		if (ret)
+			goto exit;
 	}
 
-	return _FALSE;
+exit:
+	return ret ? &write_sniff[i] : NULL;
 }
 
 struct rf_sniff_ent {
@@ -543,7 +695,7 @@ struct rf_sniff_ent rf_write_sniff_ranges[] = {
 int rf_read_sniff_num = sizeof(rf_read_sniff_ranges) / sizeof(struct rf_sniff_ent);
 int rf_write_sniff_num = sizeof(rf_write_sniff_ranges) / sizeof(struct rf_sniff_ent);
 
-bool match_rf_read_sniff_ranges(u8 path, u32 addr, u32 mask)
+bool match_rf_read_sniff_ranges(_adapter *adapter, u8 path, u32 addr, u32 mask)
 {
 	int i;
 
@@ -556,7 +708,7 @@ bool match_rf_read_sniff_ranges(u8 path, u32 addr, u32 mask)
 	return _FALSE;
 }
 
-bool match_rf_write_sniff_ranges(u8 path, u32 addr, u32 mask)
+bool match_rf_write_sniff_ranges(_adapter *adapter, u8 path, u32 addr, u32 mask)
 {
 	int i;
 
@@ -572,9 +724,12 @@ bool match_rf_write_sniff_ranges(u8 path, u32 addr, u32 mask)
 u8 dbg_rtw_read8(_adapter *adapter, u32 addr, const char *caller, const int line)
 {
 	u8 val = _rtw_read8(adapter, addr);
+	const struct rtw_io_sniff_ent *ent = match_read_sniff(adapter, addr, 1, val);
 
-	if (match_read_sniff_ranges(addr, 1))
-		RTW_INFO("DBG_IO %s:%d rtw_read8(0x%04x) return 0x%02x\n", caller, line, addr, val);
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_read8(0x%04x) return 0x%02x %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return val;
 }
@@ -582,9 +737,12 @@ u8 dbg_rtw_read8(_adapter *adapter, u32 addr, const char *caller, const int line
 u16 dbg_rtw_read16(_adapter *adapter, u32 addr, const char *caller, const int line)
 {
 	u16 val = _rtw_read16(adapter, addr);
+	const struct rtw_io_sniff_ent *ent = match_read_sniff(adapter, addr, 2, val);
 
-	if (match_read_sniff_ranges(addr, 2))
-		RTW_INFO("DBG_IO %s:%d rtw_read16(0x%04x) return 0x%04x\n", caller, line, addr, val);
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_read16(0x%04x) return 0x%04x %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return val;
 }
@@ -592,38 +750,57 @@ u16 dbg_rtw_read16(_adapter *adapter, u32 addr, const char *caller, const int li
 u32 dbg_rtw_read32(_adapter *adapter, u32 addr, const char *caller, const int line)
 {
 	u32 val = _rtw_read32(adapter, addr);
+	const struct rtw_io_sniff_ent *ent = match_read_sniff(adapter, addr, 4, val);
 
-	if (match_read_sniff_ranges(addr, 4))
-		RTW_INFO("DBG_IO %s:%d rtw_read32(0x%04x) return 0x%08x\n", caller, line, addr, val);
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_read32(0x%04x) return 0x%08x %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return val;
 }
 
 int dbg_rtw_write8(_adapter *adapter, u32 addr, u8 val, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 1))
-		RTW_INFO("DBG_IO %s:%d rtw_write8(0x%04x, 0x%02x)\n", caller, line, addr, val);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(adapter, addr, 1, val);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_write8(0x%04x, 0x%02x) %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_write8(adapter, addr, val);
 }
 int dbg_rtw_write16(_adapter *adapter, u32 addr, u16 val, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 2))
-		RTW_INFO("DBG_IO %s:%d rtw_write16(0x%04x, 0x%04x)\n", caller, line, addr, val);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(adapter, addr, 2, val);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_write16(0x%04x, 0x%04x) %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_write16(adapter, addr, val);
 }
 int dbg_rtw_write32(_adapter *adapter, u32 addr, u32 val, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 4))
-		RTW_INFO("DBG_IO %s:%d rtw_write32(0x%04x, 0x%08x)\n", caller, line, addr, val);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(adapter, addr, 4, val);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_write32(0x%04x, 0x%08x) %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_write32(adapter, addr, val);
 }
 int dbg_rtw_writeN(_adapter *adapter, u32 addr , u32 length , u8 *data, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, length))
-		RTW_INFO("DBG_IO %s:%d rtw_writeN(0x%04x, %u)\n", caller, line, addr, length);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(adapter, addr, length, 0);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_writeN(0x%04x, %u) %s\n"
+			, caller, line, addr, length, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_writeN(adapter, addr, length, data);
 }
@@ -634,8 +811,12 @@ u8 dbg_rtw_sd_f0_read8(_adapter *adapter, u32 addr, const char *caller, const in
 	u8 val = _rtw_sd_f0_read8(adapter, addr);
 
 #if 0
-	if (match_read_sniff_ranges(addr, 1))
-		RTW_INFO("DBG_IO %s:%d rtw_sd_f0_read8(0x%04x) return 0x%02x\n", caller, line, addr, val);
+	const struct rtw_io_sniff_ent *ent = match_read_sniff(adapter, addr, 1, val);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_sd_f0_read8(0x%04x) return 0x%02x %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 #endif
 
 	return val;
@@ -645,9 +826,12 @@ u8 dbg_rtw_sd_f0_read8(_adapter *adapter, u32 addr, const char *caller, const in
 u8 dbg_rtw_sd_iread8(_adapter *adapter, u32 addr, const char *caller, const int line)
 {
 	u8 val = rtw_sd_iread8(adapter, addr);
+	const struct rtw_io_sniff_ent *ent = match_read_sniff(adapter, addr, 1, val);
 
-	if (match_read_sniff_ranges(addr, 1))
-		RTW_INFO("DBG_IO %s:%d rtw_sd_iread8(0x%04x) return 0x%02x\n", caller, line, addr, val);
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_sd_iread8(0x%04x) return 0x%02x %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return val;
 }
@@ -655,9 +839,12 @@ u8 dbg_rtw_sd_iread8(_adapter *adapter, u32 addr, const char *caller, const int
 u16 dbg_rtw_sd_iread16(_adapter *adapter, u32 addr, const char *caller, const int line)
 {
 	u16 val = _rtw_sd_iread16(adapter, addr);
+	const struct rtw_io_sniff_ent *ent = match_read_sniff(adapter, addr, 2, val);
 
-	if (match_read_sniff_ranges(addr, 2))
-		RTW_INFO("DBG_IO %s:%d rtw_sd_iread16(0x%04x) return 0x%04x\n", caller, line, addr, val);
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_sd_iread16(0x%04x) return 0x%04x %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return val;
 }
@@ -665,31 +852,46 @@ u16 dbg_rtw_sd_iread16(_adapter *adapter, u32 addr, const char *caller, const in
 u32 dbg_rtw_sd_iread32(_adapter *adapter, u32 addr, const char *caller, const int line)
 {
 	u32 val = _rtw_sd_iread32(adapter, addr);
+	const struct rtw_io_sniff_ent *ent = match_read_sniff(adapter, addr, 4, val);
 
-	if (match_read_sniff_ranges(addr, 4))
-		RTW_INFO("DBG_IO %s:%d rtw_sd_iread32(0x%04x) return 0x%08x\n", caller, line, addr, val);
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_sd_iread32(0x%04x) return 0x%08x %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return val;
 }
 
 int dbg_rtw_sd_iwrite8(_adapter *adapter, u32 addr, u8 val, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 1))
-		RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite8(0x%04x, 0x%02x)\n", caller, line, addr, val);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(adapter, addr, 1, val);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite8(0x%04x, 0x%02x) %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_sd_iwrite8(adapter, addr, val);
 }
 int dbg_rtw_sd_iwrite16(_adapter *adapter, u32 addr, u16 val, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 2))
-		RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite16(0x%04x, 0x%04x)\n", caller, line, addr, val);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(adapter, addr, 2, val);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite16(0x%04x, 0x%04x) %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_sd_iwrite16(adapter, addr, val);
 }
 int dbg_rtw_sd_iwrite32(_adapter *adapter, u32 addr, u32 val, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 4))
-		RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite32(0x%04x, 0x%08x)\n", caller, line, addr, val);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(adapter, addr, 4, val);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite32(0x%04x, 0x%08x) %s\n"
+			, caller, line, addr, val, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_sd_iwrite32(adapter, addr, val);
 }

+ 2 - 7
core/rtw_ioctl_query.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_IOCTL_QUERY_C_
 
 #include <drv_types.h>

+ 6 - 9
core/rtw_ioctl_rtl.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define  _RTW_IOCTL_RTL_C_
 
 #include <drv_types.h>
@@ -432,13 +427,14 @@ NDIS_STATUS oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv)
 {
 	NDIS_STATUS		status = NDIS_STATUS_SUCCESS;
 	PADAPTER		padapter = (PADAPTER)(poid_par_priv->adapter_context);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
 
 	if (poid_par_priv->type_of_oid != QUERY_OID) {
 		status = NDIS_STATUS_NOT_ACCEPTED;
 		return status;
 	}
 	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	*(u16 *)poid_par_priv->information_buf = padapter->mlmepriv.ChannelPlan ;
+	*(u16 *)poid_par_priv->information_buf = rfctl->ChannelPlan;
 
 	return status;
 }
@@ -446,13 +442,14 @@ NDIS_STATUS oid_rt_set_channelplan_hdl(struct oid_par_priv *poid_par_priv)
 {
 	NDIS_STATUS		status = NDIS_STATUS_SUCCESS;
 	PADAPTER		padapter = (PADAPTER)(poid_par_priv->adapter_context);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
 
 	if (poid_par_priv->type_of_oid != SET_OID) {
 		status = NDIS_STATUS_NOT_ACCEPTED;
 		return status;
 	}
 
-	padapter->mlmepriv.ChannelPlan  = *(u16 *)poid_par_priv->information_buf ;
+	rfctl->ChannelPlan  = *(u16 *)poid_par_priv->information_buf;
 
 	return status;
 }

+ 94 - 422
core/rtw_ioctl_set.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_IOCTL_SET_C_
 
 #include <drv_types.h>
@@ -47,7 +42,9 @@ u8 rtw_validate_bssid(u8 *bssid)
 
 u8 rtw_validate_ssid(NDIS_802_11_SSID *ssid)
 {
+#ifdef CONFIG_VALIDATE_SSID
 	u8	 i;
+#endif
 	u8	ret = _TRUE;
 
 
@@ -79,6 +76,7 @@ u8 rtw_do_join(_adapter *padapter)
 	_list	*plist, *phead;
 	u8 *pibss = NULL;
 	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct sitesurvey_parm parm;
 	_queue	*queue	= &(pmlmepriv->scanned_queue);
 	u8 ret = _SUCCESS;
 
@@ -96,6 +94,10 @@ u8 rtw_do_join(_adapter *padapter)
 
 	pmlmepriv->to_join = _TRUE;
 
+	rtw_init_sitesurvey_parm(padapter, &parm);
+	_rtw_memcpy(&parm.ssid[0], &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID));
+	parm.ssid_num = 1;
+
 	if (_rtw_queue_empty(queue) == _TRUE) {
 		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
 		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
@@ -106,10 +108,17 @@ u8 rtw_do_join(_adapter *padapter)
 		if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _FALSE
 		    || rtw_to_roam(padapter) > 0
 		   ) {
-			/* submit site_survey_cmd */
-			ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
-			if (_SUCCESS != ret) {
+			u8 ssc_chk = rtw_sitesurvey_condition_check(padapter, _FALSE);
+
+			if ((ssc_chk == SS_ALLOW) || (ssc_chk == SS_DENY_BUSY_TRAFFIC) ){
+				/* submit site_survey_cmd */
+				ret = rtw_sitesurvey_cmd(padapter, &parm);
+				if (_SUCCESS != ret)
+					pmlmepriv->to_join = _FALSE;
+			} else {
+				/*if (ssc_chk == SS_DENY_BUDDY_UNDER_SURVEY)*/
 				pmlmepriv->to_join = _FALSE;
+				ret = _FAIL;
 			}
 		} else {
 			pmlmepriv->to_join = _FALSE;
@@ -155,26 +164,22 @@ u8 rtw_do_join(_adapter *padapter)
 				/* can't associate ; reset under-linking			 */
 				_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
 
-#if 0
-				if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)) {
-					if (_rtw_memcmp(pmlmepriv->cur_network.network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength)) {
-						/* for funk to do roaming */
-						/* funk will reconnect, but funk will not sitesurvey before reconnect */
-						if (pmlmepriv->sitesurveyctrl.traffic_busy == _FALSE)
-							rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
-					}
-
-				}
-#endif
-
 				/* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */
 				/* we try to issue sitesurvey firstly			 */
 				if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _FALSE
 				    || rtw_to_roam(padapter) > 0
 				   ) {
-					/* RTW_INFO("rtw_do_join() when   no desired bss in scanning queue\n"); */
-					ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
-					if (_SUCCESS != ret) {
+					u8 ssc_chk = rtw_sitesurvey_condition_check(padapter, _FALSE);
+
+					if ((ssc_chk == SS_ALLOW) || (ssc_chk == SS_DENY_BUSY_TRAFFIC)){
+						/* RTW_INFO(("rtw_do_join() when   no desired bss in scanning queue\n"); */
+						ret = rtw_sitesurvey_cmd(padapter, &parm);
+						if (_SUCCESS != ret)
+							pmlmepriv->to_join = _FALSE;
+					} else {
+						/*if (ssc_chk == SS_DENY_BUDDY_UNDER_SURVEY) {
+						} else {*/
+						ret = _FAIL;
 						pmlmepriv->to_join = _FALSE;
 					}
 				} else {
@@ -307,7 +312,7 @@ u8 rtw_set_802_11_bssid(_adapter *padapter, u8 *bssid)
 			if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
 				rtw_indicate_disconnect(padapter, 0, _FALSE);
 
-			rtw_free_assoc_resources(padapter, 1);
+			rtw_free_assoc_resources_cmd(padapter, _TRUE, 0);
 
 			if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) {
 				_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
@@ -344,7 +349,6 @@ u8 rtw_set_802_11_ssid(_adapter *padapter, NDIS_802_11_SSID *ssid)
 {
 	_irqL irqL;
 	u8 status = _SUCCESS;
-	u32 cur_time = 0;
 
 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 	struct wlan_network *pnetwork = &pmlmepriv->cur_network;
@@ -379,7 +383,7 @@ u8 rtw_set_802_11_ssid(_adapter *padapter, NDIS_802_11_SSID *ssid)
 					if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
 						rtw_indicate_disconnect(padapter, 0, _FALSE);
 
-					rtw_free_assoc_resources(padapter, 1);
+					rtw_free_assoc_resources_cmd(padapter, _TRUE, 0);
 
 					if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) {
 						_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
@@ -400,7 +404,7 @@ u8 rtw_set_802_11_ssid(_adapter *padapter, NDIS_802_11_SSID *ssid)
 			if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
 				rtw_indicate_disconnect(padapter, 0, _FALSE);
 
-			rtw_free_assoc_resources(padapter, 1);
+			rtw_free_assoc_resources_cmd(padapter, _TRUE, 0);
 
 			if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) {
 				_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
@@ -442,7 +446,6 @@ u8 rtw_set_802_11_connect(_adapter *padapter, u8 *bssid, NDIS_802_11_SSID *ssid)
 {
 	_irqL irqL;
 	u8 status = _SUCCESS;
-	u32 cur_time = 0;
 	bool bssid_valid = _TRUE;
 	bool ssid_valid = _TRUE;
 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -514,16 +517,18 @@ u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter,
 	struct	mlme_priv	*pmlmepriv = &padapter->mlmepriv;
 	struct	wlan_network	*cur_network = &pmlmepriv->cur_network;
 	NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state = &(cur_network->network.InfrastructureMode);
-
-
+	u8 ap2sta_mode = _FALSE;
+	u8 ret = _TRUE;
 
 	if (*pold_state != networktype) {
 		/* RTW_INFO("change mode, old_mode=%d, new_mode=%d, fw_state=0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */
 
-		if (*pold_state == Ndis802_11APMode) {
-			/* change to other mode from Ndis802_11APMode			 */
+		if (*pold_state == Ndis802_11APMode
+			|| *pold_state == Ndis802_11_mesh
+		) {
+			/* change to other mode from Ndis802_11APMode/Ndis802_11_mesh */
 			cur_network->join_res = -1;
-
+			ap2sta_mode = _TRUE;
 #ifdef CONFIG_NATIVEAP_MLME
 			stop_ap_mode(padapter);
 #endif
@@ -536,7 +541,7 @@ u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter,
 
 		if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ||
 		    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE))
-			rtw_free_assoc_resources(padapter, 1);
+			rtw_free_assoc_resources_cmd(padapter, _TRUE, 0);
 
 		if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) {
 			if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
@@ -555,6 +560,9 @@ u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter,
 
 		case Ndis802_11Infrastructure:
 			set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+
+			if (ap2sta_mode)
+				rtw_init_bcmc_stainfo(padapter);
 			break;
 
 		case Ndis802_11APMode:
@@ -566,12 +574,22 @@ u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter,
 
 			break;
 
+#ifdef CONFIG_RTW_MESH
+		case Ndis802_11_mesh:
+			set_fwstate(pmlmepriv, WIFI_MESH_STATE);
+			start_ap_mode(padapter);
+			break;
+#endif
+
 		case Ndis802_11AutoUnknown:
 		case Ndis802_11InfrastructureMax:
 			break;
 		case Ndis802_11Monitor:
 			set_fwstate(pmlmepriv, WIFI_MONITOR_STATE);
 			break;
+		default:
+			ret = _FALSE;
+			rtw_warn_on(1);
 		}
 
 		/* SecClearAllKeys(adapter); */
@@ -580,8 +598,7 @@ u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter,
 		_exit_critical_bh(&pmlmepriv->lock, &irqL);
 	}
 
-
-	return _TRUE;
+	return ret;
 }
 
 
@@ -598,7 +615,7 @@ u8 rtw_set_802_11_disassociate(_adapter *padapter)
 		rtw_disassoc_cmd(padapter, 0, 0);
 		rtw_indicate_disconnect(padapter, 0, _FALSE);
 		/* modify for CONFIG_IEEE80211W, none 11w can use it */
-		rtw_free_assoc_resources_cmd(padapter);
+		rtw_free_assoc_resources_cmd(padapter, _TRUE, 0);
 		if (_FAIL == rtw_pwr_wakeup(padapter))
 			RTW_INFO("%s(): rtw_pwr_wakeup fail !!!\n", __FUNCTION__);
 	}
@@ -610,21 +627,21 @@ u8 rtw_set_802_11_disassociate(_adapter *padapter)
 }
 
 #if 1
-u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, NDIS_802_11_SSID *pssid, int ssid_max_num, struct rtw_ieee80211_channel *ch, int ch_num)
+u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, struct sitesurvey_parm *pparm)
 {
 	_irqL	irqL;
 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 	u8	res = _TRUE;
 
 	_enter_critical_bh(&pmlmepriv->lock, &irqL);
-	res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, ch, ch_num);
+	res = rtw_sitesurvey_cmd(padapter, pparm);
 	_exit_critical_bh(&pmlmepriv->lock, &irqL);
 
 	return res;
 }
 
 #else
-u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, NDIS_802_11_SSID *pssid, int ssid_max_num, struct rtw_ieee80211_channel *ch, int ch_num)
+u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, struct sitesurvey_parm *pparm)
 {
 	_irqL	irqL;
 	struct	mlme_priv		*pmlmepriv = &padapter->mlmepriv;
@@ -656,7 +673,7 @@ u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, NDIS_802_11_SSID *pssid, i
 
 		_enter_critical_bh(&pmlmepriv->lock, &irqL);
 
-		res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0, ch, ch_num);
+		res = rtw_sitesurvey_cmd(padapter, pparm);
 
 		_exit_critical_bh(&pmlmepriv->lock, &irqL);
 	}
@@ -746,374 +763,6 @@ exit:
 
 }
 
-u8 rtw_set_802_11_remove_wep(_adapter *padapter, u32 keyindex)
-{
-
-	u8 ret = _SUCCESS;
-
-
-	if (keyindex >= 0x80000000 || padapter == NULL) {
-
-		ret = _FALSE;
-		goto exit;
-
-	} else {
-		int res;
-		struct security_priv *psecuritypriv = &(padapter->securitypriv);
-		if (keyindex < 4) {
-
-			_rtw_memset(&psecuritypriv->dot11DefKey[keyindex], 0, 16);
-
-			res = rtw_set_key(padapter, psecuritypriv, keyindex, 0, _TRUE);
-
-			psecuritypriv->dot11DefKeylen[keyindex] = 0;
-
-			if (res == _FAIL)
-				ret = _FAIL;
-
-		} else
-			ret = _FAIL;
-
-	}
-
-exit:
-
-
-	return ret;
-
-}
-
-u8 rtw_set_802_11_add_key(_adapter *padapter, NDIS_802_11_KEY *key)
-{
-
-	uint	encryptionalgo;
-	u8 *pbssid;
-	struct sta_info *stainfo;
-	u8	bgroup = _FALSE;
-	u8	bgrouptkey = _FALSE;/* can be remove later */
-	u8	ret = _SUCCESS;
-
-
-	if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)) {
-
-		/* It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, */
-		/* it must fail the request and return NDIS_STATUS_INVALID_DATA. */
-		ret = _FAIL;
-		goto exit;
-	}
-
-	if (key->KeyIndex & 0x40000000) {
-		/* Pairwise key */
-
-
-		pbssid = get_bssid(&padapter->mlmepriv);
-		stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
-
-		if ((stainfo != NULL) && (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)) {
-			encryptionalgo = stainfo->dot118021XPrivacy;
-		} else {
-			encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm;
-		}
-
-
-
-
-		if (key->KeyIndex & 0x000000FF) {
-			/* The key index is specified in the lower 8 bits by values of zero to 255. */
-			/* The key index should be set to zero for a Pairwise key, and the driver should fail with */
-			/* NDIS_STATUS_INVALID_DATA if the lower 8 bits is not zero */
-			ret = _FAIL;
-			goto exit;
-		}
-
-		/* check BSSID */
-		if (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == _TRUE) {
-
-			ret = _FALSE;
-			goto exit;
-		}
-
-		/* Check key length for TKIP. */
-		/* if(encryptionAlgorithm == RT_ENC_TKIP_ENCRYPTION && key->KeyLength != 32) */
-		if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) {
-			ret = _FAIL;
-			goto exit;
-
-		}
-
-		/* Check key length for AES. */
-		if ((encryptionalgo == _AES_) && (key->KeyLength != 16)) {
-			/* For our supplicant, EAPPkt9x.vxd, cannot differentiate TKIP and AES case. */
-			if (key->KeyLength == 32)
-				key->KeyLength = 16;
-			else {
-				ret = _FAIL;
-				goto exit;
-			}
-		}
-
-		/* Check key length for WEP. For NDTEST, 2005.01.27, by rcnjko. -> modify checking condition*/
-		if (((encryptionalgo == _WEP40_) && (key->KeyLength != 5)) || ((encryptionalgo == _WEP104_) && (key->KeyLength != 13))) {
-			ret = _FAIL;
-			goto exit;
-		}
-
-		bgroup = _FALSE;
-
-		/* Check the pairwise key. Added by Annie, 2005-07-06. */
-
-	} else {
-		/* Group key - KeyIndex(BIT30==0) */
-
-
-		/* when add wep key through add key and didn't assigned encryption type before */
-		if ((padapter->securitypriv.ndisauthtype <= 3) && (padapter->securitypriv.dot118021XGrpPrivacy == 0)) {
-
-			switch (key->KeyLength) {
-			case 5:
-				padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
-				break;
-			case 13:
-				padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
-				break;
-			default:
-				padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
-				break;
-			}
-
-			encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm;
-
-
-		} else {
-			encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy;
-
-		}
-
-		if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) == _TRUE) && (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == _FALSE)) {
-			ret = _FAIL;
-			goto exit;
-		}
-
-		/* Check key length for TKIP */
-		if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) {
-
-			ret = _FAIL;
-			goto exit;
-
-		} else if (encryptionalgo == _AES_ && (key->KeyLength != 16 && key->KeyLength != 32)) {
-
-			/* Check key length for AES */
-			/* For NDTEST, we allow keylen=32 in this case. 2005.01.27, by rcnjko. */
-			ret = _FAIL;
-			goto exit;
-		}
-
-		/* Change the key length for EAPPkt9x.vxd. Added by Annie, 2005-11-03. */
-		if ((encryptionalgo ==  _AES_) && (key->KeyLength == 32)) {
-			key->KeyLength = 16;
-		}
-
-		if (key->KeyIndex & 0x8000000) /* error ??? 0x8000_0000 */
-			bgrouptkey = _TRUE;
-
-		if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) == _TRUE) && (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _TRUE))
-			bgrouptkey = _TRUE;
-
-		bgroup = _TRUE;
-
-
-	}
-
-	/* If WEP encryption algorithm, just call rtw_set_802_11_add_wep(). */
-	if ((padapter->securitypriv.dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) && (encryptionalgo == _WEP40_  || encryptionalgo == _WEP104_)) {
-		u8 ret;
-		u32 keyindex;
-		u32 len = FIELD_OFFSET(NDIS_802_11_KEY, KeyMaterial) + key->KeyLength;
-		NDIS_802_11_WEP *wep = &padapter->securitypriv.ndiswep;
-
-
-		wep->Length = len;
-		keyindex = key->KeyIndex & 0x7fffffff;
-		wep->KeyIndex = keyindex ;
-		wep->KeyLength = key->KeyLength;
-
-
-		_rtw_memcpy(wep->KeyMaterial, key->KeyMaterial, key->KeyLength);
-		_rtw_memcpy(&(padapter->securitypriv.dot11DefKey[keyindex].skey[0]), key->KeyMaterial, key->KeyLength);
-
-		padapter->securitypriv.dot11DefKeylen[keyindex] = key->KeyLength;
-		padapter->securitypriv.dot11PrivacyKeyIndex = keyindex;
-
-		ret = rtw_set_802_11_add_wep(padapter, wep);
-
-		goto exit;
-
-	}
-
-	if (key->KeyIndex & 0x20000000) {
-		/* SetRSC */
-		if (bgroup == _TRUE) {
-			NDIS_802_11_KEY_RSC keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL;
-			_rtw_memcpy(&padapter->securitypriv.dot11Grprxpn, &keysrc, 8);
-		} else {
-			NDIS_802_11_KEY_RSC keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL;
-			_rtw_memcpy(&padapter->securitypriv.dot11Grptxpn, &keysrc, 8);
-		}
-
-	}
-
-	/* Indicate this key idx is used for TX */
-	/* Save the key in KeyMaterial */
-	if (bgroup == _TRUE) { /* Group transmit key */
-		int res;
-
-		if (bgrouptkey == _TRUE)
-			padapter->securitypriv.dot118021XGrpKeyid = (u8)key->KeyIndex;
-
-		if ((key->KeyIndex & 0x3) == 0) {
-			ret = _FAIL;
-			goto exit;
-		}
-
-		_rtw_memset(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
-		_rtw_memset(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
-		_rtw_memset(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
-
-		if ((key->KeyIndex & 0x10000000)) {
-			_rtw_memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8);
-			_rtw_memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8);
-
-
-		} else {
-			_rtw_memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8);
-			_rtw_memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8);
-
-
-		}
-
-		/* set group key by index */
-		_rtw_memcpy(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial, key->KeyLength);
-
-		key->KeyIndex = key->KeyIndex & 0x03;
-
-		padapter->securitypriv.binstallGrpkey = _TRUE;
-
-		padapter->securitypriv.bcheck_grpkey = _FALSE;
-
-
-		res = rtw_set_key(padapter, &padapter->securitypriv, key->KeyIndex, 1, _TRUE);
-
-		if (res == _FAIL)
-			ret = _FAIL;
-
-		goto exit;
-
-	} else { /* Pairwise Key */
-		u8 res;
-
-		pbssid = get_bssid(&padapter->mlmepriv);
-		stainfo = rtw_get_stainfo(&padapter->stapriv , pbssid);
-
-		if (stainfo != NULL) {
-			_rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16); /* clear keybuffer */
-
-			_rtw_memcpy(&stainfo->dot118021x_UncstKey, key->KeyMaterial, 16);
-
-			if (encryptionalgo == _TKIP_) {
-				padapter->securitypriv.busetkipkey = _FALSE;
-
-				/* if TKIP, save the Receive/Transmit MIC key in KeyMaterial[128-255] */
-				if ((key->KeyIndex & 0x10000000)) {
-					_rtw_memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 16, 8);
-					_rtw_memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 24, 8);
-
-				} else {
-					_rtw_memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 24, 8);
-					_rtw_memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 16, 8);
-
-				}
-
-			} else if (encryptionalgo == _AES_) {
-
-			}
-
-
-			/* Set key to CAM through H2C command */
-#if 0
-			if (bgrouptkey) { /* never go to here */
-				res = rtw_setstakey_cmd(padapter, stainfo, GROUP_KEY, _TRUE);
-			} else {
-				res = rtw_setstakey_cmd(padapter, stainfo, UNICAST_KEY, _TRUE);
-			}
-#else
-
-			res = rtw_setstakey_cmd(padapter, stainfo, UNICAST_KEY, _TRUE);
-#endif
-
-			if (res == _FALSE)
-				ret = _FAIL;
-
-		}
-
-	}
-
-exit:
-
-
-	return ret;
-}
-
-u8 rtw_set_802_11_remove_key(_adapter	*padapter, NDIS_802_11_REMOVE_KEY *key)
-{
-
-	uint				encryptionalgo;
-	u8 *pbssid;
-	struct sta_info *stainfo;
-	u8	bgroup = (key->KeyIndex & 0x4000000) > 0 ? _FALSE : _TRUE;
-	u8	keyIndex = (u8)key->KeyIndex & 0x03;
-	u8	ret = _SUCCESS;
-
-
-	if ((key->KeyIndex & 0xbffffffc) > 0) {
-		ret = _FAIL;
-		goto exit;
-	}
-
-	if (bgroup == _TRUE) {
-		encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy;
-		/* clear group key by index */
-		/* NdisZeroMemory(Adapter->MgntInfo.SecurityInfo.KeyBuf[keyIndex], MAX_WEP_KEY_LEN); */
-		/* Adapter->MgntInfo.SecurityInfo.KeyLen[keyIndex] = 0; */
-
-		_rtw_memset(&padapter->securitypriv.dot118021XGrpKey[keyIndex], 0, 16);
-
-		/* ! \todo Send a H2C Command to Firmware for removing this Key in CAM Entry. */
-
-	} else {
-
-		pbssid = get_bssid(&padapter->mlmepriv);
-		stainfo = rtw_get_stainfo(&padapter->stapriv , pbssid);
-		if (stainfo != NULL) {
-			encryptionalgo = stainfo->dot118021XPrivacy;
-
-			/* clear key by BSSID */
-			_rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16);
-
-			/* ! \todo Send a H2C Command to Firmware for disable this Key in CAM Entry. */
-
-		} else {
-			ret = _FAIL;
-			goto exit;
-		}
-	}
-
-exit:
-
-
-	return _TRUE;
-
-}
-
 /*
 * rtw_get_cur_max_rate -
 * @adapter: pointer to _adapter structure
@@ -1122,10 +771,13 @@ exit:
 */
 u16 rtw_get_cur_max_rate(_adapter *adapter)
 {
+	int j;
 	int	i = 0;
 	u16	rate = 0, max_rate = 0;
 	struct mlme_priv	*pmlmepriv = &adapter->mlmepriv;
 	WLAN_BSSID_EX	*pcur_bss = &pmlmepriv->cur_network.network;
+	int	sta_bssrate_len = 0;
+	unsigned char	sta_bssrate[NumRates];
 	struct sta_info *psta = NULL;
 	u8	short_GI = 0;
 #ifdef CONFIG_80211N_HT
@@ -1147,34 +799,56 @@ u16 rtw_get_cur_max_rate(_adapter *adapter)
 	if (psta == NULL)
 		return 0;
 
-	short_GI = query_ra_short_GI(psta, psta->bw_mode);
+	short_GI = query_ra_short_GI(psta, rtw_get_tx_bw_mode(adapter, psta));
 
 #ifdef CONFIG_80211N_HT
 	if (is_supported_ht(psta->wireless_mode)) {
 		rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
 		max_rate = rtw_mcs_rate(rf_type
-			, (psta->bw_mode == CHANNEL_WIDTH_40) ? 1 : 0
+			, (psta->cmn.bw_mode == CHANNEL_WIDTH_40) ? 1 : 0
 			, short_GI
 			, psta->htpriv.ht_cap.supp_mcs_set
 		);
 	}
 #ifdef CONFIG_80211AC_VHT
 	else if (is_supported_vht(psta->wireless_mode))
-		max_rate = ((rtw_vht_mcs_to_data_rate(psta->bw_mode, short_GI, pmlmepriv->vhtpriv.vht_highest_rate) + 1) >> 1) * 10;
+		max_rate = ((rtw_vht_mcs_to_data_rate(psta->cmn.bw_mode, short_GI, pmlmepriv->vhtpriv.vht_highest_rate) + 1) >> 1) * 10;
 #endif /* CONFIG_80211AC_VHT */
 	else
 #endif /* CONFIG_80211N_HT */
 	{
+		/*station mode show :station && ap support rate; softap :show ap support rate*/	
+		if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)
+			get_rate_set(adapter, sta_bssrate, &sta_bssrate_len);/*get sta rate and length*/
+
+
 		while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) {
-			rate = pcur_bss->SupportedRates[i] & 0x7F;
-			if (rate > max_rate)
-				max_rate = rate;
+			rate = pcur_bss->SupportedRates[i] & 0x7F;/*AP support rates*/
+			/*RTW_INFO("%s rate=%02X \n", __func__, rate);*/
+
+			/*check STA  support rate or not */
+			if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) {
+				for (j = 0; j < sta_bssrate_len; j++) {
+					/* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */
+					if ((rate | IEEE80211_BASIC_RATE_MASK)
+					    == (sta_bssrate[j] | IEEE80211_BASIC_RATE_MASK)) {
+						if (rate > max_rate) {
+							max_rate = rate;
+						}
+						break;
+					}
+				}
+			} else {
+			
+				if (rate > max_rate)
+					max_rate = rate;
+
+			}
 			i++;
 		}
 
 		max_rate = max_rate * 10 / 2;
 	}
-
 	return max_rate;
 }
 
@@ -1204,9 +878,6 @@ int rtw_set_scan_mode(_adapter *adapter, RT_SCAN_TYPE scan_mode)
 */
 int rtw_set_channel_plan(_adapter *adapter, u8 channel_plan)
 {
-	struct registry_priv *pregistrypriv = &adapter->registrypriv;
-	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
-
 	/* handle by cmd_thread to sync with scan operation */
 	return rtw_set_chplan_cmd(adapter, RTW_CMDF_WAIT_ACK, channel_plan, 1);
 }
@@ -1223,7 +894,8 @@ int rtw_set_country(_adapter *adapter, const char *country_code)
 #ifdef CONFIG_RTW_IOCTL_SET_COUNTRY
 	return rtw_set_country_cmd(adapter, RTW_CMDF_WAIT_ACK, country_code, 1);
 #else
-	return _FAIL;
+	RTW_INFO("%s(): not applied\n", __func__);
+	return _SUCCESS;
 #endif
 }
 

+ 20 - 13
core/rtw_iol.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 
 #include <drv_types.h>
 
@@ -306,24 +301,36 @@ int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value)
 #ifdef DBG_IO
 int dbg_rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 1))
-		RTW_INFO("DBG_IO %s:%d IOL_WB(0x%04x, 0x%02x)\n", caller, line, addr, value);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(xmit_frame->padapter, addr, 1, value);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d IOL_WB(0x%04x, 0x%02x) %s\n"
+			, caller, line, addr, value, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_IOL_append_WB_cmd(xmit_frame, addr, value);
 }
 
 int dbg_rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 2))
-		RTW_INFO("DBG_IO %s:%d IOL_WW(0x%04x, 0x%04x)\n", caller, line, addr, value);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(xmit_frame->padapter, addr, 2, value);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d IOL_WW(0x%04x, 0x%04x) %s\n"
+			, caller, line, addr, value, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_IOL_append_WW_cmd(xmit_frame, addr, value);
 }
 
 int dbg_rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, const char *caller, const int line)
 {
-	if (match_write_sniff_ranges(addr, 4))
-		RTW_INFO("DBG_IO %s:%d IOL_WD(0x%04x, 0x%08x)\n", caller, line, addr, value);
+	const struct rtw_io_sniff_ent *ent = match_write_sniff(xmit_frame->padapter, addr, 4, value);
+
+	if (ent) {
+		RTW_INFO("DBG_IO %s:%d IOL_WD(0x%04x, 0x%08x) %s\n"
+			, caller, line, addr, value, rtw_io_sniff_ent_get_tag(ent));
+	}
 
 	return _rtw_IOL_append_WD_cmd(xmit_frame, addr, value);
 }

+ 14 - 0
core/rtw_mem.c

@@ -1,3 +1,17 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 
 #include <drv_types.h>
 #include <rtw_mem.h>

+ 412 - 149
core/rtw_mi.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2015 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_MI_C_
 
 #include <drv_types.h>
@@ -32,10 +27,88 @@ void rtw_mi_update_union_chan_inf(_adapter *adapter, u8 ch, u8 offset , u8 bw)
 	iface_state->union_offset = offset;
 }
 
-/* Find union about ch, bw, ch_offset of all linked/linking interfaces */
-int _rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset, bool include_self)
+#ifdef DBG_IFACE_STATUS
+#ifdef CONFIG_P2P
+static u8 _rtw_mi_p2p_listen_scan_chk(_adapter *adapter)
 {
+	int i;
+	_adapter *iface;
 	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	u8 p2p_listen_scan_state = _FALSE;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_LISTEN) ||
+			rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_SCAN)) {
+			p2p_listen_scan_state = _TRUE;
+			break;
+		}
+	}
+	return p2p_listen_scan_state;
+}
+#endif
+#endif
+
+u8 rtw_mi_stayin_union_ch_chk(_adapter *adapter)
+{
+	u8 rst = _TRUE;
+	u8 u_ch, u_bw, u_offset;
+	u8 o_ch, o_bw, o_offset;
+
+	u_ch = rtw_mi_get_union_chan(adapter);
+	u_bw = rtw_mi_get_union_bw(adapter);
+	u_offset = rtw_mi_get_union_offset(adapter);
+
+	o_ch = rtw_get_oper_ch(adapter);
+	o_bw = rtw_get_oper_bw(adapter);
+	o_offset = rtw_get_oper_choffset(adapter);
+
+	if ((u_ch != o_ch) || (u_bw != o_bw) || (u_offset != o_offset))
+		rst = _FALSE;
+
+	#ifdef DBG_IFACE_STATUS
+	if (rst == _FALSE) {
+		RTW_ERR("%s Not stay in union channel\n", __func__);
+		if (GET_HAL_DATA(adapter)->bScanInProcess == _TRUE)
+			RTW_ERR("ScanInProcess\n");
+		#ifdef CONFIG_P2P
+		if (_rtw_mi_p2p_listen_scan_chk(adapter))
+			RTW_ERR("P2P in listen or scan state\n");
+		#endif
+		RTW_ERR("union ch, bw, offset: %u,%u,%u\n", u_ch, u_bw, u_offset);
+		RTW_ERR("oper ch, bw, offset: %u,%u,%u\n", o_ch, o_bw, o_offset);
+		RTW_ERR("=========================\n");
+	}
+	#endif
+	return rst;
+}
+
+u8 rtw_mi_stayin_union_band_chk(_adapter *adapter)
+{
+	u8 rst = _TRUE;
+	u8 u_ch, o_ch;
+	u8 u_band, o_band;
+
+	u_ch = rtw_mi_get_union_chan(adapter);
+	o_ch = rtw_get_oper_ch(adapter);
+	u_band = (u_ch > 14) ? BAND_ON_5G : BAND_ON_2_4G;
+	o_band = (o_ch > 14) ? BAND_ON_5G : BAND_ON_2_4G;
+
+	if (u_ch != o_ch)
+		if(u_band != o_band)
+			rst = _FALSE;
+
+	#ifdef DBG_IFACE_STATUS
+	if (rst == _FALSE)
+		RTW_ERR("%s Not stay in union band\n", __func__);
+	#endif
+
+	return rst;
+}
+
+/* Find union about ch, bw, ch_offset of all linked/linking interfaces */
+int rtw_mi_get_ch_setting_union_by_ifbmp(struct dvobj_priv *dvobj, u8 ifbmp, u8 *ch, u8 *bw, u8 *offset)
+{
 	_adapter *iface;
 	struct mlme_ext_priv *mlmeext;
 	int i;
@@ -53,6 +126,9 @@ int _rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset,
 
 	for (i = 0; i < dvobj->iface_nums; i++) {
 		iface = dvobj->padapters[i];
+		if (!iface || !(ifbmp & BIT(iface->iface_id)))
+			continue;
+
 		mlmeext = &iface->mlmeextpriv;
 
 		if (!check_fwstate(&iface->mlmepriv, _FW_LINKED | _FW_UNDER_LINKING))
@@ -61,9 +137,6 @@ int _rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset,
 		if (check_fwstate(&iface->mlmepriv, WIFI_OP_CH_SWITCHING))
 			continue;
 
-		if (include_self == _FALSE && adapter == iface)
-			continue;
-
 		if (num == 0) {
 			ch_ret = mlmeext->cur_channel;
 			bw_ret = mlmeext->cur_bwmode;
@@ -102,18 +175,17 @@ int _rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset,
 
 inline int rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset)
 {
-	return _rtw_mi_get_ch_setting_union(adapter, ch, bw, offset, 1);
+	return rtw_mi_get_ch_setting_union_by_ifbmp(adapter_to_dvobj(adapter), 0xFF, ch, bw, offset);
 }
 
 inline int rtw_mi_get_ch_setting_union_no_self(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset)
 {
-	return _rtw_mi_get_ch_setting_union(adapter, ch, bw, offset, 0);
+	return rtw_mi_get_ch_setting_union_by_ifbmp(adapter_to_dvobj(adapter), 0xFF & ~BIT(adapter->iface_id), ch, bw, offset);
 }
 
 /* For now, not return union_ch/bw/offset */
-void _rtw_mi_status(_adapter *adapter, struct mi_state *mstate, bool include_self)
+void rtw_mi_status_by_ifbmp(struct dvobj_priv *dvobj, u8 ifbmp, struct mi_state *mstate)
 {
-	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
 	_adapter *iface;
 	int i;
 
@@ -121,24 +193,39 @@ void _rtw_mi_status(_adapter *adapter, struct mi_state *mstate, bool include_sel
 
 	for (i = 0; i < dvobj->iface_nums; i++) {
 		iface = dvobj->padapters[i];
-
-		if (include_self == _FALSE && iface == adapter)
+		if (!iface || !(ifbmp & BIT(iface->iface_id)))
 			continue;
 
 		if (check_fwstate(&iface->mlmepriv, WIFI_STATION_STATE) == _TRUE) {
 			MSTATE_STA_NUM(mstate)++;
-			if (check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE)
+			if (check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE) {
 				MSTATE_STA_LD_NUM(mstate)++;
 
+				#ifdef CONFIG_TDLS
+				if (iface->tdlsinfo.link_established == _TRUE)
+					MSTATE_TDLS_LD_NUM(mstate)++;
+				#endif
+				#ifdef CONFIG_P2P
+				if (MLME_IS_GC(iface))
+					MSTATE_P2P_GC_NUM(mstate)++;
+				#endif
+			}
 			if (check_fwstate(&iface->mlmepriv, _FW_UNDER_LINKING) == _TRUE)
 				MSTATE_STA_LG_NUM(mstate)++;
 
-		} else if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE) == _TRUE
-			&& check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE
-		) {
-			MSTATE_AP_NUM(mstate)++;
-			if (iface->stapriv.asoc_sta_count > 2)
-				MSTATE_AP_LD_NUM(mstate)++;
+#ifdef CONFIG_AP_MODE
+		} else if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE) == _TRUE ) {
+			if (check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE) {
+				MSTATE_AP_NUM(mstate)++;
+				if (iface->stapriv.asoc_sta_count > 2)
+					MSTATE_AP_LD_NUM(mstate)++;
+				#ifdef CONFIG_P2P
+				if (MLME_IS_GO(iface))
+					MSTATE_P2P_GO_NUM(mstate)++;
+				#endif
+			} else
+				MSTATE_AP_STARTING_NUM(mstate)++;
+#endif
 
 		} else if (check_fwstate(&iface->mlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE) == _TRUE
 			&& check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE
@@ -146,11 +233,29 @@ void _rtw_mi_status(_adapter *adapter, struct mi_state *mstate, bool include_sel
 			MSTATE_ADHOC_NUM(mstate)++;
 			if (iface->stapriv.asoc_sta_count > 2)
 				MSTATE_ADHOC_LD_NUM(mstate)++;
+
+#ifdef CONFIG_RTW_MESH
+		} else if (check_fwstate(&iface->mlmepriv, WIFI_MESH_STATE) == _TRUE
+			&& check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE
+		) {
+			MSTATE_MESH_NUM(mstate)++;
+			if (iface->stapriv.asoc_sta_count > 2)
+				MSTATE_MESH_LD_NUM(mstate)++;
+#endif
+
 		}
 
 		if (check_fwstate(&iface->mlmepriv, WIFI_UNDER_WPS) == _TRUE)
 			MSTATE_WPS_NUM(mstate)++;
 
+		if (check_fwstate(&iface->mlmepriv, WIFI_SITE_MONITOR) == _TRUE) {
+			MSTATE_SCAN_NUM(mstate)++;
+
+			if (mlmeext_scan_state(&iface->mlmeextpriv) != SCAN_DISABLE
+				&& mlmeext_scan_state(&iface->mlmeextpriv) != SCAN_BACK_OP)
+				MSTATE_SCAN_ENTER_NUM(mstate)++;
+		}
+
 #ifdef CONFIG_IOCTL_CFG80211
 		if (rtw_cfg80211_get_is_mgmt_tx(iface))
 			MSTATE_MGMT_TX_NUM(mstate)++;
@@ -159,38 +264,91 @@ void _rtw_mi_status(_adapter *adapter, struct mi_state *mstate, bool include_sel
 			MSTATE_ROCH_NUM(mstate)++;
 		#endif
 #endif /* CONFIG_IOCTL_CFG80211 */
-
+#ifdef CONFIG_P2P
+		if (MLME_IS_PD(iface))
+			MSTATE_P2P_DV_NUM(mstate)++;
+#endif
 	}
 }
 
 inline void rtw_mi_status(_adapter *adapter, struct mi_state *mstate)
 {
-	return _rtw_mi_status(adapter, mstate, 1);
+	return rtw_mi_status_by_ifbmp(adapter_to_dvobj(adapter), 0xFF, mstate);
 }
+
 inline void rtw_mi_status_no_self(_adapter *adapter, struct mi_state *mstate)
 {
-	return _rtw_mi_status(adapter, mstate, 0);
+	return rtw_mi_status_by_ifbmp(adapter_to_dvobj(adapter), 0xFF & ~BIT(adapter->iface_id), mstate);
 }
+
+inline void rtw_mi_status_no_others(_adapter *adapter, struct mi_state *mstate)
+{
+	return rtw_mi_status_by_ifbmp(adapter_to_dvobj(adapter), BIT(adapter->iface_id), mstate);
+}
+
+/* For now, not handle union_ch/bw/offset */
+inline void rtw_mi_status_merge(struct mi_state *d, struct mi_state *a)
+{
+	d->sta_num += a->sta_num;
+	d->ld_sta_num += a->ld_sta_num;
+	d->lg_sta_num += a->lg_sta_num;
+#ifdef CONFIG_TDLS
+	d->ld_tdls_num += a->ld_tdls_num;
+#endif
+#ifdef CONFIG_AP_MODE
+	d->ap_num += a->ap_num;
+	d->ld_ap_num += a->ld_ap_num;
+#endif
+	d->adhoc_num += a->adhoc_num;
+	d->ld_adhoc_num += a->ld_adhoc_num;
+#ifdef CONFIG_RTW_MESH
+	d->mesh_num += a->mesh_num;
+	d->ld_mesh_num += a->ld_mesh_num;
+#endif
+	d->scan_num += a->scan_num;
+	d->scan_enter_num += a->scan_enter_num;
+	d->uwps_num += a->uwps_num;
+#ifdef CONFIG_IOCTL_CFG80211
+	#ifdef CONFIG_P2P
+	d->roch_num += a->roch_num;
+	#endif
+	d->mgmt_tx_num += a->mgmt_tx_num;
+#endif
+}
+
 void dump_mi_status(void *sel, struct dvobj_priv *dvobj)
 {
 	RTW_PRINT_SEL(sel, "== dvobj-iface_state ==\n");
 	RTW_PRINT_SEL(sel, "sta_num:%d\n", DEV_STA_NUM(dvobj));
 	RTW_PRINT_SEL(sel, "linking_sta_num:%d\n", DEV_STA_LG_NUM(dvobj));
 	RTW_PRINT_SEL(sel, "linked_sta_num:%d\n", DEV_STA_LD_NUM(dvobj));
+#ifdef CONFIG_TDLS
+	RTW_PRINT_SEL(sel, "linked_tdls_num:%d\n", DEV_TDLS_LD_NUM(dvobj));
+#endif
+#ifdef CONFIG_AP_MODE
 	RTW_PRINT_SEL(sel, "ap_num:%d\n", DEV_AP_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "starting_ap_num:%d\n", DEV_AP_STARTING_NUM(dvobj));
 	RTW_PRINT_SEL(sel, "linked_ap_num:%d\n", DEV_AP_LD_NUM(dvobj));
+#endif
 	RTW_PRINT_SEL(sel, "adhoc_num:%d\n", DEV_ADHOC_NUM(dvobj));
 	RTW_PRINT_SEL(sel, "linked_adhoc_num:%d\n", DEV_ADHOC_LD_NUM(dvobj));
+#ifdef CONFIG_RTW_MESH
+	RTW_PRINT_SEL(sel, "mesh_num:%d\n", DEV_MESH_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "linked_mesh_num:%d\n", DEV_MESH_LD_NUM(dvobj));
+#endif
 #ifdef CONFIG_P2P
-	RTW_PRINT_SEL(sel, "p2p_device_num:%d\n", rtw_mi_stay_in_p2p_mode(dvobj->padapters[IFACE_ID0]));
+	RTW_PRINT_SEL(sel, "p2p_device_num:%d\n", DEV_P2P_DV_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "p2p_gc_num:%d\n", DEV_P2P_GC_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "p2p_go_num:%d\n", DEV_P2P_GO_NUM(dvobj));
 #endif
+	RTW_PRINT_SEL(sel, "scan_num:%d\n", DEV_SCAN_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "under_wps_num:%d\n", DEV_WPS_NUM(dvobj));
 #if defined(CONFIG_IOCTL_CFG80211)
 	#if defined(CONFIG_P2P)
 	RTW_PRINT_SEL(sel, "roch_num:%d\n", DEV_ROCH_NUM(dvobj));
 	#endif
 	RTW_PRINT_SEL(sel, "mgmt_tx_num:%d\n", DEV_MGMT_TX_NUM(dvobj));
 #endif
-	RTW_PRINT_SEL(sel, "under_wps_num:%d\n", DEV_WPS_NUM(dvobj));
 	RTW_PRINT_SEL(sel, "union_ch:%d\n", DEV_U_CH(dvobj));
 	RTW_PRINT_SEL(sel, "union_bw:%d\n", DEV_U_BW(dvobj));
 	RTW_PRINT_SEL(sel, "union_offset:%d\n", DEV_U_OFFSET(dvobj));
@@ -209,12 +367,9 @@ inline void rtw_mi_update_iface_status(struct mlme_priv *pmlmepriv, sint state)
 	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
 	struct mi_state *iface_state = &dvobj->iface_state;
 	struct mi_state tmp_mstate;
-	u8 i;
 	u8 u_ch, u_offset, u_bw;
-	_adapter *iface;
 
 	if (state == WIFI_MONITOR_STATE
-		|| state == WIFI_SITE_MONITOR
 		|| state == 0xFFFFFFFF
 	)
 		return;
@@ -252,11 +407,11 @@ u8 rtw_mi_check_status(_adapter *adapter, u8 type)
 
 	switch (type) {
 	case MI_LINKED:
-		if (MSTATE_STA_LD_NUM(iface_state) || MSTATE_AP_NUM(iface_state) || MSTATE_ADHOC_NUM(iface_state)) /*check_fwstate(&iface->mlmepriv, _FW_LINKED)*/
+		if (MSTATE_STA_LD_NUM(iface_state) || MSTATE_AP_NUM(iface_state) || MSTATE_ADHOC_NUM(iface_state) || MSTATE_MESH_NUM(iface_state)) /*check_fwstate(&iface->mlmepriv, _FW_LINKED)*/
 			ret = _TRUE;
 		break;
 	case MI_ASSOC:
-		if (MSTATE_STA_LD_NUM(iface_state) || MSTATE_AP_LD_NUM(iface_state) || MSTATE_ADHOC_LD_NUM(iface_state))
+		if (MSTATE_STA_LD_NUM(iface_state) || MSTATE_AP_LD_NUM(iface_state) || MSTATE_ADHOC_LD_NUM(iface_state) || MSTATE_MESH_LD_NUM(iface_state))
 			ret = _TRUE;
 		break;
 	case MI_UNDER_WPS:
@@ -282,6 +437,17 @@ u8 rtw_mi_check_status(_adapter *adapter, u8 type)
 			ret = _TRUE;
 		break;
 
+#ifdef CONFIG_RTW_MESH
+	case MI_MESH:
+		if (MSTATE_MESH_NUM(iface_state))
+			ret = _TRUE;
+		break;
+	case MI_MESH_ASSOC:
+		if (MSTATE_MESH_LD_NUM(iface_state))
+			ret = _TRUE;
+		break;
+#endif
+
 	case MI_STA_NOLINK: /* this is misleading, but not used now */
 		if (MSTATE_STA_NUM(iface_state) && (!(MSTATE_STA_LD_NUM(iface_state) || MSTATE_STA_LG_NUM(iface_state))))
 			ret = _TRUE;
@@ -301,28 +467,6 @@ u8 rtw_mi_check_status(_adapter *adapter, u8 type)
 	return ret;
 }
 
-u8 rtw_mi_mp_mode_check(_adapter *padapter)
-{
-#ifdef CONFIG_MP_INCLUDED
-#ifdef CONFIG_CONCURRENT_MODE
-	int i;
-	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
-	_adapter *iface = NULL;
-
-	for (i = 0; i < dvobj->iface_nums; i++) {
-		iface = dvobj->padapters[i];
-
-		if ((iface) && (iface->registrypriv.mp_mode == 1))
-			return _TRUE;
-	}
-#else
-	if (padapter->registrypriv.mp_mode == 1)
-		return _TRUE;
-#endif
-#endif /* CONFIG_MP_INCLUDED */
-	return _FALSE;
-}
-
 /*
 * return value : 0 is failed or have not interface meet condition
 * return value : !0 is success or interface numbers which meet condition
@@ -374,27 +518,54 @@ static u8 _rtw_mi_process_without_schk(_adapter *padapter, bool exclude_self,
 	return ret;
 }
 
-static u8 _rtw_mi_netif_stop_queue(_adapter *padapter, void *data)
+static u8 _rtw_mi_netif_caroff_qstop(_adapter *padapter, void *data)
 {
-	bool carrier_off = *(bool *)data;
 	struct net_device *pnetdev = padapter->pnetdev;
 
-	if (carrier_off)
-		netif_carrier_off(pnetdev);
+	rtw_netif_carrier_off(pnetdev);
 	rtw_netif_stop_queue(pnetdev);
 	return _TRUE;
 }
-u8 rtw_mi_netif_stop_queue(_adapter *padapter, bool carrier_off)
+u8 rtw_mi_netif_caroff_qstop(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_netif_caroff_qstop);
+}
+u8 rtw_mi_buddy_netif_caroff_qstop(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_caroff_qstop);
+}
+
+static u8 _rtw_mi_netif_caron_qstart(_adapter *padapter, void *data)
 {
-	bool in_data = carrier_off;
+	struct net_device *pnetdev = padapter->pnetdev;
 
-	return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_netif_stop_queue);
+	rtw_netif_carrier_on(pnetdev);
+	rtw_netif_start_queue(pnetdev);
+	return _TRUE;
+}
+u8 rtw_mi_netif_caron_qstart(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_netif_caron_qstart);
 }
-u8 rtw_mi_buddy_netif_stop_queue(_adapter *padapter, bool carrier_off)
+u8 rtw_mi_buddy_netif_caron_qstart(_adapter *padapter)
 {
-	bool in_data = carrier_off;
+	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_caron_qstart);
+}
+
+static u8 _rtw_mi_netif_stop_queue(_adapter *padapter, void *data)
+{
+	struct net_device *pnetdev = padapter->pnetdev;
 
-	return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_netif_stop_queue);
+	rtw_netif_stop_queue(pnetdev);
+	return _TRUE;
+}
+u8 rtw_mi_netif_stop_queue(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_netif_stop_queue);
+}
+u8 rtw_mi_buddy_netif_stop_queue(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_stop_queue);
 }
 
 static u8 _rtw_mi_netif_wake_queue(_adapter *padapter, void *data)
@@ -431,6 +602,23 @@ u8 rtw_mi_buddy_netif_carrier_on(_adapter *padapter)
 	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_carrier_on);
 }
 
+static u8 _rtw_mi_netif_carrier_off(_adapter *padapter, void *data)
+{
+	struct net_device *pnetdev = padapter->pnetdev;
+
+	if (pnetdev)
+		rtw_netif_carrier_off(pnetdev);
+	return _TRUE;
+}
+u8 rtw_mi_netif_carrier_off(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_netif_carrier_off);
+}
+u8 rtw_mi_buddy_netif_carrier_off(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_carrier_off);
+}
+
 static u8 _rtw_mi_scan_abort(_adapter *adapter, void *data)
 {
 	bool bwait = *(bool *)data;
@@ -456,32 +644,57 @@ void rtw_mi_buddy_scan_abort(_adapter *adapter, bool bwait)
 	_rtw_mi_process(adapter, _TRUE, &in_data, _rtw_mi_scan_abort);
 }
 
-static u8 _rtw_mi_start_drv_threads(_adapter *adapter, void *data)
+static u32 _rtw_mi_start_drv_threads(_adapter *adapter, bool exclude_self)
 {
-	rtw_start_drv_threads(adapter);
-	return _TRUE;
+	int i;
+	_adapter *iface = NULL;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	u32 _status = _SUCCESS;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (iface) {
+			if ((exclude_self) && (iface == adapter))
+				continue;
+			if (rtw_start_drv_threads(iface) == _FAIL) {
+				_status = _FAIL;
+				break;
+			}
+		}
+	}
+	return _status;
 }
-void rtw_mi_start_drv_threads(_adapter *adapter)
+u32 rtw_mi_start_drv_threads(_adapter *adapter)
 {
-	_rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_start_drv_threads);
+	return _rtw_mi_start_drv_threads(adapter, _FALSE);
 }
-void rtw_mi_buddy_start_drv_threads(_adapter *adapter)
+u32 rtw_mi_buddy_start_drv_threads(_adapter *adapter)
 {
-	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_start_drv_threads);
+	return _rtw_mi_start_drv_threads(adapter, _TRUE);
 }
 
-static u8 _rtw_mi_stop_drv_threads(_adapter *adapter, void *data)
+static void _rtw_mi_stop_drv_threads(_adapter *adapter, bool exclude_self)
 {
-	rtw_stop_drv_threads(adapter);
-	return _TRUE;
+	int i;
+	_adapter *iface = NULL;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (iface) {
+			if ((exclude_self) && (iface == adapter))
+				continue;
+			rtw_stop_drv_threads(iface);
+		}
+	}
 }
 void rtw_mi_stop_drv_threads(_adapter *adapter)
 {
-	_rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_stop_drv_threads);
+	_rtw_mi_stop_drv_threads(adapter, _FALSE);
 }
 void rtw_mi_buddy_stop_drv_threads(_adapter *adapter)
 {
-	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_stop_drv_threads);
+	_rtw_mi_stop_drv_threads(adapter, _TRUE);
 }
 
 static u8 _rtw_mi_cancel_all_timer(_adapter *adapter, void *data)
@@ -540,6 +753,30 @@ void rtw_mi_buddy_intf_stop(_adapter *adapter)
 	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_intf_stop);
 }
 
+#ifdef CONFIG_NEW_NETDEV_HDL
+static u8 _rtw_mi_hal_iface_init(_adapter *padapter, void *data)
+{
+	if (rtw_hal_iface_init(padapter) == _SUCCESS)
+		return _TRUE;
+	return _FALSE;
+}
+u8 rtw_mi_hal_iface_init(_adapter *padapter)
+{
+	int i;
+	_adapter *iface;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+
+	u8 ret = _TRUE;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (iface && iface->netif_up)
+			rtw_hal_iface_init(padapter);
+	}
+	return ret;
+}
+#endif
+
 static u8 _rtw_mi_suspend_free_assoc_resource(_adapter *padapter, void *data)
 {
 	return rtw_suspend_free_assoc_resource(padapter);
@@ -588,58 +825,14 @@ void rtw_mi_buddy_set_scan_deny(_adapter *adapter, u32 ms)
 
 	_rtw_mi_process(adapter, _TRUE, &in_data, _rtw_mi_set_scan_deny);
 }
-#endif
-
-struct nulldata_param {
-	unsigned char *da;
-	unsigned int power_mode;
-	int try_cnt;
-	int wait_ms;
-};
-
-static u8 _rtw_mi_issue_nulldata(_adapter *padapter, void *data)
-{
-	struct nulldata_param *pnulldata_param = (struct nulldata_param *)data;
-
-	if (is_client_associated_to_ap(padapter) == _TRUE) {
-		/* TODO: TDLS peers */
-		issue_nulldata(padapter, pnulldata_param->da, pnulldata_param->power_mode, pnulldata_param->try_cnt, pnulldata_param->wait_ms);
-		return _TRUE;
-	}
-	return _FALSE;
-}
-
-u8 rtw_mi_issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
-{
-	struct nulldata_param nparam;
-
-	nparam.da = da;
-	nparam.power_mode = power_mode;/*0 or 1*/
-	nparam.try_cnt = try_cnt;
-	nparam.wait_ms = wait_ms;
-
-	return _rtw_mi_process(padapter, _FALSE, &nparam, _rtw_mi_issue_nulldata);
-}
-u8 rtw_mi_buddy_issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
-{
-	struct nulldata_param nparam;
-
-	nparam.da = da;
-	nparam.power_mode = power_mode;
-	nparam.try_cnt = try_cnt;
-	nparam.wait_ms = wait_ms;
-
-	return _rtw_mi_process(padapter, _TRUE, &nparam, _rtw_mi_issue_nulldata);
-}
+#endif /*CONFIG_SET_SCAN_DENY_TIMER*/
 
 static u8 _rtw_mi_beacon_update(_adapter *padapter, void *data)
 {
-	struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv;
-
-	if (mlmeext_msr(mlmeext) == WIFI_FW_AP_STATE
+	if (!MLME_IS_STA(padapter)
 	    && check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _TRUE) {
-		RTW_INFO(ADPT_FMT"-WIFI_FW_AP_STATE - update_beacon\n", ADPT_ARG(padapter));
-		update_beacon(padapter, 0, NULL, _TRUE);
+		RTW_INFO(ADPT_FMT" - update_beacon\n", ADPT_ARG(padapter));
+		update_beacon(padapter, 0xFF, NULL, _TRUE);
 	}
 	return _TRUE;
 }
@@ -658,7 +851,7 @@ static u8 _rtw_mi_hal_dump_macaddr(_adapter *padapter, void *data)
 {
 	u8 mac_addr[ETH_ALEN] = {0};
 
-	rtw_hal_get_macaddr_port(padapter, mac_addr);
+	rtw_hal_get_hwreg(padapter, HW_VAR_MAC_ADDR, mac_addr);
 	RTW_INFO(ADPT_FMT"MAC Address ="MAC_FMT"\n", ADPT_ARG(padapter), MAC_ARG(mac_addr));
 	return _TRUE;
 }
@@ -925,20 +1118,6 @@ u8 rtw_mi_buddy_dynamic_check_timer_handlder(_adapter *padapter)
 	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_dynamic_check_timer_handlder);
 }
 
-static u8 _rtw_mi_dev_unload(_adapter *adapter, void *data)
-{
-	rtw_dev_unload(adapter);
-	return _TRUE;
-}
-u8 rtw_mi_dev_unload(_adapter *padapter)
-{
-	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_dev_unload);
-}
-u8 rtw_mi_buddy_dev_unload(_adapter *padapter)
-{
-	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_dev_unload);
-}
-
 static u8 _rtw_mi_dynamic_chk_wk_hdl(_adapter *adapter, void *data)
 {
 	rtw_iface_dynamic_chk_wk_hdl(adapter);
@@ -999,6 +1178,29 @@ u8 rtw_mi_sreset_adapter_hdl(_adapter *padapter, u8 bstart)
 
 	return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_sreset_adapter_hdl);
 }
+
+#if defined(DBG_CONFIG_ERROR_RESET) && defined(CONFIG_CONCURRENT_MODE)
+void rtw_mi_ap_info_restore(_adapter *adapter)
+{
+	int i;
+	_adapter *iface;
+	struct mlme_priv *pmlmepriv;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (iface) {
+			pmlmepriv = &iface->mlmepriv;
+
+			if (MLME_IS_AP(iface) || MLME_IS_MESH(iface)) {
+				RTW_INFO(FUNC_ADPT_FMT" %s\n", FUNC_ADPT_ARG(iface), MLME_IS_AP(iface) ? "AP" : "MESH");
+				rtw_iface_bcmc_sec_cam_map_restore(iface);
+			}
+		}
+	}
+}
+#endif /*#if defined(DBG_CONFIG_ERROR_RESET) && defined(CONFIG_CONCURRENT_MODE)*/
+
 u8 rtw_mi_buddy_sreset_adapter_hdl(_adapter *padapter, u8 bstart)
 {
 	u8 in_data = bstart;
@@ -1007,9 +1209,9 @@ u8 rtw_mi_buddy_sreset_adapter_hdl(_adapter *padapter, u8 bstart)
 }
 static u8 _rtw_mi_tx_beacon_hdl(_adapter *adapter, void *data)
 {
-	if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _TRUE
-	    && check_fwstate(&adapter->mlmepriv, WIFI_ASOC_STATE) == _TRUE
-	   ) {
+	if ((MLME_IS_AP(adapter) || MLME_IS_MESH(adapter))
+		&& check_fwstate(&adapter->mlmepriv, WIFI_ASOC_STATE) == _TRUE
+	) {
 		adapter->mlmepriv.update_bcn = _TRUE;
 #ifndef CONFIG_INTERRUPT_BASED_TXBCN
 #if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
@@ -1032,7 +1234,7 @@ static u8 _rtw_mi_set_tx_beacon_cmd(_adapter *adapter, void *data)
 {
 	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
 
-	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+	if (MLME_IS_AP(adapter) || MLME_IS_MESH(adapter)) {
 		if (pmlmepriv->update_bcn == _TRUE)
 			set_tx_beacon_cmd(adapter);
 	}
@@ -1098,7 +1300,7 @@ _adapter *rtw_get_iface_by_id(_adapter *padapter, u8 iface_id)
 	return  dvobj->padapters[iface_id];
 }
 
-_adapter *rtw_get_iface_by_macddr(_adapter *padapter, u8 *mac_addr)
+_adapter *rtw_get_iface_by_macddr(_adapter *padapter, const u8 *mac_addr)
 {
 	int i;
 	_adapter *iface = NULL;
@@ -1190,9 +1392,10 @@ void rtw_dbg_skb_process(_adapter *padapter, union recv_frame *precvframe, union
 static s32 _rtw_mi_buddy_clone_bcmc_packet(_adapter *adapter, union recv_frame *precvframe, u8 *pphy_status, union recv_frame *pcloneframe)
 {
 	s32 ret = _SUCCESS;
+#ifdef CONFIG_SKB_ALLOCATED
 	u8 *pbuf = precvframe->u.hdr.rx_data;
+#endif
 	struct rx_pkt_attrib *pattrib = NULL;
-	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(adapter);
 
 	if (pcloneframe) {
 		pcloneframe->u.hdr.adapter = adapter;
@@ -1218,7 +1421,7 @@ static s32 _rtw_mi_buddy_clone_bcmc_packet(_adapter *adapter, union recv_frame *
 			rtw_dbg_skb_process(adapter, precvframe, pcloneframe);
 #endif
 
-			if (pattrib->physt && pphy_status)
+			if (pphy_status)
 				rx_query_phy_status(pcloneframe, pphy_status);
 
 			ret = rtw_recv_entry(pcloneframe);
@@ -1240,6 +1443,8 @@ void rtw_mi_buddy_clone_bcmc_packet(_adapter *padapter, union recv_frame *precvf
 	struct recv_priv *precvpriv = &padapter->recvpriv;/*primary_padapter*/
 	_queue *pfree_recv_queue = &precvpriv->free_recv_queue;
 	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+	u8 *fhead = get_recvframe_data(precvframe);
+	u8 type = GetFrameType(fhead);
 
 	for (i = 0; i < dvobj->iface_nums; i++) {
 		iface = dvobj->padapters[i];
@@ -1247,6 +1452,8 @@ void rtw_mi_buddy_clone_bcmc_packet(_adapter *padapter, union recv_frame *precvf
 			continue;
 		if (rtw_is_adapter_up(iface) == _FALSE || iface->registered == 0)
 			continue;
+		if (type == WIFI_DATA_TYPE && !adapter_allow_bmc_data_rx(iface))
+			continue;
 
 		pcloneframe = rtw_alloc_recvframe(pfree_recv_queue);
 		if (pcloneframe) {
@@ -1283,6 +1490,45 @@ _adapter *rtw_mi_get_ap_adapter(_adapter *padapter)
 }
 #endif
 
+u8 rtw_mi_get_ld_sta_ifbmp(_adapter *adapter)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	int i;
+	_adapter *iface = NULL;
+	u8 ifbmp = 0;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (!iface)
+			continue;
+
+		if (MLME_IS_STA(iface) && MLME_IS_ASOC(iface))
+			ifbmp |= BIT(i);
+	}
+
+	return ifbmp;
+}
+
+u8 rtw_mi_get_ap_mesh_ifbmp(_adapter *adapter)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	int i;
+	_adapter *iface = NULL;
+	u8 ifbmp = 0;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (!iface)
+			continue;
+
+		if (CHK_MLME_STATE(iface, WIFI_AP_STATE | WIFI_MESH_STATE)
+			&& MLME_IS_ASOC(iface))
+			ifbmp |= BIT(i);
+	}
+
+	return ifbmp;
+}
+
 void rtw_mi_update_ap_bmc_camid(_adapter *padapter, u8 camid_a, u8 camid_b)
 {
 #ifdef CONFIG_CONCURRENT_MODE
@@ -1307,3 +1553,20 @@ void rtw_mi_update_ap_bmc_camid(_adapter *padapter, u8 camid_a, u8 camid_b)
 	}
 #endif
 }
+
+u8 rtw_mi_get_assoc_if_num(_adapter *adapter)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	u8 n_assoc_iface = 0;
+#if 1
+	u8 i;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		if (check_fwstate(&(dvobj->padapters[i]->mlmepriv), WIFI_ASOC_STATE))
+			n_assoc_iface++;
+	}
+#else
+	n_assoc_iface = DEV_STA_LD_NUM(dvobj) + DEV_AP_NUM(dvobj) + DEV_ADHOC_NUM(dvobj) + DEV_MESH_NUM(dvobj);
+#endif
+	return n_assoc_iface;
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 424 - 228
core/rtw_mlme.c


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 356 - 390
core/rtw_mlme_ext.c


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 474 - 181
core/rtw_mp.c


+ 2 - 7
core/rtw_mp_ioctl.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_MP_IOCTL_C_
 
 #include <drv_types.h>

+ 65 - 91
core/rtw_odm.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2013 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2017 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
@@ -11,23 +11,52 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 
 #include <rtw_odm.h>
 #include <hal_data.h>
 
+u32 rtw_phydm_ability_ops(_adapter *adapter, HAL_PHYDM_OPS ops, u32 ability)
+{
+	HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter);
+	struct dm_struct *podmpriv = &pHalData->odmpriv;
+	u32 result = 0;
 
+	switch (ops) {
+	case HAL_PHYDM_DIS_ALL_FUNC:
+		podmpriv->support_ability = DYNAMIC_FUNC_DISABLE;
+		halrf_cmn_info_set(podmpriv, HALRF_CMNINFO_ABILITY, DYNAMIC_FUNC_DISABLE);
+		break;
+	case HAL_PHYDM_FUNC_SET:
+		podmpriv->support_ability |= ability;
+		break;
+	case HAL_PHYDM_FUNC_CLR:
+		podmpriv->support_ability &= ~(ability);
+		break;
+	case HAL_PHYDM_ABILITY_BK:
+		/* dm flag backup*/
+		podmpriv->bk_support_ability = podmpriv->support_ability;
+		pHalData->bk_rf_ability = halrf_cmn_info_get(podmpriv, HALRF_CMNINFO_ABILITY);
+		break;
+	case HAL_PHYDM_ABILITY_RESTORE:
+		/* restore dm flag */
+		podmpriv->support_ability = podmpriv->bk_support_ability;
+		halrf_cmn_info_set(podmpriv, HALRF_CMNINFO_ABILITY, pHalData->bk_rf_ability);
+		break;
+	case HAL_PHYDM_ABILITY_SET:
+		podmpriv->support_ability = ability;
+		break;
+	case HAL_PHYDM_ABILITY_GET:
+		result = podmpriv->support_ability;
+		break;
+	}
+	return result;
+}
 
 /* set ODM_CMNINFO_IC_TYPE based on chip_type */
 void rtw_odm_init_ic_type(_adapter *adapter)
 {
-	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
-	struct PHY_DM_STRUCT *odm = &hal_data->odmpriv;
+	struct dm_struct *odm = adapter_to_phydm(adapter);
 	u4Byte ic_type = chip_type_to_odm_ic_type(rtw_get_chip_type(adapter));
 
 	rtw_warn_on(!ic_type);
@@ -35,20 +64,6 @@ void rtw_odm_init_ic_type(_adapter *adapter)
 	odm_cmn_info_init(odm, ODM_CMNINFO_IC_TYPE, ic_type);
 }
 
-inline void rtw_odm_set_force_igi_lb(_adapter *adapter, u8 lb)
-{
-	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
-
-	hal_data->u1ForcedIgiLb = lb;
-}
-
-inline u8 rtw_odm_get_force_igi_lb(_adapter *adapter)
-{
-	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
-
-	return hal_data->u1ForcedIgiLb;
-}
-
 void rtw_odm_adaptivity_ver_msg(void *sel, _adapter *adapter)
 {
 	RTW_PRINT_SEL(sel, "ADAPTIVITY_VERSION "ADAPTIVITY_VERSION"\n");
@@ -60,9 +75,6 @@ void rtw_odm_adaptivity_ver_msg(void *sel, _adapter *adapter)
 void rtw_odm_adaptivity_en_msg(void *sel, _adapter *adapter)
 {
 	struct registry_priv *regsty = &adapter->registrypriv;
-	struct mlme_priv *mlme = &adapter->mlmepriv;
-	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
-	struct PHY_DM_STRUCT *odm = &hal_data->odmpriv;
 
 	RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_EN_");
 
@@ -91,43 +103,16 @@ void rtw_odm_adaptivity_mode_msg(void *sel, _adapter *adapter)
 		_RTW_PRINT_SEL(sel, "INVALID\n");
 }
 
-#define RTW_ADAPTIVITY_DML_DISABLE 0
-#define RTW_ADAPTIVITY_DML_ENABLE 1
-
-void rtw_odm_adaptivity_dml_msg(void *sel, _adapter *adapter)
-{
-	struct registry_priv *regsty = &adapter->registrypriv;
-
-	RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_DML_");
-
-	if (regsty->adaptivity_dml == RTW_ADAPTIVITY_DML_DISABLE)
-		_RTW_PRINT_SEL(sel, "DISABLE\n");
-	else if (regsty->adaptivity_dml == RTW_ADAPTIVITY_DML_ENABLE)
-		_RTW_PRINT_SEL(sel, "ENABLE\n");
-	else
-		_RTW_PRINT_SEL(sel, "INVALID\n");
-}
-
-void rtw_odm_adaptivity_dc_backoff_msg(void *sel, _adapter *adapter)
-{
-	struct registry_priv *regsty = &adapter->registrypriv;
-
-	RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_DC_BACKOFF:%u\n", regsty->adaptivity_dc_backoff);
-}
-
 void rtw_odm_adaptivity_config_msg(void *sel, _adapter *adapter)
 {
 	rtw_odm_adaptivity_ver_msg(sel, adapter);
 	rtw_odm_adaptivity_en_msg(sel, adapter);
 	rtw_odm_adaptivity_mode_msg(sel, adapter);
-	rtw_odm_adaptivity_dml_msg(sel, adapter);
-	rtw_odm_adaptivity_dc_backoff_msg(sel, adapter);
 }
 
 bool rtw_odm_adaptivity_needed(_adapter *adapter)
 {
 	struct registry_priv *regsty = &adapter->registrypriv;
-	struct mlme_priv *mlme = &adapter->mlmepriv;
 	bool ret = _FALSE;
 
 	if (regsty->adaptivity_en == RTW_ADAPTIVITY_EN_ENABLE)
@@ -138,47 +123,32 @@ bool rtw_odm_adaptivity_needed(_adapter *adapter)
 
 void rtw_odm_adaptivity_parm_msg(void *sel, _adapter *adapter)
 {
-	HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter);
-	struct PHY_DM_STRUCT *odm = &pHalData->odmpriv;
+	struct dm_struct *odm = adapter_to_phydm(adapter);
 
 	rtw_odm_adaptivity_config_msg(sel, adapter);
 
-	RTW_PRINT_SEL(sel, "%10s %16s %16s %22s %12s\n"
-		, "th_l2h_ini", "th_edcca_hl_diff", "th_l2h_ini_mode2", "th_edcca_hl_diff_mode2", "edcca_enable");
-	RTW_PRINT_SEL(sel, "0x%-8x %-16d 0x%-14x %-22d %-12d\n"
+	RTW_PRINT_SEL(sel, "%10s %16s\n"
+		, "th_l2h_ini", "th_edcca_hl_diff");
+	RTW_PRINT_SEL(sel, "0x%-8x %-16d\n"
 		, (u8)odm->th_l2h_ini
 		, odm->th_edcca_hl_diff
-		, (u8)odm->th_l2h_ini_mode2
-		, odm->th_edcca_hl_diff_mode2
-		, odm->edcca_enable
-	);
-
-	RTW_PRINT_SEL(sel, "%15s %9s\n", "AdapEnableState", "Adap_Flag");
-	RTW_PRINT_SEL(sel, "%-15x %-9x\n"
-		, odm->adaptivity_enable
-		, odm->adaptivity_flag
 	);
 }
 
-void rtw_odm_adaptivity_parm_set(_adapter *adapter, s8 th_l2h_ini, s8 th_edcca_hl_diff, s8 th_l2h_ini_mode2, s8 th_edcca_hl_diff_mode2, u8 edcca_enable)
+void rtw_odm_adaptivity_parm_set(_adapter *adapter, s8 th_l2h_ini, s8 th_edcca_hl_diff)
 {
-	HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter);
-	struct PHY_DM_STRUCT *odm = &pHalData->odmpriv;
+	struct dm_struct *odm = adapter_to_phydm(adapter);
 
 	odm->th_l2h_ini = th_l2h_ini;
 	odm->th_edcca_hl_diff = th_edcca_hl_diff;
-	odm->th_l2h_ini_mode2 = th_l2h_ini_mode2;
-	odm->th_edcca_hl_diff_mode2 = th_edcca_hl_diff_mode2;
-	odm->edcca_enable = edcca_enable;
 }
 
 void rtw_odm_get_perpkt_rssi(void *sel, _adapter *adapter)
 {
-	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
-	struct PHY_DM_STRUCT *odm = &(hal_data->odmpriv);
+	struct dm_struct *odm = adapter_to_phydm(adapter);
 
-	RTW_PRINT_SEL(sel, "rx_rate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n",
-		      HDATA_RATE(odm->rx_rate), odm->RSSI_A, odm->RSSI_B);
+	RTW_PRINT_SEL(sel, "rx_rate = %s, rssi_a = %d(%%), rssi_b = %d(%%)\n",
+		      HDATA_RATE(odm->rx_rate), odm->rssi_a, odm->rssi_b);
 }
 
 
@@ -208,11 +178,10 @@ void rtw_odm_releasespinlock(_adapter *adapter,	enum rt_spinlock_type type)
 	}
 }
 
-inline u8 rtw_odm_get_dfs_domain(_adapter *adapter)
+inline u8 rtw_odm_get_dfs_domain(struct dvobj_priv *dvobj)
 {
 #ifdef CONFIG_DFS_MASTER
-	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
-	struct PHY_DM_STRUCT *pDM_Odm = &(hal_data->odmpriv);
+	struct dm_struct *pDM_Odm = dvobj_to_phydm(dvobj);
 
 	return pDM_Odm->dfs_region_domain;
 #else
@@ -220,10 +189,10 @@ inline u8 rtw_odm_get_dfs_domain(_adapter *adapter)
 #endif
 }
 
-inline u8 rtw_odm_dfs_domain_unknown(_adapter *adapter)
+inline u8 rtw_odm_dfs_domain_unknown(struct dvobj_priv *dvobj)
 {
 #ifdef CONFIG_DFS_MASTER
-	return rtw_odm_get_dfs_domain(adapter) == PHYDM_DFS_DOMAIN_UNKNOWN;
+	return rtw_odm_get_dfs_domain(dvobj) == PHYDM_DFS_DOMAIN_UNKNOWN;
 #else
 	return 1;
 #endif
@@ -232,23 +201,28 @@ inline u8 rtw_odm_dfs_domain_unknown(_adapter *adapter)
 #ifdef CONFIG_DFS_MASTER
 inline VOID rtw_odm_radar_detect_reset(_adapter *adapter)
 {
-	phydm_radar_detect_reset(GET_ODM(adapter));
+	phydm_radar_detect_reset(adapter_to_phydm(adapter));
 }
 
 inline VOID rtw_odm_radar_detect_disable(_adapter *adapter)
 {
-	phydm_radar_detect_disable(GET_ODM(adapter));
+	phydm_radar_detect_disable(adapter_to_phydm(adapter));
 }
 
 /* called after ch, bw is set */
 inline VOID rtw_odm_radar_detect_enable(_adapter *adapter)
 {
-	phydm_radar_detect_enable(GET_ODM(adapter));
+	phydm_radar_detect_enable(adapter_to_phydm(adapter));
 }
 
 inline BOOLEAN rtw_odm_radar_detect(_adapter *adapter)
 {
-	return phydm_radar_detect(GET_ODM(adapter));
+	return phydm_radar_detect(adapter_to_phydm(adapter));
+}
+
+inline u8 rtw_odm_radar_detect_polling_int_ms(struct dvobj_priv *dvobj)
+{
+	return phydm_dfs_polling_time(dvobj_to_phydm(dvobj));
 }
 #endif /* CONFIG_DFS_MASTER */
 
@@ -260,11 +234,11 @@ void rtw_odm_parse_rx_phy_status_chinfo(union recv_frame *rframe, u8 *phys)
 
 #if (ODM_PHY_STATUS_NEW_TYPE_SUPPORT == 1)
 	_adapter *adapter = rframe->u.hdr.adapter;
-	struct PHY_DM_STRUCT *phydm = GET_ODM(adapter);
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
 	struct rx_pkt_attrib *attrib = &rframe->u.hdr.attrib;
 	u8 *wlanhdr = get_recvframe_data(rframe);
 
-	if (phydm->support_ic_type & ODM_IC_PHY_STATUE_NEW_TYPE) {
+	if (phydm->support_ic_type & PHYSTS_2ND_TYPE_IC) {
 		/*
 		* 8723D:
 		* type_0(CCK)
@@ -293,7 +267,7 @@ void rtw_odm_parse_rx_phy_status_chinfo(union recv_frame *rframe, u8 *phys)
 		*/
 
 		if ((*phys & 0xf) == 0) {
-			struct _phy_status_rpt_jaguar2_type0 *phys_t0 = (struct _phy_status_rpt_jaguar2_type0 *)phys;
+			struct phy_status_rpt_jaguar2_type0 *phys_t0 = (struct phy_status_rpt_jaguar2_type0 *)phys;
 
 			if (DBG_RX_PHYSTATUS_CHINFO) {
 				RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, l_rxsc:%u)\n"
@@ -306,7 +280,7 @@ void rtw_odm_parse_rx_phy_status_chinfo(union recv_frame *rframe, u8 *phys)
 			}
 
 		} else if ((*phys & 0xf) == 1) {
-			struct _phy_status_rpt_jaguar2_type1 *phys_t1 = (struct _phy_status_rpt_jaguar2_type1 *)phys;
+			struct phy_status_rpt_jaguar2_type1 *phys_t1 = (struct phy_status_rpt_jaguar2_type1 *)phys;
 			u8 rxsc = (attrib->data_rate > DESC_RATE11M && attrib->data_rate < DESC_RATEMCS0) ? phys_t1->l_rxsc : phys_t1->ht_rxsc;
 			u8 pkt_cch = 0;
 			u8 pkt_bw = CHANNEL_WIDTH_20;
@@ -427,7 +401,7 @@ type1_end:
 				attrib->ch = pkt_cch;
 
 		} else {
-			struct _phy_status_rpt_jaguar2_type2 *phys_t2 = (struct _phy_status_rpt_jaguar2_type2 *)phys;
+			struct phy_status_rpt_jaguar2_type2 *phys_t2 = (struct phy_status_rpt_jaguar2_type2 *)phys;
 
 			if (DBG_RX_PHYSTATUS_CHINFO) {
 				RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, l_rxsc:%u, ht_rxsc:%u)\n"

+ 261 - 114
core/rtw_p2p.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_P2P_C_
 
 #include <drv_types.h>
@@ -85,7 +80,7 @@ static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf)
 			pcur += ETH_ALEN;
 
 			/* P2P interface address */
-			_rtw_memcpy(pcur, psta->hwaddr, ETH_ALEN);
+			_rtw_memcpy(pcur, psta->cmn.mac_addr, ETH_ALEN);
 			pcur += ETH_ALEN;
 
 			*pcur = psta->dev_cap;
@@ -295,7 +290,6 @@ static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8 *raddr,
 	unsigned short				*fctrl;
 	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
 	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
-	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 
 
 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
@@ -757,6 +751,7 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel
 	_adapter *padapter = pwdinfo->padapter;
 	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
 	struct wifi_display_info	*pwfd_info = padapter->wdinfo.wfd_info;
+	u16 v16 = 0;
 
 	if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
 		goto exit;
@@ -794,36 +789,43 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel
 			if (is_any_client_associated(pwdinfo->padapter)) {
 				if (pwdinfo->wfd_tdls_enable) {
 					/*	TDLS mode + WSD ( WFD Service Discovery ) */
-					RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT);
+					v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT;
+					RTW_PUT_BE16(wfdie + wfdielen, v16);
 				} else {
 					/*	WiFi Direct mode + WSD ( WFD Service Discovery ) */
-					RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT);
+					v16 =  pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT;
+					RTW_PUT_BE16(wfdie + wfdielen, v16);
 				}
 			} else {
 				if (pwdinfo->wfd_tdls_enable) {
 					/*	available for WFD session + TDLS mode + WSD ( WFD Service Discovery ) */
-					RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT);
+					v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT;
+					RTW_PUT_BE16(wfdie + wfdielen, v16);
 				} else {
 					/*	available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
-					RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT);
+					v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT;
+					RTW_PUT_BE16(wfdie + wfdielen, v16);
 				}
 			}
 		} else {
 			if (pwdinfo->wfd_tdls_enable) {
 				/*	available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
-				RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT);
+				v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT;
+				RTW_PUT_BE16(wfdie + wfdielen, v16);
 			} else {
-
 				/*	available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
-				RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT);
+				v16 =  pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT;
+				RTW_PUT_BE16(wfdie + wfdielen, v16);
 			}
 		}
 	} else {
-		if (pwdinfo->wfd_tdls_enable)
-			RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT);
-		else
-			RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT);
-
+		if (pwdinfo->wfd_tdls_enable) {
+			v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT;
+			RTW_PUT_BE16(wfdie + wfdielen, v16);
+		} else {
+			v16 =  pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT;
+			RTW_PUT_BE16(wfdie + wfdielen, v16);
+		}
 	}
 
 	wfdielen += 2;
@@ -2467,7 +2469,7 @@ u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint le
 
 							/* _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); */
 							/* issue GO Discoverability Request */
-							issue_group_disc_req(pwdinfo, psta->hwaddr);
+							issue_group_disc_req(pwdinfo, psta->cmn.mac_addr);
 							/* _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); */
 
 							status = P2P_STATUS_SUCCESS;
@@ -2571,14 +2573,15 @@ u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8
 	return ch_no;
 }
 
-u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned)
+u8 rtw_p2p_ch_inclusion(_adapter *adapter, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned)
 {
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
 	int	i = 0, j = 0, temp = 0;
 	u8 ch_no = 0;
 
 	for (i = 0; i < peer_ch_num; i++) {
-		for (j = temp; j < pmlmeext->max_chan_nums; j++) {
-			if (*(peer_ch_list + i) == pmlmeext->channel_set[j].ChannelNum) {
+		for (j = temp; j < rfctl->max_chan_nums; j++) {
+			if (*(peer_ch_list + i) == rfctl->channel_set[j].ChannelNum) {
 				ch_list_inclusioned[ch_no++] = *(peer_ch_list + i);
 				temp = j;
 				break;
@@ -2703,7 +2706,7 @@ u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, u8 *pframe,
 
 		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) {
 			peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list);
-			ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned);
+			ch_num_inclusioned = rtw_p2p_ch_inclusion(padapter, peer_ch_list, peer_ch_num, ch_list_inclusioned);
 
 			if (ch_num_inclusioned == 0) {
 				RTW_INFO("[%s] No common channel in channel list!\n", __FUNCTION__);
@@ -2803,8 +2806,6 @@ u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe
 		u8	attr_content = 0x00;
 		u32	attr_contentlen = 0;
 		u8	operatingch_info[5] = { 0x00 };
-		uint	ch_cnt = 0;
-		u8	ch_content[100] = { 0x00 };
 		u8	groupid[38];
 		u16	cap_attr;
 		u8	peer_ch_list[100] = { 0x00 };
@@ -2898,7 +2899,7 @@ u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe
 				RTW_INFO("[%s] channel list attribute found, len = %d\n", __FUNCTION__,  pwdinfo->channel_list_attr_len);
 
 				peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list);
-				ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned);
+				ch_num_inclusioned = rtw_p2p_ch_inclusion(padapter, peer_ch_list, peer_ch_num, ch_list_inclusioned);
 
 				if (ch_num_inclusioned == 0) {
 					RTW_INFO("[%s] No common channel in channel list!\n", __FUNCTION__);
@@ -2970,7 +2971,9 @@ u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe
 
 u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
 {
+#ifdef CONFIG_CONCURRENT_MODE
 	_adapter *padapter = pwdinfo->padapter;
+#endif
 	u8 *ies;
 	u32 ies_len;
 	u8 *p2p_ie;
@@ -3069,19 +3072,20 @@ void find_phase_handler(_adapter	*padapter)
 {
 	struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
 	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
-	NDIS_802_11_SSID	ssid;
+	struct sitesurvey_parm parm;
 	_irqL				irqL;
 	u8					_status = 0;
 
 
-	_rtw_memset((unsigned char *)&ssid, 0, sizeof(NDIS_802_11_SSID));
-	_rtw_memcpy(ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
-	ssid.SsidLength = P2P_WILDCARD_SSID_LEN;
+	rtw_init_sitesurvey_parm(padapter, &parm);
+	_rtw_memcpy(&parm.ssid[0].Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
+	parm.ssid[0].SsidLength = P2P_WILDCARD_SSID_LEN;
+	parm.ssid_num = 1;
 
 	rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
 
 	_enter_critical_bh(&pmlmepriv->lock, &irqL);
-	_status = rtw_sitesurvey_cmd(padapter, &ssid, 1, NULL, 0);
+	_status = rtw_sitesurvey_cmd(padapter, &parm);
 	_exit_critical_bh(&pmlmepriv->lock, &irqL);
 
 
@@ -3092,8 +3096,6 @@ void p2p_concurrent_handler(_adapter *padapter);
 void restore_p2p_state_handler(_adapter	*padapter)
 {
 	struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
-	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
-
 
 	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
 		rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
@@ -3106,7 +3108,7 @@ void restore_p2p_state_handler(_adapter	*padapter)
 
 		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP)) {
 			set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
-			rtw_mi_buddy_issue_nulldata(padapter, NULL, 0, 3, 500);
+			rtw_back_opch(padapter);
 		}
 	}
 #endif
@@ -3170,6 +3172,12 @@ void p2p_concurrent_handler(_adapter	*padapter)
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 	u8					val8;
 
+#ifdef CONFIG_IOCTL_CFG80211
+	if (pwdinfo->driver_interface == DRIVER_CFG80211
+		&& !rtw_cfg80211_get_is_roch(padapter))
+		return;
+#endif
+
 	if (rtw_mi_check_status(padapter, MI_LINKED)) {
 		u8 union_ch = rtw_mi_get_union_chan(padapter);
 		u8 union_bw = rtw_mi_get_union_bw(padapter);
@@ -3178,10 +3186,10 @@ void p2p_concurrent_handler(_adapter	*padapter)
 		pwdinfo->operating_channel = union_ch;
 
 		if (pwdinfo->driver_interface == DRIVER_CFG80211) {
-			RTW_INFO("%s, switch ch back to union_ch=%d\n", __func__, union_ch);
+			RTW_INFO("%s, switch ch back to union=%u,%u, %u\n"
+				, __func__, union_ch, union_bw, union_offset);
 			set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
-
-			rtw_mi_buddy_issue_nulldata(padapter, NULL, 0, 3, 500);
+			rtw_back_opch(padapter);
 
 		} else if (pwdinfo->driver_interface == DRIVER_WEXT) {
 			if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
@@ -3191,8 +3199,7 @@ void p2p_concurrent_handler(_adapter	*padapter)
 					RTW_INFO("[%s] P2P_STATE_IDLE, ext_listen_period = %d\n", __FUNCTION__, pwdinfo->ext_listen_period);
 
 					if (union_ch != pwdinfo->listen_channel) {
-						/*	Will switch to listen channel so that need to send the NULL data with PW bit to AP. */
-						rtw_mi_buddy_issue_nulldata(padapter, NULL, 1, 3, 500);
+						rtw_leave_opch(padapter);
 						set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
 					}
 
@@ -3205,6 +3212,7 @@ void p2p_concurrent_handler(_adapter	*padapter)
 					/*	Todo: To check the value of pwdinfo->ext_listen_period is equal to 0 or not. */
 					_set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_period);
 				}
+
 			} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN) ||
 				rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL) ||
 				(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _FALSE) ||
@@ -3224,17 +3232,19 @@ void p2p_concurrent_handler(_adapter	*padapter)
 						rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
 					}
 					rtw_p2p_set_state(pwdinfo, P2P_STATE_IDLE);
-					rtw_mi_buddy_issue_nulldata(padapter, NULL, 0, 3, 500);
+					rtw_back_opch(padapter);
 				}
 
 				/*	Todo: To check the value of pwdinfo->ext_listen_interval is equal to 0 or not. */
 				_set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_interval);
+
 			} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK)) {
 				/*	The driver had finished the P2P handshake successfully. */
 				val8 = 0;
 				rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
 				set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
-				rtw_mi_buddy_issue_nulldata(padapter, NULL, 0, 3, 500);
+				rtw_back_opch(padapter);
+
 			} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
 				val8 = 1;
 				set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
@@ -3269,10 +3279,136 @@ void p2p_concurrent_handler(_adapter	*padapter)
 #endif
 
 #ifdef CONFIG_IOCTL_CFG80211
+u8 roch_stay_in_cur_chan(_adapter *padapter)
+{
+	int i;
+	_adapter *iface;
+	struct mlme_priv *pmlmepriv;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+	u8 rst = _FALSE;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (iface) {
+			pmlmepriv = &iface->mlmepriv;
+
+			if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS | WIFI_UNDER_KEY_HANDSHAKE) == _TRUE) {
+				RTW_INFO(ADPT_FMT"- _FW_UNDER_LINKING |WIFI_UNDER_WPS | WIFI_UNDER_KEY_HANDSHAKE (mlme state:0x%x)\n",
+						ADPT_ARG(iface), get_fwstate(&iface->mlmepriv));
+				rst = _TRUE;
+				break;
+			}
+			#ifdef CONFIG_AP_MODE
+			if (MLME_IS_AP(iface) || MLME_IS_MESH(iface)) {
+				if (rtw_ap_sta_states_check(iface) == _TRUE) {
+					rst = _TRUE;
+					break;
+				}
+			}
+			#endif
+		}
+	}
+
+	return rst;
+}
+
 static int ro_ch_handler(_adapter *adapter, u8 *buf)
 {
-	/* TODO: move remain on channel logical here */
-	return H2C_SUCCESS;
+	int ret = H2C_SUCCESS;
+	struct p2p_roch_parm *roch_parm = (struct p2p_roch_parm *)buf;
+	struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
+	struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &adapter->cfg80211_wdinfo;
+#ifdef CONFIG_CONCURRENT_MODE
+	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+#ifdef RTW_ROCH_BACK_OP
+	struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+#endif
+#endif
+	u8 ready_on_channel = _FALSE;
+	u8 remain_ch;
+	unsigned int duration;
+
+	_enter_critical_mutex(&pwdev_priv->roch_mutex, NULL);
+
+	if (rtw_cfg80211_get_is_roch(adapter) != _TRUE)
+		goto exit;
+
+	remain_ch = (u8)ieee80211_frequency_to_channel(roch_parm->ch.center_freq);
+	duration = roch_parm->duration;
+
+	RTW_INFO(FUNC_ADPT_FMT" ch:%u duration:%d, cookie:0x%llx\n"
+		, FUNC_ADPT_ARG(adapter), remain_ch, roch_parm->duration, roch_parm->cookie);
+
+	if (roch_parm->wdev && roch_parm->cookie) {
+		if (pcfg80211_wdinfo->ro_ch_wdev != roch_parm->wdev) {
+			RTW_WARN(FUNC_ADPT_FMT" ongoing wdev:%p, wdev:%p\n"
+				, FUNC_ADPT_ARG(adapter), pcfg80211_wdinfo->ro_ch_wdev, roch_parm->wdev);
+			rtw_warn_on(1);
+		}
+
+		if (pcfg80211_wdinfo->remain_on_ch_cookie != roch_parm->cookie) {
+			RTW_WARN(FUNC_ADPT_FMT" ongoing cookie:0x%llx, cookie:0x%llx\n"
+				, FUNC_ADPT_ARG(adapter), pcfg80211_wdinfo->remain_on_ch_cookie, roch_parm->cookie);
+			rtw_warn_on(1);
+		}
+	}
+
+	if (roch_stay_in_cur_chan(adapter) == _TRUE) {
+		remain_ch = rtw_mi_get_union_chan(adapter);
+		RTW_INFO(FUNC_ADPT_FMT" stay in union ch:%d\n", FUNC_ADPT_ARG(adapter), remain_ch);
+	}
+
+	#ifdef CONFIG_CONCURRENT_MODE
+	if (rtw_mi_check_status(adapter, MI_LINKED) && (0 != rtw_mi_get_union_chan(adapter))) {
+		if ((remain_ch != rtw_mi_get_union_chan(adapter)) && !check_fwstate(&adapter->mlmepriv, _FW_LINKED)) {
+			if (remain_ch != pmlmeext->cur_channel
+				#ifdef RTW_ROCH_BACK_OP
+				|| ATOMIC_READ(&pwdev_priv->switch_ch_to) == 1
+				#endif
+			) {
+				rtw_leave_opch(adapter);
+
+				#ifdef RTW_ROCH_BACK_OP
+				RTW_INFO("%s, set switch ch timer, duration=%d\n", __func__, duration - pwdinfo->ext_listen_interval);
+				ATOMIC_SET(&pwdev_priv->switch_ch_to, 0);
+				_set_timer(&pwdinfo->ap_p2p_switch_timer, duration - pwdinfo->ext_listen_interval);
+				#endif
+			}
+		}
+		ready_on_channel = _TRUE;
+	} else
+	#endif /* CONFIG_CONCURRENT_MODE */
+	{
+		if (remain_ch != rtw_get_oper_ch(adapter))
+			ready_on_channel = _TRUE;
+	}
+
+	if (ready_on_channel == _TRUE) {
+		#ifndef RTW_SINGLE_WIPHY
+		if (!check_fwstate(&adapter->mlmepriv, _FW_LINKED))
+		#endif
+		{
+			#ifdef CONFIG_CONCURRENT_MODE
+			if (rtw_get_oper_ch(adapter) != remain_ch)
+			#endif
+			{
+				/* if (!padapter->mlmepriv.LinkDetectInfo.bBusyTraffic) */
+				set_channel_bwmode(adapter, remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+			}
+		}
+	}
+
+	#ifdef CONFIG_BT_COEXIST
+	rtw_btcoex_ScanNotify(adapter, _TRUE);
+	#endif
+
+	RTW_INFO("%s, set ro ch timer, duration=%d\n", __func__, duration);
+	_set_timer(&pcfg80211_wdinfo->remain_on_ch_timer, duration);
+
+exit:
+	_exit_critical_mutex(&pwdev_priv->roch_mutex, NULL);
+
+	return ret;
 }
 
 static int cancel_ro_ch_handler(_adapter *padapter, u8 *buf)
@@ -3304,6 +3440,11 @@ static int cancel_ro_ch_handler(_adapter *padapter, u8 *buf)
 		}
 	}
 
+#if defined(RTW_ROCH_BACK_OP) && defined(CONFIG_CONCURRENT_MODE)
+	_cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer);
+	ATOMIC_SET(&pwdev_priv->switch_ch_to, 1);
+#endif
+
 	if (rtw_mi_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) {
 		if (0)
 			RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n",
@@ -3325,6 +3466,7 @@ static int cancel_ro_ch_handler(_adapter *padapter, u8 *buf)
 	}
 
 	set_channel_bwmode(padapter, ch, offset, bw);
+	rtw_back_opch(padapter);
 
 	rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
 #ifdef CONFIG_DEBUG_CFG80211
@@ -3335,7 +3477,7 @@ static int cancel_ro_ch_handler(_adapter *padapter, u8 *buf)
 
 	rtw_cfg80211_set_is_roch(padapter, _FALSE);
 	pcfg80211_wdinfo->ro_ch_wdev = NULL;
-	pcfg80211_wdinfo->last_ro_ch_time = rtw_get_current_time();
+	rtw_cfg80211_set_last_ro_ch_time(padapter);
 
 	rtw_cfg80211_remain_on_channel_expired(wdev
 		, pcfg80211_wdinfo->remain_on_ch_cookie
@@ -3355,14 +3497,14 @@ exit:
 	return ret;
 }
 
-static void ro_ch_timer_process(struct timer_list *t)
+static void ro_ch_timer_process(void *FunctionContext)
 {
-	struct cfg80211_wifidirect_info *pcfg80211_wdinfo = from_timer(pcfg80211_wdinfo, t, remain_on_ch_timer);
-	_adapter *adapter = container_of(pcfg80211_wdinfo, _adapter, cfg80211_wdinfo);
+	_adapter *adapter = (_adapter *)FunctionContext;
 
 	p2p_cancel_roch_cmd(adapter, 0, NULL, 0);
 }
 
+#if 0
 static void rtw_change_p2pie_op_ch(_adapter *padapter, const u8 *frame_body, u32 len, u8 ch)
 {
 	u8 *ies, *p2p_ie;
@@ -3393,7 +3535,9 @@ static void rtw_change_p2pie_op_ch(_adapter *padapter, const u8 *frame_body, u32
 		p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
 	}
 }
+#endif
 
+#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
 static void rtw_change_p2pie_ch_list(_adapter *padapter, const u8 *frame_body, u32 len, u8 ch)
 {
 	u8 *ies, *p2p_ie;
@@ -3437,11 +3581,12 @@ static void rtw_change_p2pie_ch_list(_adapter *padapter, const u8 *frame_body, u
 		p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
 	}
 }
+#endif
 
+#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
 static bool rtw_chk_p2pie_ch_list_with_buddy(_adapter *padapter, const u8 *frame_body, u32 len)
 {
 	bool fit = _FALSE;
-#ifdef CONFIG_CONCURRENT_MODE
 	u8 *ies, *p2p_ie;
 	u32 ies_len, p2p_ielen;
 	u8 union_ch = rtw_mi_get_union_chan(padapter);
@@ -3483,14 +3628,14 @@ static bool rtw_chk_p2pie_ch_list_with_buddy(_adapter *padapter, const u8 *frame
 		/* Get the next P2P IE */
 		p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
 	}
-#endif
+
 	return fit;
 }
 
+#if defined(CONFIG_P2P_INVITE_IOT)
 static bool rtw_chk_p2pie_op_ch_with_buddy(_adapter *padapter, const u8 *frame_body, u32 len)
 {
 	bool fit = _FALSE;
-#ifdef CONFIG_CONCURRENT_MODE
 	u8 *ies, *p2p_ie;
 	u32 ies_len, p2p_ielen;
 	u8 union_ch = rtw_mi_get_union_chan(padapter);
@@ -3519,13 +3664,13 @@ static bool rtw_chk_p2pie_op_ch_with_buddy(_adapter *padapter, const u8 *frame_b
 		/* Get the next P2P IE */
 		p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
 	}
-#endif
+
 	return fit;
 }
+#endif
 
 static void rtw_cfg80211_adjust_p2pie_channel(_adapter *padapter, const u8 *frame_body, u32 len)
 {
-#ifdef CONFIG_CONCURRENT_MODE
 	u8 *ies, *p2p_ie;
 	u32 ies_len, p2p_ielen;
 	u8 union_ch = rtw_mi_get_union_chan(padapter);
@@ -3588,8 +3733,8 @@ static void rtw_cfg80211_adjust_p2pie_channel(_adapter *padapter, const u8 *fram
 
 	}
 
-#endif
 }
+#endif
 
 #ifdef CONFIG_WFD
 u32 rtw_xframe_build_wfd_ie(struct xmit_frame *xframe)
@@ -3673,8 +3818,6 @@ u32 rtw_xframe_build_wfd_ie(struct xmit_frame *xframe)
 bool rtw_xframe_del_wfd_ie(struct xmit_frame *xframe)
 {
 #define DBG_XFRAME_DEL_WFD_IE 0
-
-	_adapter *adapter = xframe->padapter;
 	u8 *frame = xframe->buf_addr + TXDESC_OFFSET;
 	u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr);
 	u8 *frame_tail = frame + xframe->attrib.pktlen;
@@ -3721,12 +3864,9 @@ bool rtw_xframe_del_wfd_ie(struct xmit_frame *xframe)
 void rtw_xframe_chk_wfd_ie(struct xmit_frame *xframe)
 {
 	_adapter *adapter = xframe->padapter;
-	u8 *frame = xframe->buf_addr + TXDESC_OFFSET;
-	u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr);
-	u8 *frame_tail = frame + xframe->attrib.pktlen;
-
+#ifdef CONFIG_IOCTL_CFG80211
 	struct wifidirect_info *wdinfo = &adapter->wdinfo;
-	struct mlme_priv *mlme = &adapter->mlmepriv;
+#endif
 	u8 build = 0;
 	u8 del = 0;
 
@@ -3734,7 +3874,7 @@ void rtw_xframe_chk_wfd_ie(struct xmit_frame *xframe)
 		del = 1;
 
 #ifdef CONFIG_IOCTL_CFG80211
-	if (_TRUE == wdinfo->wfd_info->wfd_enable)
+	if (wdinfo->wfd_info->wfd_enable == _TRUE)
 #endif
 		del = build = 1;
 
@@ -3754,7 +3894,6 @@ u8 *dump_p2p_attr_ch_list(u8 *p2p_ie, uint p2p_ielen, u8 *buf, u32 buf_len)
 	int w_sz = 0;
 	u8 ch_cnt = 0;
 	u8 ch_list[40];
-	bool continuous = _FALSE;
 
 	pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, &attr_contentlen);
 	if (pattr != NULL) {
@@ -4057,10 +4196,13 @@ int rtw_p2p_check_frames(_adapter *padapter, const u8 *buf, u32 len, u8 tx)
 				if (!tx) {
 					#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
 					if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) {
+						#if defined(CONFIG_P2P_INVITE_IOT)
 						if (op_ch != -1 && rtw_chk_p2pie_op_ch_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) {
 							RTW_INFO(FUNC_ADPT_FMT" op_ch:%u has no intersect with buddy\n", FUNC_ADPT_ARG(padapter), op_ch);
 							rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0);
-						} else if (rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) {
+						} else
+						#endif
+						if (rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) {
 							RTW_INFO(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter));
 							rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0);
 						}
@@ -4176,24 +4318,23 @@ int rtw_p2p_check_frames(_adapter *padapter, const u8 *buf, u32 len, u8 tx)
 
 		switch (OUI_Subtype) {
 		case P2P_NOTICE_OF_ABSENCE:
-			RTW_INFO("RTW_%s:P2P_NOTICE_OF_ABSENCE, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", dialogToken);
+			RTW_INFO("RTW_%s:P2P_NOTICE_OF_ABSENCE, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
 			break;
 		case P2P_PRESENCE_REQUEST:
-			RTW_INFO("RTW_%s:P2P_PRESENCE_REQUEST, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", dialogToken);
+			RTW_INFO("RTW_%s:P2P_PRESENCE_REQUEST, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
 			break;
 		case P2P_PRESENCE_RESPONSE:
-			RTW_INFO("RTW_%s:P2P_PRESENCE_RESPONSE, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", dialogToken);
+			RTW_INFO("RTW_%s:P2P_PRESENCE_RESPONSE, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
 			break;
 		case P2P_GO_DISC_REQUEST:
-			RTW_INFO("RTW_%s:P2P_GO_DISC_REQUEST, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", dialogToken);
+			RTW_INFO("RTW_%s:P2P_GO_DISC_REQUEST, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
 			break;
 		default:
-			RTW_INFO("RTW_%s:OUI_Subtype=%d, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", OUI_Subtype, dialogToken);
+			RTW_INFO("RTW_%s:OUI_Subtype=%d, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", OUI_Subtype, dialogToken);
 			break;
 		}
 
-	} else
-		RTW_INFO("RTW_%s:action frame category=%d\n", (tx == _TRUE) ? "TX" : "RX", category);
+	}
 
 	return is_p2p_frame;
 }
@@ -4204,14 +4345,13 @@ void rtw_init_cfg80211_wifidirect_info(_adapter	*padapter)
 
 	_rtw_memset(pcfg80211_wdinfo, 0x00, sizeof(struct cfg80211_wifidirect_info));
 
-	rtw_init_timer(&pcfg80211_wdinfo->remain_on_ch_timer, padapter, ro_ch_timer_process);
+	rtw_init_timer(&pcfg80211_wdinfo->remain_on_ch_timer, padapter, ro_ch_timer_process, padapter);
 }
 #endif /* CONFIG_IOCTL_CFG80211	 */
 
 s32 p2p_protocol_wk_hdl(_adapter *padapter, int intCmdType, u8 *buf)
 {
 	int ret = H2C_SUCCESS;
-	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
 
 	switch (intCmdType) {
 	case P2P_FIND_PHASE_WK:
@@ -4288,7 +4428,6 @@ int process_p2p_cross_connect_ie(PADAPTER padapter, u8 *IEs, u32 IELength)
 	u8	p2p_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */
 	u32	attr_contentlen = 0;
 
-	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
 
 
 	if (IELength <= _BEACON_IE_OFFSET_)
@@ -4411,7 +4550,7 @@ void p2p_ps_wk_hdl(_adapter *padapter, u8 p2p_ps_state)
 {
 	struct pwrctrl_priv		*pwrpriv = adapter_to_pwrctl(padapter);
 	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
-
+	u32 ps_deny = 0;
 
 	/* Pre action for p2p state */
 	switch (p2p_ps_state) {
@@ -4433,6 +4572,16 @@ void p2p_ps_wk_hdl(_adapter *padapter, u8 p2p_ps_state)
 		}
 		break;
 	case P2P_PS_ENABLE:
+		_enter_pwrlock(&adapter_to_pwrctl(padapter)->lock);
+		ps_deny = rtw_ps_deny_get(padapter);
+		_exit_pwrlock(&adapter_to_pwrctl(padapter)->lock);
+
+		if ((ps_deny & (PS_DENY_SCAN | PS_DENY_JOIN))
+			|| rtw_mi_check_fwstate(padapter, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING))) {
+			pwdinfo->p2p_ps_mode = P2P_PS_NONE;
+			RTW_DBG(FUNC_ADPT_FMT" Block P2P PS under site survey or LINKING\n", FUNC_ADPT_ARG(padapter));
+			return;
+		}
 		if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
 #ifdef CONFIG_MCC_MODE
 			if (MCC_EN(padapter)) {
@@ -4467,6 +4616,9 @@ void p2p_ps_wk_hdl(_adapter *padapter, u8 p2p_ps_state)
 		break;
 	}
 
+#ifdef CONFIG_MCC_MODE
+	rtw_hal_mcc_process_noa(padapter);
+#endif /* CONFIG_MCC_MODE */
 }
 
 u8 p2p_ps_wk_cmd(_adapter *padapter, u8 p2p_ps_state, u8 enqueue)
@@ -4520,9 +4672,10 @@ exit:
 }
 #endif /* CONFIG_P2P_PS */
 
-static void __reset_ch_sitesurvey_timer_process(struct wifidirect_info *pwdinfo)
+static void reset_ch_sitesurvey_timer_process(void *FunctionContext)
 {
-	_adapter *adapter = container_of(pwdinfo, _adapter, wdinfo);
+	_adapter *adapter = (_adapter *)FunctionContext;
+	struct	wifidirect_info		*pwdinfo = &adapter->wdinfo;
 
 	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
 		return;
@@ -4538,15 +4691,10 @@ static void __reset_ch_sitesurvey_timer_process(struct wifidirect_info *pwdinfo)
 	pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
 }
 
-static void reset_ch_sitesurvey_timer_process(struct timer_list *t)
+static void reset_ch_sitesurvey_timer_process2(void *FunctionContext)
 {
-	struct	wifidirect_info		*pwdinfo = from_timer(pwdinfo, t, reset_ch_sitesurvey);
-	__reset_ch_sitesurvey_timer_process(pwdinfo);
-}
-
-static void __reset_ch_sitesurvey_timer_process2(struct wifidirect_info *pwdinfo)
-{
-	_adapter *adapter = container_of(pwdinfo, _adapter, wdinfo);
+	_adapter *adapter = (_adapter *)FunctionContext;
+	struct	wifidirect_info		*pwdinfo = &adapter->wdinfo;
 
 	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
 		return;
@@ -4562,16 +4710,10 @@ static void __reset_ch_sitesurvey_timer_process2(struct wifidirect_info *pwdinfo
 	pwdinfo->p2p_info.scan_op_ch_only = 0;
 }
 
-static void reset_ch_sitesurvey_timer_process2(struct timer_list *t)
+static void restore_p2p_state_timer_process(void *FunctionContext)
 {
-	struct	wifidirect_info		*pwdinfo = from_timer(pwdinfo, t, reset_ch_sitesurvey2);
-	__reset_ch_sitesurvey_timer_process2(pwdinfo);
-}
-
-static void restore_p2p_state_timer_process(struct timer_list *t)
-{
-	struct	wifidirect_info		*pwdinfo = from_timer(pwdinfo, t, restore_p2p_state_timer);
-	_adapter *adapter = container_of(pwdinfo, _adapter, wdinfo);
+	_adapter *adapter = (_adapter *)FunctionContext;
+	struct	wifidirect_info		*pwdinfo = &adapter->wdinfo;
 
 	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
 		return;
@@ -4579,13 +4721,12 @@ static void restore_p2p_state_timer_process(struct timer_list *t)
 	p2p_protocol_wk_cmd(adapter, P2P_RESTORE_STATE_WK);
 }
 
-static void pre_tx_scan_timer_process(struct timer_list *t)
+static void pre_tx_scan_timer_process(void *FunctionContext)
 {
-	struct	wifidirect_info		*pwdinfo = from_timer(pwdinfo, t, pre_tx_scan_timer);
-	_adapter *adapter = container_of(pwdinfo, _adapter, wdinfo);
+	_adapter							*adapter = (_adapter *) FunctionContext;
+	struct	wifidirect_info				*pwdinfo = &adapter->wdinfo;
 	_irqL							irqL;
 	struct mlme_priv					*pmlmepriv = &adapter->mlmepriv;
-	u8								_status = 0;
 
 	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
 		return;
@@ -4611,10 +4752,10 @@ static void pre_tx_scan_timer_process(struct timer_list *t)
 	_exit_critical_bh(&pmlmepriv->lock, &irqL);
 }
 
-static void find_phase_timer_process(struct timer_list *t)
+static void find_phase_timer_process(void *FunctionContext)
 {
-	struct	wifidirect_info		*pwdinfo = from_timer(pwdinfo, t, find_phase_timer);
-	_adapter *adapter = container_of(pwdinfo, _adapter, wdinfo);
+	_adapter *adapter = (_adapter *)FunctionContext;
+	struct	wifidirect_info		*pwdinfo = &adapter->wdinfo;
 
 	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
 		return;
@@ -4870,11 +5011,11 @@ void rtw_init_wifidirect_timers(_adapter *padapter)
 {
 	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
 
-	rtw_init_timer(&pwdinfo->find_phase_timer, padapter, find_phase_timer_process);
-	rtw_init_timer(&pwdinfo->restore_p2p_state_timer, padapter, restore_p2p_state_timer_process);
-	rtw_init_timer(&pwdinfo->pre_tx_scan_timer, padapter, pre_tx_scan_timer_process);
-	rtw_init_timer(&pwdinfo->reset_ch_sitesurvey, padapter, reset_ch_sitesurvey_timer_process);
-	rtw_init_timer(&pwdinfo->reset_ch_sitesurvey2, padapter, reset_ch_sitesurvey_timer_process2);
+	rtw_init_timer(&pwdinfo->find_phase_timer, padapter, find_phase_timer_process, padapter);
+	rtw_init_timer(&pwdinfo->restore_p2p_state_timer, padapter, restore_p2p_state_timer_process, padapter);
+	rtw_init_timer(&pwdinfo->pre_tx_scan_timer, padapter, pre_tx_scan_timer_process, padapter);
+	rtw_init_timer(&pwdinfo->reset_ch_sitesurvey, padapter, reset_ch_sitesurvey_timer_process, padapter);
+	rtw_init_timer(&pwdinfo->reset_ch_sitesurvey2, padapter, reset_ch_sitesurvey_timer_process2, padapter);
 #ifdef CONFIG_CONCURRENT_MODE
 	rtw_init_timer(&pwdinfo->ap_p2p_switch_timer, padapter, ap_p2p_switch_timer_process, padapter);
 #endif
@@ -4899,7 +5040,6 @@ void init_wifidirect_info(_adapter *padapter, enum P2P_ROLE role)
 #ifdef CONFIG_WFD
 	struct wifi_display_info	*pwfd_info = &padapter->wfd_info;
 #endif
-	u8 union_ch = 0;
 	pwdinfo = &padapter->wdinfo;
 
 	pwdinfo->padapter = padapter;
@@ -4914,6 +5054,8 @@ void init_wifidirect_info(_adapter *padapter, enum P2P_ROLE role)
 		&& pwdinfo->driver_interface != DRIVER_CFG80211
 	) {
 		#ifdef CONFIG_CONCURRENT_MODE
+		u8 union_ch = 0;
+
 		if (rtw_mi_check_status(padapter, MI_LINKED))
 			union_ch = rtw_mi_get_union_chan(padapter);
 
@@ -5049,6 +5191,14 @@ void init_wifidirect_info(_adapter *padapter, enum P2P_ROLE role)
 	pwdinfo->p2p_info.scan_op_ch_only = 0;
 }
 
+void _rtw_p2p_set_role(struct wifidirect_info *wdinfo, enum P2P_ROLE role)
+{
+	if (wdinfo->role != role) {
+		wdinfo->role = role;
+		rtw_mi_update_iface_status(&(wdinfo->padapter->mlmepriv), 0);
+	}
+}
+
 #ifdef CONFIG_DBG_P2P
 
 /**
@@ -5197,9 +5347,6 @@ int rtw_p2p_enable(_adapter *padapter, enum P2P_ROLE role)
 	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
 
 	if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || role == P2P_ROLE_GO) {
-		u8 channel, ch_offset;
-		u16 bwmode;
-
 #if defined(CONFIG_CONCURRENT_MODE) && (!defined(RTW_P2P_GROUP_INTERFACE) || !RTW_P2P_GROUP_INTERFACE)
 		/*	Commented by Albert 2011/12/30 */
 		/*	The driver just supports 1 P2P group operation. */
@@ -5259,8 +5406,8 @@ int rtw_p2p_enable(_adapter *padapter, enum P2P_ROLE role)
 			_cancel_timer_ex(&pwdinfo->pre_tx_scan_timer);
 			_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
 			_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey2);
-			__reset_ch_sitesurvey_timer_process(pwdinfo);
-			__reset_ch_sitesurvey_timer_process2(pwdinfo);
+			reset_ch_sitesurvey_timer_process(padapter);
+			reset_ch_sitesurvey_timer_process2(padapter);
 #ifdef CONFIG_CONCURRENT_MODE
 			_cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer);
 #endif

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 374 - 196
core/rtw_pwrctrl.c


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 522 - 220
core/rtw_recv.c


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 608 - 422
core/rtw_rf.c


+ 2470 - 0
core/rtw_rm.c

@@ -0,0 +1,2470 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+
+#include <drv_types.h>
+#include <hal_data.h>
+#include "rtw_rm_fsm.h"
+
+#define pstr(s) s+strlen(s)
+
+u8 rm_post_event_hdl(_adapter *padapter, u8 *pbuf)
+{
+#ifdef CONFIG_RTW_80211K
+	struct rm_event *pev = (struct rm_event *)pbuf;
+
+	_rm_post_event(padapter, pev->rmid, pev->evid);
+	rm_handler(padapter, pev);
+#endif
+	return H2C_SUCCESS;
+}
+
+#ifdef CONFIG_RTW_80211K
+
+/* 802.11-2012 Table E-1 Operationg classes in United States */
+static RT_OPERATING_CLASS RTW_OP_CLASS_US[] = {
+	/* 0, OP_CLASS_NULL */	{  0,  0, {}},
+	/* 1, OP_CLASS_1 */	{115,  4, {36, 40, 44, 48}},
+	/* 2, OP_CLASS_2 */	{118,  4, {52, 56, 60, 64}},
+	/* 3, OP_CLASS_3 */	{124,  4, {149, 153, 157, 161}},
+	/* 4, OP_CLASS_4 */	{121, 11, {100, 104, 108, 112, 116, 120, 124,
+						128, 132, 136, 140}},
+	/* 5, OP_CLASS_5 */	{125,  5, {149, 153, 157, 161, 165}},
+	/* 6, OP_CLASS_12 */	{ 81, 11, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}}
+};
+
+struct cmd_meas_type_ {
+	u8 id;
+	char *name;
+};
+
+char *rm_type_req_name(u8 meas_type) {
+
+	switch (meas_type) {
+	case basic_req:
+		return "basic_req";
+	case cca_req:
+		return "cca_req";
+	case rpi_histo_req:
+		return "rpi_histo_req";
+	case ch_load_req:
+		return "ch_load_req";
+	case noise_histo_req:
+		return "noise_histo_req";
+	case bcn_req:
+		return "bcn_req";
+	case frame_req:
+		return "frame_req";
+	case sta_statis_req:
+		return "sta_statis_req";
+	}
+	return "unknown_req";
+};
+
+char *rm_type_rep_name(u8 meas_type) {
+
+	switch (meas_type) {
+	case basic_rep:
+		return "basic_rep";
+	case cca_rep:
+		return "cca_rep";
+	case rpi_histo_rep:
+		return "rpi_histo_rep";
+	case ch_load_rep:
+		return "ch_load_rep";
+	case noise_histo_rep:
+		return "noise_histo_rep";
+	case bcn_rep:
+		return "bcn_rep";
+	case frame_rep:
+		return "frame_rep";
+	case sta_statis_rep:
+		return "sta_statis_rep";
+	}
+	return "unknown_rep";
+};
+
+char *rm_en_cap_name(enum rm_cap_en en)
+{
+	switch (en) {
+	case RM_LINK_MEAS_CAP_EN:
+		return "RM_LINK_MEAS_CAP_EN";
+	case RM_NB_REP_CAP_EN:
+		return "RM_NB_REP_CAP_EN";
+	case RM_PARAL_MEAS_CAP_EN:
+		return "RM_PARAL_MEAS_CAP_EN";
+	case RM_REPEAT_MEAS_CAP_EN:
+		return "RM_REPEAT_MEAS_CAP_EN";
+	case RM_BCN_PASSIVE_MEAS_CAP_EN:
+		return "RM_BCN_PASSIVE_MEAS_CAP_EN";
+	case RM_BCN_ACTIVE_MEAS_CAP_EN:
+		return "RM_BCN_ACTIVE_MEAS_CAP_EN";
+	case RM_BCN_TABLE_MEAS_CAP_EN:
+		return "RM_BCN_TABLE_MEAS_CAP_EN";
+	case RM_BCN_MEAS_REP_COND_CAP_EN:
+		return "RM_BCN_MEAS_REP_COND_CAP_EN";
+
+	case RM_FRAME_MEAS_CAP_EN:
+		return "RM_FRAME_MEAS_CAP_EN";
+	case RM_CH_LOAD_CAP_EN:
+		return "RM_CH_LOAD_CAP_EN";
+	case RM_NOISE_HISTO_CAP_EN:
+		return "RM_NOISE_HISTO_CAP_EN";
+	case RM_STATIS_MEAS_CAP_EN:
+		return "RM_STATIS_MEAS_CAP_EN";
+	case RM_LCI_MEAS_CAP_EN:
+		return "RM_LCI_MEAS_CAP_EN";
+	case RM_LCI_AMIMUTH_CAP_EN:
+		return "RM_LCI_AMIMUTH_CAP_EN";
+	case RM_TRANS_STREAM_CAT_MEAS_CAP_EN:
+		return "RM_TRANS_STREAM_CAT_MEAS_CAP_EN";
+	case RM_TRIG_TRANS_STREAM_CAT_MEAS_CAP_EN:
+		return "RM_TRIG_TRANS_STREAM_CAT_MEAS_CAP_EN";
+
+	case RM_AP_CH_REP_CAP_EN:
+		return "RM_AP_CH_REP_CAP_EN";
+	case RM_RM_MIB_CAP_EN:
+		return "RM_RM_MIB_CAP_EN";
+	case RM_OP_CH_MAX_MEAS_DUR0:
+		return "RM_OP_CH_MAX_MEAS_DUR0";
+	case RM_OP_CH_MAX_MEAS_DUR1:
+		return "RM_OP_CH_MAX_MEAS_DUR1";
+	case RM_OP_CH_MAX_MEAS_DUR2:
+		return "RM_OP_CH_MAX_MEAS_DUR2";
+	case RM_NONOP_CH_MAX_MEAS_DUR0:
+		return "RM_NONOP_CH_MAX_MEAS_DUR0";
+	case RM_NONOP_CH_MAX_MEAS_DUR1:
+		return "RM_NONOP_CH_MAX_MEAS_DUR1";
+	case RM_NONOP_CH_MAX_MEAS_DUR2:
+		return "RM_NONOP_CH_MAX_MEAS_DUR2";
+
+	case RM_MEAS_PILOT_CAP0:
+		return "RM_MEAS_PILOT_CAP0";		/* 24-26 */
+	case RM_MEAS_PILOT_CAP1:
+		return "RM_MEAS_PILOT_CAP1";
+	case RM_MEAS_PILOT_CAP2:
+		return "RM_MEAS_PILOT_CAP2";
+	case RM_MEAS_PILOT_TRANS_INFO_CAP_EN:
+		return "RM_MEAS_PILOT_TRANS_INFO_CAP_EN";
+	case RM_NB_REP_TSF_OFFSET_CAP_EN:
+		return "RM_NB_REP_TSF_OFFSET_CAP_EN";
+	case RM_RCPI_MEAS_CAP_EN:
+		return "RM_RCPI_MEAS_CAP_EN";		/* 29 */
+	case RM_RSNI_MEAS_CAP_EN:
+		return "RM_RSNI_MEAS_CAP_EN";
+	case RM_BSS_AVG_ACCESS_DELAY_CAP_EN:
+		return "RM_BSS_AVG_ACCESS_DELAY_CAP_EN";
+
+	case RM_AVALB_ADMIS_CAPACITY_CAP_EN:
+		return "RM_AVALB_ADMIS_CAPACITY_CAP_EN";
+	case RM_ANT_CAP_EN:
+		return "RM_ANT_CAP_EN";
+	case RM_RSVD:
+	case RM_MAX:
+	default:
+		break;
+	}
+	return "unknown";
+}
+
+int rm_en_cap_chk_and_set(struct rm_obj *prm, enum rm_cap_en en)
+{
+	int idx;
+	u8 cap;
+
+
+	if (en >= RM_MAX)
+		return _FALSE;
+
+	idx = en / 8;
+	cap = prm->psta->padapter->rmpriv.rm_en_cap_def[idx];
+
+	if (!(cap & BIT(en - (idx*8)))) {
+		RTW_INFO("RM: %s incapable\n",rm_en_cap_name(en));
+		rm_set_rep_mode(prm, MEAS_REP_MOD_INCAP);
+		return _FALSE;
+	}
+	return _SUCCESS;
+}
+
+static u8 rm_get_oper_class_via_ch(u8 ch)
+{
+	int i,j,sz;
+
+
+	sz = sizeof(RTW_OP_CLASS_US)/sizeof(struct _RT_OPERATING_CLASS);
+
+	for (i = 0; i < sz; i++) {
+		for (j = 0; j < RTW_OP_CLASS_US[i].Len; j++) {
+			if ( ch == RTW_OP_CLASS_US[i].Channel[j]) {
+				RTW_INFO("RM: ch %u in oper_calss %u\n",
+					ch, RTW_OP_CLASS_US[i].global_op_class);
+				return RTW_OP_CLASS_US[i].global_op_class;
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+static u8 rm_get_ch_set(
+	struct rtw_ieee80211_channel *pch_set, u8 op_class, u8 ch_num)
+{
+	int i,j,sz;
+	u8 ch_amount = 0;
+
+
+	sz = sizeof(RTW_OP_CLASS_US)/sizeof(struct _RT_OPERATING_CLASS);
+
+	if (ch_num != 0) {
+		pch_set[0].hw_value = ch_num;
+		ch_amount = 1;
+		RTW_INFO("RM: meas_ch->hw_value = %u\n", pch_set->hw_value);
+		goto done;
+	}
+
+	for (i = 0; i < sz; i++) {
+
+		if (RTW_OP_CLASS_US[i].global_op_class == op_class) {
+
+			for (j = 0; j < RTW_OP_CLASS_US[i].Len; j++) {
+				pch_set[j].hw_value =
+					RTW_OP_CLASS_US[i].Channel[j];
+				RTW_INFO("RM: meas_ch[%d].hw_value = %u\n",
+					j, pch_set[j].hw_value);
+			}
+			ch_amount = RTW_OP_CLASS_US[i].Len;
+			break;
+		}
+	}
+done:
+	return ch_amount;
+}
+
+static int is_wildcard_bssid(u8 *bssid)
+{
+	int i;
+	u8 val8 = 0xff;
+
+
+	for (i=0;i<6;i++)
+		val8 &= bssid[i];
+
+	if (val8 == 0xff)
+		return _SUCCESS;
+	return _FALSE;
+}
+
+/* for caller outside rm */
+u8 rm_add_nb_req(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+	struct rm_obj *prm;
+
+
+	prm = rm_alloc_rmobj(padapter);
+
+	if (prm == NULL) {
+		RTW_ERR("RM: unable to alloc rm obj for requeset\n");
+		return _FALSE;
+	}
+
+	prm->psta = psta;
+	prm->q.category = RTW_WLAN_CATEGORY_RADIO_MEAS;
+	prm->q.diag_token = pmlmeinfo->dialogToken++;
+	prm->q.m_token = 1;
+
+	prm->rmid = psta->cmn.aid << 16
+		| prm->q.diag_token << 8
+		| RM_MASTER;
+
+	prm->q.action_code = RM_ACT_NB_REP_REQ;
+
+	#if 0
+	if (pmac) { /* find sta_info according to bssid */
+		pmac += 4; /* skip mac= */
+		if (hwaddr_parse(pmac, bssid) == NULL) {
+			sprintf(pstr(s), "Err: \nincorrect mac format\n");
+			return _FAIL;
+		}
+		psta = rm_get_sta(padapter, 0xff, bssid);
+	}
+	#endif
+
+	/* enquee rmobj */
+	rm_enqueue_rmobj(padapter, prm, _FALSE);
+
+	RTW_INFO("RM: rmid=%x add req to " MAC_FMT "\n",
+		prm->rmid, MAC_ARG(psta->cmn.mac_addr));
+
+	return _SUCCESS;
+}
+
+
+static u8 *build_wlan_hdr(_adapter *padapter, struct xmit_frame *pmgntframe,
+	struct sta_info *psta, u16 frame_type)
+{
+	u8 *pframe;
+	u16 *fctrl;
+	struct pkt_attrib *pattr;
+	struct rtw_ieee80211_hdr *pwlanhdr;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+
+	/* update attribute */
+	pattr = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattr);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	_rtw_memcpy(pwlanhdr->addr1, psta->cmn.mac_addr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3,
+		get_my_bssid(&(pmlmeinfo->network)),ETH_ALEN);
+
+	RTW_INFO("RM: dst = " MAC_FMT "\n", MAC_ARG(pwlanhdr->addr1));
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFragNum(pframe, 0);
+
+	set_frame_sub_type(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattr->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	return pframe;
+}
+
+void rm_set_rep_mode(struct rm_obj *prm, u8 mode)
+{
+
+	RTW_INFO("RM: rmid=%x set %s\n",
+		prm->rmid,
+		mode|MEAS_REP_MOD_INCAP?"INCAP":
+		mode|MEAS_REP_MOD_REFUSE?"REFUSE":
+		mode|MEAS_REP_MOD_LATE?"LATE":"");
+
+	prm->p.m_mode |= mode;
+}
+
+int issue_null_reply(struct rm_obj *prm)
+{
+	int len=0, my_len;
+	u8 *pframe, m_mode;
+	_adapter *padapter = prm->psta->padapter;
+	struct pkt_attrib *pattr;
+	struct xmit_frame *pmgntframe;
+	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+
+
+	m_mode = prm->p.m_mode;
+	if (m_mode || prm->p.rpt == 0) {
+		RTW_INFO("RM: rmid=%x reply (%s repeat=%d)\n",
+			prm->rmid,
+			m_mode&MEAS_REP_MOD_INCAP?"INCAP":
+			m_mode&MEAS_REP_MOD_REFUSE?"REFUSE":
+			m_mode&MEAS_REP_MOD_LATE?"LATE":"no content",
+			prm->p.rpt);
+	}
+
+	switch (prm->p.action_code) {
+	case RM_ACT_RADIO_MEAS_REQ:
+		len = 8;
+		break;
+	case RM_ACT_NB_REP_REQ:
+		len = 3;
+		break;
+	case RM_ACT_LINK_MEAS_REQ:
+		len = 3;
+		break;
+	default:
+		break;
+	}
+
+	if (len==0)
+		return _FALSE;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL) {
+		RTW_ERR("RM: %s alloc xmit_frame fail\n",__func__);
+		return _FALSE;
+	}
+	pattr = &pmgntframe->attrib;
+	pframe = build_wlan_hdr(padapter, pmgntframe, prm->psta, WIFI_ACTION);
+	pframe = rtw_set_fixed_ie(pframe, 3, &prm->p.category, &pattr->pktlen);
+
+	my_len = 0;
+	if (len>5) {
+		prm->p.len = len - 3 - 2;
+		pframe = rtw_set_fixed_ie(pframe, len - 3,
+			&prm->p.e_id, &my_len);
+	}
+
+	pattr->pktlen += my_len;
+	pattr->last_txcmdsz = pattr->pktlen;
+	dump_mgntframe(padapter, pmgntframe);
+
+	return _SUCCESS;
+}
+
+int ready_for_scan(struct rm_obj *prm)
+{
+	_adapter *padapter = prm->psta->padapter;
+	u8 ssc_chk;
+
+	if (!rtw_is_adapter_up(padapter))
+		return _FALSE;
+
+	ssc_chk = rtw_sitesurvey_condition_check(padapter, _FALSE);
+
+	if (ssc_chk == SS_ALLOW)
+		return _SUCCESS;
+
+	return _FALSE;
+}
+
+int rm_sitesurvey(struct rm_obj *prm)
+{
+	int meas_ch_num=0;
+	u8 ch_num=0, op_class=0, val8;
+	struct rtw_ieee80211_channel *pch_set;
+	struct sitesurvey_parm parm;
+
+
+	RTW_INFO("RM: rmid=%x %s\n",prm->rmid, __func__);
+
+	pch_set = &prm->q.ch_set[0];
+
+	_rtw_memset(pch_set, 0,
+		sizeof(struct rtw_ieee80211_channel) * MAX_OP_CHANNEL_SET_NUM);
+
+	if (prm->q.ch_num == 0) {
+		/* ch_num=0   : scan all ch in operating class */
+		op_class = prm->q.op_class;
+
+	} else if (prm->q.ch_num == 255) {
+		/* 802.11 p.499 */
+		/* ch_num=255 : scan all ch in current operating class */
+		op_class = rm_get_oper_class_via_ch(
+			(u8)prm->psta->padapter->mlmeextpriv.cur_channel);
+	} else
+		ch_num = prm->q.ch_num;
+
+	/* get means channel */
+	meas_ch_num = rm_get_ch_set(pch_set, op_class, ch_num);
+	prm->q.ch_set_ch_amount = meas_ch_num;
+
+	_rtw_memset(&parm, 0, sizeof(struct sitesurvey_parm));
+	_rtw_memcpy(parm.ch, pch_set,
+		sizeof(struct rtw_ieee80211_channel) * MAX_OP_CHANNEL_SET_NUM);
+
+	_rtw_memcpy(&parm.ssid[0], &prm->q.opt.bcn.ssid, IW_ESSID_MAX_SIZE);
+
+	parm.ssid_num = 1;
+	parm.scan_mode = prm->q.m_mode;
+	parm.ch_num = meas_ch_num;
+	parm.igi = 0;
+	parm.token = prm->rmid;
+	parm.duration = prm->q.meas_dur;
+	/* parm.bw = BW_20M; */
+
+	rtw_sitesurvey_cmd(prm->psta->padapter, &parm);
+
+	return _SUCCESS;
+}
+
+static u8 translate_percentage_to_rcpi(u32 SignalStrengthIndex)
+{
+	s32 SignalPower; /* in dBm. */
+	u8 rcpi;
+
+	/* Translate to dBm (x=y-100) */
+	SignalPower = SignalStrengthIndex - 100;
+
+	/* RCPI = Int{(Power in dBm + 110)*2} for 0dBm > Power > -110dBm
+	 *    0	: power <= -110.0 dBm
+	 *    1	: power =  -109.5 dBm
+	 *    2	: power =  -109.0 dBm
+	 */
+
+	rcpi = (SignalPower + 110)*2;
+	return rcpi;
+}
+
+static int rm_parse_ch_load_s_elem(struct rm_obj *prm, u8 *pbody, int req_len)
+{
+	u8 *popt_id;
+	int i, p=0; /* position */
+	int len = req_len;
+
+
+	prm->q.opt_s_elem_len = len;
+#if (RM_MORE_DBG_MSG)
+	RTW_INFO("RM: opt_s_elem_len=%d\n", len);
+#endif
+	while (len) {
+
+		switch (pbody[p]) {
+		case ch_load_rep_info:
+			/* check RM_EN */
+			rm_en_cap_chk_and_set(prm, RM_CH_LOAD_CAP_EN);
+
+			_rtw_memcpy(&(prm->q.opt.clm.rep_cond),
+				&pbody[p+2], sizeof(prm->q.opt.clm.rep_cond));
+
+			RTW_INFO("RM: ch_load_rep_info=%u:%u\n",
+				prm->q.opt.clm.rep_cond.cond,
+				prm->q.opt.clm.rep_cond.threshold);
+			break;
+		default:
+			break;
+
+		}
+		len = len - (int)pbody[p+1] - 2;
+		p = p + (int)pbody[p+1] + 2;
+#if (RM_MORE_DBG_MSG)
+		RTW_INFO("RM: opt_s_elem_len=%d\n",len);
+#endif
+	}
+	return _SUCCESS;
+}
+
+static int rm_parse_noise_histo_s_elem(struct rm_obj *prm,
+	u8 *pbody, int req_len)
+{
+	u8 *popt_id;
+	int i, p=0; /* position */
+	int len = req_len;
+
+
+	prm->q.opt_s_elem_len = len;
+#if (RM_MORE_DBG_MSG)
+	RTW_INFO("RM: opt_s_elem_len=%d\n", len);
+#endif
+
+	while (len) {
+
+		switch (pbody[p]) {
+		case noise_histo_rep_info:
+			/* check RM_EN */
+			rm_en_cap_chk_and_set(prm, RM_NOISE_HISTO_CAP_EN);
+
+			_rtw_memcpy(&(prm->q.opt.nhm.rep_cond),
+				&pbody[p+2], sizeof(prm->q.opt.nhm.rep_cond));
+
+			RTW_INFO("RM: noise_histo_rep_info=%u:%u\n",
+				prm->q.opt.nhm.rep_cond.cond,
+				prm->q.opt.nhm.rep_cond.threshold);
+			break;
+		default:
+			break;
+
+       		}
+		len = len - (int)pbody[p+1] - 2;
+		p = p + (int)pbody[p+1] + 2;
+#if (RM_MORE_DBG_MSG)
+		RTW_INFO("RM: opt_s_elem_len=%d\n",len);
+#endif
+	}
+	return _SUCCESS;
+}
+
+static int rm_parse_bcn_req_s_elem(struct rm_obj *prm, u8 *pbody, int req_len)
+{
+	u8 *popt_id;
+	int i, p=0; /* position */
+	int len = req_len;
+
+
+	/* opt length,2:pbody[0]+ pbody[1] */
+	/* first opt id : pbody[18] */
+
+	prm->q.opt_s_elem_len = len;
+#if (RM_MORE_DBG_MSG)
+	RTW_INFO("RM: opt_s_elem_len=%d\n", len);
+#endif
+
+	popt_id = prm->q.opt.bcn.opt_id;
+	while (len && prm->q.opt.bcn.opt_id_num < BCN_REQ_OPT_MAX_NUM) {
+
+		switch (pbody[p]) {
+		case bcn_req_ssid:
+			RTW_INFO("bcn_req_ssid\n");
+
+#if (DBG_BCN_REQ_WILDCARD)
+			RTW_INFO("DBG set ssid to WILDCARD\n");
+#else
+#if (DBG_BCN_REQ_SSID)
+			RTW_INFO("DBG set ssid to %s\n",DBG_BCN_REQ_SSID_NAME);
+			i = strlen(DBG_BCN_REQ_SSID_NAME);
+			prm->q.opt.bcn.ssid.SsidLength = i;
+			_rtw_memcpy(&(prm->q.opt.bcn.ssid.Ssid),
+				DBG_BCN_REQ_SSID_NAME, i);
+
+#else /* original */
+			prm->q.opt.bcn.ssid.SsidLength = pbody[p+1];
+			_rtw_memcpy(&(prm->q.opt.bcn.ssid.Ssid),
+				&pbody[p+2], pbody[p+1]);
+#endif
+#endif
+
+			RTW_INFO("RM: bcn_req_ssid=%s\n",
+				prm->q.opt.bcn.ssid.Ssid);
+
+			popt_id[prm->q.opt.bcn.opt_id_num++] = pbody[p];
+			break;
+
+		case bcn_req_rep_info:
+			/* check RM_EN */
+			rm_en_cap_chk_and_set(prm, RM_BCN_MEAS_REP_COND_CAP_EN);
+
+			_rtw_memcpy(&(prm->q.opt.bcn.rep_cond),
+				&pbody[p+2], sizeof(prm->q.opt.bcn.rep_cond));
+
+			RTW_INFO("bcn_req_rep_info=%u:%u\n",
+				prm->q.opt.bcn.rep_cond.cond,
+				prm->q.opt.bcn.rep_cond.threshold);
+
+			/*popt_id[prm->q.opt.bcn.opt_id_num++] = pbody[p];*/
+			break;
+
+		case bcn_req_rep_detail:
+#if DBG_BCN_REQ_DETAIL
+			prm->q.opt.bcn.rep_detail = 2; /* all IE in beacon */
+#else
+			prm->q.opt.bcn.rep_detail = pbody[p+2];
+#endif
+			popt_id[prm->q.opt.bcn.opt_id_num++] = pbody[p];
+
+#if (RM_MORE_DBG_MSG)
+			RTW_INFO("RM: report_detail=%d\n",
+				prm->q.opt.bcn.rep_detail);
+#endif
+			break;
+
+		case bcn_req_req:
+			RTW_INFO("RM: bcn_req_req\n");
+
+			prm->q.opt.bcn.req_start = rtw_malloc(pbody[p+1]);
+
+			if (prm->q.opt.bcn.req_start == NULL) {
+				RTW_ERR("RM: req_start malloc fail!!\n");
+				break;
+			}
+
+			for (i = 0; i < pbody[p+1]; i++)
+				*((prm->q.opt.bcn.req_start)+i) =
+					pbody[p+2+i];
+
+			prm->q.opt.bcn.req_len = pbody[p+1];
+			popt_id[prm->q.opt.bcn.opt_id_num++] = pbody[p];
+			break;
+
+		case bcn_req_ac_ch_rep:
+#if (RM_MORE_DBG_MSG)
+			RTW_INFO("RM: bcn_req_ac_ch_rep\n");
+#endif
+			popt_id[prm->q.opt.bcn.opt_id_num++] = pbody[p];
+			break;
+
+		default:
+			break;
+
+       		}
+		len = len - (int)pbody[p+1] - 2;
+		p = p + (int)pbody[p+1] + 2;
+#if (RM_MORE_DBG_MSG)
+		RTW_INFO("RM: opt_s_elem_len=%d\n",len);
+#endif
+	}
+
+	return _SUCCESS;
+}
+
+static int rm_parse_meas_req(struct rm_obj *prm, u8 *pbody)
+{
+	int p; /* position */
+	int req_len;
+
+
+	req_len = (int)pbody[1];
+	p = 5;
+
+	prm->q.op_class = pbody[p++];
+	prm->q.ch_num = pbody[p++];
+	prm->q.rand_intvl = le16_to_cpu(*(u16*)(&pbody[p]));
+	p+=2;
+	prm->q.meas_dur = le16_to_cpu(*(u16*)(&pbody[p]));
+	p+=2;
+
+	if (prm->q.m_type == bcn_req) {
+		/*
+		 * 0: passive
+		 * 1: active
+		 * 2: bcn_table
+		 */
+		prm->q.m_mode = pbody[p++];
+
+		/* BSSID */
+		_rtw_memcpy(&(prm->q.bssid), &pbody[p], 6);
+		p+=6;
+
+		/*
+		 * default, used when Reporting detail subelement
+		 * is not included in Beacon Request
+		 */
+		prm->q.opt.bcn.rep_detail = 2;
+	}
+
+	if (req_len-(p-2) <= 0) /* without sub-element */
+		return _SUCCESS;
+
+	switch (prm->q.m_type) {
+	case bcn_req:
+		rm_parse_bcn_req_s_elem(prm, &pbody[p], req_len-(p-2));
+		break;
+	case ch_load_req:
+		rm_parse_ch_load_s_elem(prm, &pbody[p], req_len-(p-2));
+		break;
+	case noise_histo_req:
+		rm_parse_noise_histo_s_elem(prm, &pbody[p], req_len-(p-2));
+		break;
+	default:
+		break;
+	}
+
+	return _SUCCESS;
+}
+
+/* receive measurement request */
+int rm_recv_radio_mens_req(_adapter *padapter,
+	union recv_frame *precv_frame, struct sta_info *psta)
+{
+	struct rm_obj *prm;
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	u8 *pdiag_body = (u8 *)(precv_frame->u.hdr.rx_data +
+		sizeof(struct rtw_ieee80211_hdr_3addr));
+	u8 *pmeas_body = &pdiag_body[5];
+	u8 rmid, update = 0;
+
+
+#if 0
+	/* search existing rm_obj */
+	rmid = psta->cmn.aid << 16
+		| pdiag_body[2] << 8
+		| RM_SLAVE;
+
+	prm = rm_get_rmobj(padapter, rmid);
+	if (prm) {
+		RTW_INFO("RM: Found an exist meas rmid=%u\n", rmid);
+		update = 1;
+	} else
+#endif
+	prm = rm_alloc_rmobj(padapter);
+
+	if (prm == NULL) {
+		RTW_ERR("RM: unable to alloc rm obj for requeset\n");
+		return _FALSE;
+	}
+
+	prm->psta = psta;
+	prm->q.diag_token = pdiag_body[2];
+	prm->q.rpt = le16_to_cpu(*(u16*)(&pdiag_body[3]));
+
+	/* Figure 8-104 Measurement Requested format */
+	prm->q.e_id = pmeas_body[0];
+	prm->q.m_token = pmeas_body[2];
+	prm->q.m_mode = pmeas_body[3];
+	prm->q.m_type = pmeas_body[4];
+
+	prm->rmid = psta->cmn.aid << 16
+		| prm->q.diag_token << 8
+		| RM_SLAVE;
+
+	RTW_INFO("RM: rmid=%x, bssid " MAC_FMT "\n", prm->rmid,
+		MAC_ARG(prm->psta->cmn.mac_addr));
+
+#if (RM_MORE_DBG_MSG)
+	RTW_INFO("RM: element_id = %d\n", prm->q.e_id);
+	RTW_INFO("RM: length = %d\n", (int)pmeas_body[1]);
+	RTW_INFO("RM: meas_token = %d\n", prm->q.m_token);
+	RTW_INFO("RM: meas_mode = %d\n", prm->q.m_mode);
+	RTW_INFO("RM: meas_type = %d\n", prm->q.m_type);
+#endif
+
+	if (prm->q.e_id != _MEAS_REQ_IE_) /* 38 */
+		return _FALSE;
+
+	switch (prm->q.m_type) {
+	case bcn_req:
+		RTW_INFO("RM: recv beacon_request\n");
+		switch (prm->q.m_mode) {
+		case bcn_req_passive:
+			rm_en_cap_chk_and_set(prm, RM_BCN_PASSIVE_MEAS_CAP_EN);
+			break;
+		case bcn_req_active:
+			rm_en_cap_chk_and_set(prm, RM_BCN_ACTIVE_MEAS_CAP_EN);
+			break;
+		case bcn_req_bcn_table:
+			rm_en_cap_chk_and_set(prm, RM_BCN_TABLE_MEAS_CAP_EN);
+			break;
+		default:
+			rm_set_rep_mode(prm, MEAS_REP_MOD_INCAP);
+			break;
+		}
+		break;
+	case ch_load_req:
+		RTW_INFO("RM: recv ch_load_request\n");
+		rm_en_cap_chk_and_set(prm, RM_CH_LOAD_CAP_EN);
+		break;
+	case noise_histo_req:
+		RTW_INFO("RM: recv noise_histogram_request\n");
+		rm_en_cap_chk_and_set(prm, RM_NOISE_HISTO_CAP_EN);
+		break;
+	default:
+		RTW_INFO("RM: recv unknown request type 0x%02x\n",
+			prm->q.m_type);
+		rm_set_rep_mode(prm, MEAS_REP_MOD_INCAP);
+		goto done;
+       }
+	rm_parse_meas_req(prm, pmeas_body);
+done:
+	if (!update)
+		rm_enqueue_rmobj(padapter, prm, _FALSE);
+
+	return _SUCCESS;
+}
+
+/* receive measurement report */
+int rm_recv_radio_mens_rep(_adapter *padapter,
+	union recv_frame *precv_frame, struct sta_info *psta)
+{
+	int ret = _FALSE;
+	struct rm_obj *prm;
+	u32 rmid;
+	u8 *pdiag_body = (u8 *)(precv_frame->u.hdr.rx_data +
+		sizeof(struct rtw_ieee80211_hdr_3addr));
+	u8 *pmeas_body = &pdiag_body[3];
+
+
+	rmid = psta->cmn.aid << 16
+		| pdiag_body[2] << 8
+		| RM_MASTER;
+
+	prm = rm_get_rmobj(padapter, rmid);
+	if (prm == NULL)
+		return _FALSE;
+
+	prm->p.action_code = pdiag_body[1];
+	prm->p.diag_token = pdiag_body[2];
+
+	/* Figure 8-140 Measuremnt Report format */
+	prm->p.e_id = pmeas_body[0];
+	prm->p.m_token = pmeas_body[2];
+	prm->p.m_mode = pmeas_body[3];
+	prm->p.m_type = pmeas_body[4];
+
+	RTW_INFO("RM: rmid=%x, bssid " MAC_FMT "\n", prm->rmid,
+		MAC_ARG(prm->psta->cmn.mac_addr));
+
+#if (RM_MORE_DBG_MSG)
+	RTW_INFO("RM: element_id = %d\n", prm->p.e_id);
+	RTW_INFO("RM: length = %d\n", (int)pmeas_body[1]);
+	RTW_INFO("RM: meas_token = %d\n", prm->p.m_token);
+	RTW_INFO("RM: meas_mode = %d\n", prm->p.m_mode);
+	RTW_INFO("RM: meas_type = %d\n", prm->p.m_type);
+#endif
+	if (prm->p.e_id != _MEAS_RSP_IE_) /* 39 */
+		return _FALSE;
+
+	RTW_INFO("RM: recv %s\n", rm_type_rep_name(prm->p.m_type));
+	rm_post_event(padapter, prm->rmid, RM_EV_recv_rep);
+
+	return ret;
+}
+
+int rm_radio_mens_nb_rep(_adapter *padapter,
+	union recv_frame *precv_frame, struct sta_info *psta)
+{
+	u8 *pdiag_body = (u8 *)(precv_frame->u.hdr.rx_data +
+		sizeof(struct rtw_ieee80211_hdr_3addr));
+	u8 *pmeas_body = &pdiag_body[3];
+	u32 len = precv_frame->u.hdr.len;
+	u32 rmid;
+	struct rm_obj *prm;
+
+
+	rmid = psta->cmn.aid << 16
+		| pdiag_body[2] << 8
+		| RM_MASTER;
+
+	prm = rm_get_rmobj(padapter, rmid);
+	if (prm == NULL)
+		return _FALSE;
+
+	prm->p.action_code = pdiag_body[1];
+	prm->p.diag_token = pdiag_body[2];
+	prm->p.e_id = pmeas_body[0];
+
+	RTW_INFO("RM: rmid=%x, bssid " MAC_FMT "\n", prm->rmid,
+		MAC_ARG(prm->psta->cmn.mac_addr));
+
+#if (RM_MORE_DBG_MSG)
+	RTW_INFO("RM: element_id = %d\n", prm->p.e_id);
+	RTW_INFO("RM: length = %d\n", (int)pmeas_body[1]);
+#endif
+	rm_post_event(padapter, prm->rmid, RM_EV_recv_rep);
+
+#ifdef CONFIG_LAYER2_ROAMING
+	if (rtw_wnm_btm_candidates_survey(padapter
+			,(pdiag_body + 3)
+			,(len - sizeof(struct rtw_ieee80211_hdr_3addr))
+			,_FALSE) == _FAIL)
+		return _FALSE;
+#endif
+	rtw_cfg80211_rx_rrm_action(padapter, precv_frame);
+
+	return _TRUE;
+}
+
+unsigned int rm_on_action(_adapter *padapter, union recv_frame *precv_frame)
+{
+	u32 ret = _FAIL;
+	u8 *pframe = NULL;
+	u8 *pframe_body = NULL;
+	u8 action_code = 0;
+	u8 diag_token = 0;
+	struct rtw_ieee80211_hdr_3addr *whdr;
+	struct sta_info *psta;
+
+
+	pframe = precv_frame->u.hdr.rx_data;
+
+	/* check RA matches or not */
+	if (!_rtw_memcmp(adapter_mac_addr(padapter),
+		GetAddr1Ptr(pframe), ETH_ALEN))
+		goto exit;
+
+	whdr = (struct rtw_ieee80211_hdr_3addr *)pframe;
+	RTW_INFO("RM: %s bssid = " MAC_FMT "\n",
+		__func__, MAC_ARG(whdr->addr2));
+
+	psta = rtw_get_stainfo(&padapter->stapriv, whdr->addr2);
+
+        if (!psta) {
+		RTW_ERR("RM: psta not found\n");
+                goto exit;
+        }
+
+	pframe_body = (unsigned char *)(pframe +
+		sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	/* Figure 8-438 radio measurement request frame Action field format */
+	/* Category = pframe_body[0] = 5 (Radio Measurement) */
+	action_code = pframe_body[1];
+	diag_token = pframe_body[2];
+
+#if (RM_MORE_DBG_MSG)
+	RTW_INFO("RM: %s radio_action=%x, diag_token=%x\n", __func__,
+		action_code, diag_token);
+#endif
+
+	switch (action_code) {
+
+	case RM_ACT_RADIO_MEAS_REQ:
+		RTW_INFO("RM: RM_ACT_RADIO_MEAS_REQ\n");
+		ret = rm_recv_radio_mens_req(padapter, precv_frame, psta);
+		break;
+
+	case RM_ACT_RADIO_MEAS_REP:
+		RTW_INFO("RM: RM_ACT_RADIO_MEAS_REP\n");
+		ret = rm_recv_radio_mens_rep(padapter, precv_frame, psta);
+		break;
+
+	case RM_ACT_LINK_MEAS_REQ:
+		RTW_INFO("RM: RM_ACT_LINK_MEAS_REQ\n");
+		break;
+
+	case RM_ACT_LINK_MEAS_REP:
+		RTW_INFO("RM: RM_ACT_LINK_MEAS_REP\n");
+		break;
+
+	case RM_ACT_NB_REP_REQ:
+		RTW_INFO("RM: RM_ACT_NB_REP_REQ\n");
+		break;
+
+	case RM_ACT_NB_REP_RESP:
+		RTW_INFO("RM: RM_ACT_NB_REP_RESP\n");
+		ret = rm_radio_mens_nb_rep(padapter, precv_frame, psta);
+		break;
+
+	default:
+		/* TODO reply incabable */
+		RTW_ERR("RM: unknown specturm management action %2x\n",
+			action_code);
+		break;
+	}
+exit:
+	return ret;
+}
+
+static u8 *rm_gen_bcn_detail_elem(_adapter *padapter, u8 *pframe,
+	struct rm_obj *prm, struct wlan_network *pnetwork,
+	unsigned int *fr_len)
+{
+	WLAN_BSSID_EX *pbss = &pnetwork->network;
+	unsigned int my_len;
+	int j, k, len;
+	u8 *plen;
+	u8 *ptr;
+	u8 val8, eid;
+
+
+	my_len = 0;
+	/* Reporting Detail values
+	 * 0: No fixed length fields or elements
+	 * 1: All fixed length fields and any requested elements
+	 *    in the Request info element if present
+	 * 2: All fixed length fields and elements
+	 * 3-255: Reserved
+	 */
+
+	/* report_detail = 0 */
+	if (prm->q.opt.bcn.rep_detail == 0
+		|| prm->q.opt.bcn.rep_detail > 2) {
+		return pframe;
+	}
+
+	/* ID */
+	val8 = 1; /* 1:reported frame body */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	plen = pframe;
+	val8 = 0;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* report_detail = 2 */
+	if (prm->q.opt.bcn.rep_detail == 2) {
+		pframe = rtw_set_fixed_ie(pframe, pbss->IELength - 4,
+			pbss->IEs, &my_len); /* -4 remove FCS */
+		goto done;
+	}
+
+	/* report_detail = 1 */
+	/* all fixed lenght fields */
+	pframe = rtw_set_fixed_ie(pframe,
+		_FIXED_IE_LENGTH_, pbss->IEs, &my_len);
+
+	for (j = 0; j < prm->q.opt.bcn.opt_id_num; j++) {
+		switch (prm->q.opt.bcn.opt_id[j]) {
+		case bcn_req_ssid:
+			/* SSID */
+#if (RM_MORE_DBG_MSG)
+			RTW_INFO("RM: bcn_req_ssid\n");
+#endif
+			pframe = rtw_set_ie(pframe, _SSID_IE_,
+				pbss->Ssid.SsidLength,
+				pbss->Ssid.Ssid, &my_len);
+			break;
+		case bcn_req_req:
+			if (prm->q.opt.bcn.req_start == NULL)
+				break;
+#if (RM_MORE_DBG_MSG)
+			RTW_INFO("RM: bcn_req_req");
+#endif
+			for (k=0; k<prm->q.opt.bcn.req_len; k++) {
+				eid = prm->q.opt.bcn.req_start[k];
+
+				val8 = pbss->IELength - _FIXED_IE_LENGTH_;
+				ptr = rtw_get_ie(pbss->IEs + _FIXED_IE_LENGTH_,
+					eid, &len, val8);
+
+				if (!ptr)
+					continue;
+#if (RM_MORE_DBG_MSG)
+				switch (eid) {
+				case EID_QBSSLoad:
+					RTW_INFO("RM: EID_QBSSLoad\n");
+					break;
+				case EID_HTCapability:
+					RTW_INFO("RM: EID_HTCapability\n");
+					break;
+				case _MDIE_:
+					RTW_INFO("RM: EID_MobilityDomain\n");
+					break;
+				default:
+					RTW_INFO("RM: EID %d todo\n",eid);
+					break;
+				}
+#endif
+				pframe = rtw_set_ie(pframe, eid,
+					len,ptr+2, &my_len);
+			} /* for() */
+			break;
+		case bcn_req_ac_ch_rep:
+		default:
+			RTW_INFO("RM: OPT %d TODO\n",prm->q.opt.bcn.opt_id[j]);
+			break;
+		}
+	}
+done:
+	/*
+	 * update my length
+	 * content length does NOT include ID and LEN
+	 */
+	val8 = my_len - 2;
+	rtw_set_fixed_ie(plen, 1, &val8, &j);
+
+	/* update length to caller */
+	*fr_len += my_len;
+
+	return pframe;
+}
+
+static u8 rm_get_rcpi(struct rm_obj *prm, struct wlan_network *pnetwork)
+{
+	return translate_percentage_to_rcpi(
+		pnetwork->network.PhyInfo.SignalStrength);
+}
+
+static u8 rm_get_rsni(struct rm_obj *prm, struct wlan_network *pnetwork)
+{
+	int i;
+	u8 val8, snr;
+	HAL_DATA_TYPE *pHalData = GET_HAL_DATA(prm->psta->padapter);
+
+
+	if (pnetwork->network.PhyInfo.is_cck_rate) {
+		/* current HW doesn't have CCK RSNI */
+		/* 255 indicates RSNI is unavailable */
+		val8 = 255;
+	} else {
+		snr = 0;
+		for (i = 0; i < pHalData->NumTotalRFPath; i++) {
+			snr += pnetwork->network.PhyInfo.rx_snr[i];
+		}
+		snr = snr / pHalData->NumTotalRFPath;
+		val8 = (u8)(snr + 10)*2;
+	}
+	return val8;
+}
+
+u8 rm_bcn_req_cond_mach(struct rm_obj *prm, struct wlan_network *pnetwork)
+{
+	u8 val8;
+
+
+	switch(prm->q.opt.bcn.rep_cond.cond) {
+	case bcn_rep_cond_immediately:
+		return _SUCCESS;
+	case bcn_req_cond_rcpi_greater:
+		val8 = rm_get_rcpi(prm, pnetwork);
+		if (val8 > prm->q.opt.bcn.rep_cond.threshold)
+			return _SUCCESS;
+		break;
+	case bcn_req_cond_rcpi_less:
+		val8 = rm_get_rcpi(prm, pnetwork);
+		if (val8 < prm->q.opt.bcn.rep_cond.threshold)
+			return _SUCCESS;
+		break;
+	case bcn_req_cond_rsni_greater:
+		val8 = rm_get_rsni(prm, pnetwork);
+		if (val8 != 255 && val8 > prm->q.opt.bcn.rep_cond.threshold)
+			return _SUCCESS;
+		break;
+	case bcn_req_cond_rsni_less:
+		val8 = rm_get_rsni(prm, pnetwork);
+		if (val8 != 255 && val8 < prm->q.opt.bcn.rep_cond.threshold)
+			return _SUCCESS;
+		break;
+	default:
+		RTW_ERR("RM: bcn_req cond %u not support\n",
+			prm->q.opt.bcn.rep_cond.cond);
+		break;
+	}
+	return _FALSE;
+}
+
+static u8 *rm_bcn_rep_fill_scan_resule (struct rm_obj *prm,
+	u8 *pframe, struct wlan_network *pnetwork, unsigned int *fr_len)
+{
+	int snr, i;
+	u8 val8, *plen;
+	u16 val16;
+	u32 val32;
+	u64 val64;
+	PWLAN_BSSID_EX pbss;
+	unsigned int my_len;
+	_adapter *padapter = prm->psta->padapter;
+
+
+	my_len = 0;
+	/* meas ID */
+	val8 = EID_MeasureReport;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* remember position form elelment length */
+	plen = pframe;
+
+	/* meas_rpt_len */
+	/* default 3 = mode + token + type but no beacon content */
+	val8 = 3;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* meas_token */
+	val8 = prm->q.m_token;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* meas_rpt_mode F8-141 */
+	val8 = prm->p.m_mode;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* meas_type T8-81 */
+	val8 = bcn_rep;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	if (pnetwork == NULL)
+		goto done;
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &prm->q.op_class, &my_len);
+
+	/* channel */
+	pbss = &pnetwork->network;
+	val8 = pbss->Configuration.DSConfig;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* Actual Measurement StartTime */
+	val64 = cpu_to_le64(prm->meas_start_time);
+	pframe = rtw_set_fixed_ie(pframe, 8, (u8 *)&val64, &my_len);
+
+	/* Measurement Duration */
+	val16 = prm->meas_end_time - prm->meas_start_time;
+	val16 = cpu_to_le16(val16);
+	pframe = rtw_set_fixed_ie(pframe, 2, (u8 *)&val16, &my_len);
+
+	/* TODO
+	 * ReportedFrameInformation:
+	 * 0 :beacon or probe rsp
+	 * 1 :pilot frame
+	 */
+	val8 = 0; /* report frame info */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* RCPI */
+	val8 = rm_get_rcpi(prm, pnetwork);
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* RSNI */
+	val8 = rm_get_rsni(prm, pnetwork);
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* BSSID */
+	pframe = rtw_set_fixed_ie(pframe, 6, (u8 *)&pbss->MacAddress, &my_len);
+
+	/*
+	 * AntennaID
+	 * 0: unknown
+	 * 255: multiple antenna (Diversity)
+	 */
+	val8 = 0;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* ParentTSF */
+	val32 = prm->meas_start_time + pnetwork->network.PhyInfo.free_cnt;
+	pframe = rtw_set_fixed_ie(pframe, 4, (u8 *)&val32, &my_len);
+
+	/*
+	 * Generate Beacon detail
+	 */
+	pframe = rm_gen_bcn_detail_elem(padapter, pframe,
+		prm, pnetwork, &my_len);
+done:
+	/*
+	 * update my length
+	 * content length does NOT include ID and LEN
+	 */
+	val8 = my_len - 2;
+	rtw_set_fixed_ie(plen, 1, &val8, &i);
+
+	/* update length to caller */
+	*fr_len += my_len;
+
+	return pframe;
+}
+
+static u8 *rm_gen_bcn_rep_ie (struct rm_obj *prm,
+	u8 *pframe, struct wlan_network *pnetwork, unsigned int *fr_len)
+{
+	int snr, i;
+	u8 val8, *plen;
+	u16 val16;
+	u32 val32;
+	u64 val64;
+	unsigned int my_len;
+	_adapter *padapter = prm->psta->padapter;
+
+
+	my_len = 0;
+	plen = pframe + 1;
+	pframe = rtw_set_fixed_ie(pframe, 7, &prm->p.e_id, &my_len);
+
+	/* Actual Measurement StartTime */
+	val64 = cpu_to_le64(prm->meas_start_time);
+	pframe = rtw_set_fixed_ie(pframe, 8, (u8 *)&val64, &my_len);
+
+	/* Measurement Duration */
+	val16 = prm->meas_end_time - prm->meas_start_time;
+	val16 = cpu_to_le16(val16);
+	pframe = rtw_set_fixed_ie(pframe, 2, (u8*)&val16, &my_len);
+
+	/* TODO
+	* ReportedFrameInformation:
+	* 0 :beacon or probe rsp
+	* 1 :pilot frame
+	*/
+	val8 = 0; /* report frame info */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* RCPI */
+	val8 = rm_get_rcpi(prm, pnetwork);
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* RSNI */
+	val8 = rm_get_rsni(prm, pnetwork);
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* BSSID */
+	pframe = rtw_set_fixed_ie(pframe, 6,
+		(u8 *)&pnetwork->network.MacAddress, &my_len);
+
+	/*
+	 * AntennaID
+	 * 0: unknown
+	 * 255: multiple antenna (Diversity)
+	 */
+	val8 = 0;
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* ParentTSF */
+	val32 = prm->meas_start_time + pnetwork->network.PhyInfo.free_cnt;
+	pframe = rtw_set_fixed_ie(pframe, 4, (u8 *)&val32, &my_len);
+
+	/* Generate Beacon detail */
+	pframe = rm_gen_bcn_detail_elem(padapter, pframe,
+		prm, pnetwork, &my_len);
+done:
+	/*
+	* update my length
+	* content length does NOT include ID and LEN
+	*/
+	val8 = my_len - 2;
+	rtw_set_fixed_ie(plen, 1, &val8, &i);
+
+	/* update length to caller */
+	*fr_len += my_len;
+
+	return pframe;
+}
+
+static int retrieve_scan_result(struct rm_obj *prm)
+{
+	_irqL irqL;
+	_list *plist, *phead;
+	_queue *queue;
+	_adapter *padapter = prm->psta->padapter;
+	struct rtw_ieee80211_channel *pch_set;
+	struct wlan_network *pnetwork = NULL;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	int i, meas_ch_num=0;
+	PWLAN_BSSID_EX pbss;
+	unsigned int matched_network;
+	int len, my_len;
+	u8 buf_idx, *pbuf = NULL, *tmp_buf = NULL;
+
+
+	tmp_buf = rtw_malloc(MAX_XMIT_EXTBUF_SZ);
+	if (tmp_buf == NULL)
+		return 0;
+
+	my_len = 0;
+	buf_idx = 0;
+	matched_network = 0;
+	queue = &(pmlmepriv->scanned_queue);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	/* get requested measurement channel set */
+	pch_set = prm->q.ch_set;
+	meas_ch_num = prm->q.ch_set_ch_amount;
+
+	/* search scan queue to find requested SSID */
+	while (1) {
+
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		pbss = &pnetwork->network;
+
+		/*
+		* report network if requested channel set contains
+		* the channel matchs selected network
+		*/
+		if (rtw_chset_search_ch(adapter_to_chset(padapter),
+			pbss->Configuration.DSConfig) == 0)
+			goto next;
+
+		if (rtw_mlme_band_check(padapter, pbss->Configuration.DSConfig)
+			== _FALSE)
+			goto next;
+
+		if (rtw_validate_ssid(&(pbss->Ssid)) == _FALSE)
+			goto next;
+
+		/* go through measurement requested channels */
+		for (i = 0; i < meas_ch_num; i++) {
+
+			/* match channel */
+			if (pch_set[i].hw_value != pbss->Configuration.DSConfig)
+				continue;
+
+			/* match bssid */
+			if (is_wildcard_bssid(prm->q.bssid) == FALSE)
+				if (_rtw_memcmp(prm->q.bssid,
+					pbss->MacAddress, 6) == _FALSE) {
+					continue;
+				}
+			/*
+			 * default wildcard SSID. wildcard SSID:
+			 * A SSID value (null) used to represent all SSIDs
+			 */
+
+			/* match ssid */
+			if ((prm->q.opt.bcn.ssid.SsidLength > 0) &&
+				_rtw_memcmp(prm->q.opt.bcn.ssid.Ssid,
+				pbss->Ssid.Ssid,
+				prm->q.opt.bcn.ssid.SsidLength) == _FALSE)
+				continue;
+
+			/* match condition */
+			if (rm_bcn_req_cond_mach(prm, pnetwork) == _FALSE) {
+				RTW_INFO("RM: condition mismatch ch %u ssid %s bssid "MAC_FMT"\n",
+					pch_set[i].hw_value, pbss->Ssid.Ssid,
+					MAC_ARG(pbss->MacAddress));
+				RTW_INFO("RM: condition %u:%u\n",
+					prm->q.opt.bcn.rep_cond.cond,
+					prm->q.opt.bcn.rep_cond.threshold);
+				continue;
+			}
+
+			/* Found a matched SSID */
+			matched_network++;
+
+			RTW_INFO("RM: ch %u Found %s bssid "MAC_FMT"\n",
+				pch_set[i].hw_value, pbss->Ssid.Ssid,
+				MAC_ARG(pbss->MacAddress));
+
+			len = 0;
+			_rtw_memset(tmp_buf, 0, MAX_XMIT_EXTBUF_SZ);
+			rm_gen_bcn_rep_ie(prm, tmp_buf, pnetwork, &len);
+new_packet:
+			if (my_len == 0) {
+				pbuf = rtw_malloc(MAX_XMIT_EXTBUF_SZ);
+				if (pbuf == NULL)
+					goto fail;
+				prm->buf[buf_idx].pbuf = pbuf;
+			}
+
+			if ((MAX_XMIT_EXTBUF_SZ - (my_len+len+24+4)) > 0) {
+				pbuf = rtw_set_fixed_ie(pbuf,
+					len, tmp_buf, &my_len);
+				prm->buf[buf_idx].len = my_len;
+			} else {
+				if (my_len == 0) /* not enough space */
+					goto fail;
+
+				my_len = 0;
+				buf_idx++;
+				goto new_packet;
+			}
+		} /* for() */
+next:
+		plist = get_next(plist);
+	} /* while() */
+fail:
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (tmp_buf)
+		rtw_mfree(tmp_buf, MAX_XMIT_EXTBUF_SZ);
+
+	RTW_INFO("RM: Found %d matched %s\n", matched_network,
+		prm->q.opt.bcn.ssid.Ssid);
+
+	if (prm->buf[buf_idx].pbuf)
+		return buf_idx+1;
+
+	return 0;
+}
+
+int issue_beacon_rep(struct rm_obj *prm)
+{
+	int i, my_len;
+	u8 *pframe;
+	_adapter *padapter = prm->psta->padapter;
+	struct pkt_attrib *pattr;
+	struct xmit_frame *pmgntframe;
+	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+	int pkt_num;
+
+
+	pkt_num = retrieve_scan_result(prm);
+
+	if (pkt_num == 0) {
+		issue_null_reply(prm);
+		return _SUCCESS;
+	}
+
+	for (i=0;i<pkt_num;i++) {
+
+		pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+		if (pmgntframe == NULL) {
+			RTW_ERR("RM: %s alloc xmit_frame fail\n",__func__);
+			goto fail;
+		}
+		pattr = &pmgntframe->attrib;
+		pframe = build_wlan_hdr(padapter,
+			pmgntframe, prm->psta, WIFI_ACTION);
+		pframe = rtw_set_fixed_ie(pframe,
+			3, &prm->p.category, &pattr->pktlen);
+
+		my_len = 0;
+		pframe = rtw_set_fixed_ie(pframe,
+			prm->buf[i].len, prm->buf[i].pbuf, &my_len);
+
+		pattr->pktlen += my_len;
+		pattr->last_txcmdsz = pattr->pktlen;
+		dump_mgntframe(padapter, pmgntframe);
+	}
+fail:
+	for (i=0;i<pkt_num;i++) {
+		if (prm->buf[i].pbuf) {
+			rtw_mfree(prm->buf[i].pbuf, MAX_XMIT_EXTBUF_SZ);
+			prm->buf[i].pbuf = NULL;
+			prm->buf[i].len = 0;
+		}
+	}
+	return _SUCCESS;
+}
+
+/* neighbor request */
+int issue_nb_req(struct rm_obj *prm)
+{
+	_adapter *padapter = prm->psta->padapter;
+	struct sta_info *psta = prm->psta;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct xmit_frame *pmgntframe = NULL;
+	struct pkt_attrib *pattr = NULL;
+	u8 val8;
+	u8 *pframe = NULL;
+
+
+	RTW_INFO("RM: %s\n", __func__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL) {
+		RTW_ERR("RM: %s alloc xmit_frame fail\n",__func__);
+		return _FALSE;
+	}
+	pattr = &pmgntframe->attrib;
+	pframe = build_wlan_hdr(padapter, pmgntframe, psta, WIFI_ACTION);
+	pframe = rtw_set_fixed_ie(pframe,
+		3, &prm->q.category, &pattr->pktlen);
+
+	if (prm->q.pssid) {
+
+		u8 sub_ie[64] = {0};
+		u8 *pie = &sub_ie[2];
+
+		RTW_INFO("RM: Send NB Req to "MAC_FMT" for(SSID) %s searching\n",
+			MAC_ARG(pmlmepriv->cur_network.network.MacAddress),
+			pmlmepriv->cur_network.network.Ssid.Ssid);
+
+		val8 = strlen(prm->q.pssid);
+		sub_ie[0] = 0; /*SSID*/
+		sub_ie[1] = val8;
+
+		_rtw_memcpy(pie, prm->q.pssid, val8);
+
+		pframe = rtw_set_fixed_ie(pframe, val8 + 2,
+			sub_ie, &pattr->pktlen);
+	} else {
+
+		if (!pmlmepriv->cur_network.network.Ssid.SsidLength)
+			RTW_INFO("RM: Send NB Req to "MAC_FMT"\n",
+				MAC_ARG(pmlmepriv->cur_network.network.MacAddress));
+		else {
+			u8 sub_ie[64] = {0};
+			u8 *pie = &sub_ie[2];
+
+			RTW_INFO("RM: Send NB Req to "MAC_FMT" for(SSID) %s searching\n",
+				MAC_ARG(pmlmepriv->cur_network.network.MacAddress),
+				pmlmepriv->cur_network.network.Ssid.Ssid);
+
+			sub_ie[0] = 0; /*SSID*/
+			sub_ie[1] = pmlmepriv->cur_network.network.Ssid.SsidLength;
+
+			_rtw_memcpy(pie, pmlmepriv->cur_network.network.Ssid.Ssid,
+				pmlmepriv->cur_network.network.Ssid.SsidLength);
+
+			pframe = rtw_set_fixed_ie(pframe,
+				pmlmepriv->cur_network.network.Ssid.SsidLength + 2,
+				sub_ie, &pattr->pktlen);
+		}
+	}
+
+	pattr->last_txcmdsz = pattr->pktlen;
+	dump_mgntframe(padapter, pmgntframe);
+
+	return _SUCCESS;
+}
+
+static u8 *rm_gen_bcn_req_s_elem(_adapter *padapter,
+	u8 *pframe, unsigned int *fr_len)
+{
+	u8 val8;
+	unsigned int my_len = 0;
+	u8 bssid[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+
+	val8 = bcn_req_active; /* measurement mode T8-64 */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	pframe = rtw_set_fixed_ie(pframe, 6, bssid, &my_len);
+
+	/* update length to caller */
+	*fr_len += my_len;
+
+	/* optional subelements */
+	return pframe;
+}
+
+static u8 *rm_gen_ch_load_req_s_elem(_adapter *padapter,
+	u8 *pframe, unsigned int *fr_len)
+{
+	u8 val8;
+	unsigned int my_len = 0;
+
+
+	val8 = 1; /* 1: channel load T8-60 */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	val8 = 2; /* channel load length = 2 (extensible)  */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	val8 = 0; /* channel load condition : 0 (issue when meas done) T8-61 */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	val8 = 0; /* channel load reference value : 0 */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* update length to caller */
+	*fr_len += my_len;
+
+	return pframe;
+}
+
+static u8 *rm_gen_noise_histo_req_s_elem(_adapter *padapter,
+	u8 *pframe, unsigned int *fr_len)
+{
+	u8 val8;
+	unsigned int my_len = 0;
+
+
+	val8 = 1; /* 1: noise histogram T8-62 */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	val8 = 2; /* noise histogram length = 2 (extensible)  */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	val8 = 0; /* noise histogram condition : 0 (issue when meas done) T8-63 */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	val8 = 0; /* noise histogram reference value : 0 */
+	pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+
+	/* update length to caller */
+	*fr_len += my_len;
+
+	return pframe;
+}
+
+int issue_radio_meas_req(struct rm_obj *prm)
+{
+	u8 val8;
+	u8 *pframe;
+	u8 *plen;
+	u16 val16;
+	int my_len, i;
+	struct xmit_frame *pmgntframe;
+	struct pkt_attrib *pattr;
+	_adapter *padapter = prm->psta->padapter;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+
+	RTW_INFO("RM: %s - %s\n", __func__, rm_type_req_name(prm->q.m_type));
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL) {
+		RTW_ERR("RM: %s alloc xmit_frame fail\n",__func__);
+		return _FALSE;
+	}
+	pattr = &pmgntframe->attrib;
+	pframe = build_wlan_hdr(padapter, pmgntframe, prm->psta, WIFI_ACTION);
+	pframe = rtw_set_fixed_ie(pframe, 3, &prm->q.category, &pattr->pktlen);
+
+	/* repeat */
+	val16 = cpu_to_le16(prm->q.rpt);
+	pframe = rtw_set_fixed_ie(pframe, 2,
+		(unsigned char *)&(val16), &pattr->pktlen);
+
+	my_len = 0;
+	plen = pframe + 1;
+	pframe = rtw_set_fixed_ie(pframe, 7, &prm->q.e_id, &my_len);
+
+	/* random interval */
+	val16 = 100; /* 100 TU */
+	val16 = cpu_to_le16(val16);
+	pframe = rtw_set_fixed_ie(pframe, 2, (u8 *)&val16, &my_len);
+
+	/* measurement duration */
+	val16 = 100;
+	val16 = cpu_to_le16(val16);
+	pframe = rtw_set_fixed_ie(pframe, 2, (u8 *)&val16, &my_len);
+
+	/* optional subelement */
+	switch (prm->q.m_type) {
+	case bcn_req:
+		pframe = rm_gen_bcn_req_s_elem(padapter, pframe, &my_len);
+		break;
+	case ch_load_req:
+		pframe = rm_gen_ch_load_req_s_elem(padapter, pframe, &my_len);
+		break;
+	case noise_histo_req:
+		pframe = rm_gen_noise_histo_req_s_elem(padapter,
+			pframe, &my_len);
+		break;
+	case basic_req:
+	default:
+		break;
+	}
+
+	/* length */
+	val8 = (u8)my_len - 2;
+	rtw_set_fixed_ie(plen, 1, &val8, &i);
+
+	pattr->pktlen += my_len;
+
+	pattr->last_txcmdsz = pattr->pktlen;
+	dump_mgntframe(padapter, pmgntframe);
+
+	return _SUCCESS;
+}
+
+/* noise histogram */
+static u8 rm_get_anpi(struct rm_obj *prm, struct wlan_network *pnetwork)
+{
+	return translate_percentage_to_rcpi(
+		pnetwork->network.PhyInfo.SignalStrength);
+}
+
+int rm_radio_meas_report_cond(struct rm_obj *prm)
+{
+	u8 val8;
+	int i;
+
+
+	switch (prm->q.m_type) {
+	case ch_load_req:
+
+		val8 = prm->p.ch_load;
+		switch (prm->q.opt.clm.rep_cond.cond) {
+		case ch_load_cond_immediately:
+			return _SUCCESS;
+		case ch_load_cond_anpi_equal_greater:
+			if (val8 >= prm->q.opt.clm.rep_cond.threshold)
+				return _SUCCESS;
+		case ch_load_cond_anpi_equal_less:
+			if (val8 <= prm->q.opt.clm.rep_cond.threshold)
+				return _SUCCESS;
+		default:
+			break;
+		}
+		break;
+	case noise_histo_req:
+		val8 = prm->p.anpi;
+		switch (prm->q.opt.nhm.rep_cond.cond) {
+		case noise_histo_cond_immediately:
+			return _SUCCESS;
+		case noise_histo_cond_anpi_equal_greater:
+			if (val8 >= prm->q.opt.nhm.rep_cond.threshold)
+				return _SUCCESS;
+			break;
+		case noise_histo_cond_anpi_equal_less:
+			if (val8 <= prm->q.opt.nhm.rep_cond.threshold)
+				return _SUCCESS;
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	return _FAIL;
+}
+
+int retrieve_radio_meas_result(struct rm_obj *prm)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(prm->psta->padapter);
+	int i, ch = -1;
+	u8 val8;
+
+
+	ch = rtw_chset_search_ch(adapter_to_chset(prm->psta->padapter),
+		prm->q.ch_num);
+
+	if ((ch == -1) || (ch >= MAX_CHANNEL_NUM)) {
+		RTW_ERR("RM: get ch(CH:%d) fail\n", prm->q.ch_num);
+		ch = 0;
+	}
+
+	switch (prm->q.m_type) {
+	case ch_load_req:
+#ifdef CONFIG_RTW_ACS
+		val8 = hal_data->acs.clm_ratio[ch];
+#else
+		val8 = 0;
+#endif
+		prm->p.ch_load = val8;
+		break;
+	case noise_histo_req:
+#ifdef CONFIG_RTW_ACS
+		/* ANPI */
+		prm->p.anpi = hal_data->acs.nhm_ratio[ch];
+
+		/* IPI 0~10 */
+		for (i=0;i<11;i++)
+			prm->p.ipi[i] = hal_data->acs.nhm[ch][i];
+		
+#else
+		val8 = 0;
+		prm->p.anpi = val8;
+		for (i=0;i<11;i++)
+			prm->p.ipi[i] = val8;
+#endif
+		break;
+	default:
+		break;
+	}
+	return _SUCCESS;
+}
+
+int issue_radio_meas_rep(struct rm_obj *prm)
+{
+	u8 val8;
+	u8 *pframe;
+	u8 *plen;
+	u16 val16;
+	u64 val64;
+	unsigned int my_len;
+	_adapter *padapter = prm->psta->padapter;
+	struct xmit_frame *pmgntframe;
+	struct pkt_attrib *pattr;
+	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+	struct sta_info *psta = prm->psta;
+	int i;
+
+
+	RTW_INFO("RM: %s\n", __func__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL) {
+		RTW_ERR("RM: ERR %s alloc xmit_frame fail\n",__func__);
+		return _FALSE;
+	}
+	pattr = &pmgntframe->attrib;
+	pframe = build_wlan_hdr(padapter, pmgntframe, psta, WIFI_ACTION);
+	pframe = rtw_set_fixed_ie(pframe, 3,
+		&prm->p.category, &pattr->pktlen);
+
+	my_len = 0;
+	plen = pframe + 1;
+	pframe = rtw_set_fixed_ie(pframe, 7, &prm->p.e_id, &my_len);
+
+	/* Actual Meas start time - 8 bytes */
+	val64 = cpu_to_le64(prm->meas_start_time);
+	pframe = rtw_set_fixed_ie(pframe, 8, (u8 *)&val64, &my_len);
+
+	/* measurement duration */
+	val16 = prm->meas_end_time - prm->meas_start_time;
+	val16 = cpu_to_le16(val16);
+	pframe = rtw_set_fixed_ie(pframe, 2, (u8 *)&val16, &my_len);
+
+	/* optional subelement */
+	switch (prm->q.m_type) {
+	case ch_load_req:
+		val8 = prm->p.ch_load;
+		pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+		break;
+	case noise_histo_req:
+		/*
+		 * AntennaID
+		 * 0: unknown
+		 * 255: multiple antenna (Diversity)
+		 */
+		val8 = 0;
+		pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+		/* ANPI */
+		val8 = prm->p.anpi;
+		pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+		/* IPI 0~10 */
+		for (i=0;i<11;i++) {
+			val8 = prm->p.ipi[i];
+			pframe = rtw_set_fixed_ie(pframe, 1, &val8, &my_len);
+		}
+		break;
+	default:
+		break;
+	}
+done:
+	/* length */
+	val8 = (u8)my_len-2;
+	rtw_set_fixed_ie(plen, 1, &val8, &i); /* use variable i to ignore it */
+
+	pattr->pktlen += my_len;
+	pattr->last_txcmdsz = pattr->pktlen;
+	dump_mgntframe(padapter, pmgntframe);
+
+	return _SUCCESS;
+}
+
+void rtw_ap_parse_sta_rm_en_cap(_adapter *padapter,
+	struct sta_info *psta, struct rtw_ieee802_11_elems *elem)
+{
+	if (elem->rm_en_cap) {
+		RTW_INFO("assoc.rm_en_cap="RM_CAP_FMT"\n",
+			RM_CAP_ARG(elem->rm_en_cap));
+		_rtw_memcpy(psta->rm_en_cap,
+			(elem->rm_en_cap), elem->rm_en_cap_len);
+	}
+}
+
+void RM_IE_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE)
+{
+	int i;
+
+	_rtw_memcpy(&padapter->rmpriv.rm_en_cap_assoc, pIE->data, pIE->Length);
+	RTW_INFO("assoc.rm_en_cap="RM_CAP_FMT"\n", RM_CAP_ARG(pIE->data));
+}
+
+/* Debug command */
+
+#if (RM_SUPPORT_IWPRIV_DBG)
+static int hex2num(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+int hex2byte(const char *hex)
+{
+	int a, b;
+	a = hex2num(*hex++);
+	if (a < 0)
+		return -1;
+	b = hex2num(*hex++);
+	if (b < 0)
+		return -1;
+	return (a << 4) | b;
+}
+
+static char * hwaddr_parse(char *txt, u8 *addr)
+{
+	size_t i;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		int a;
+
+		a = hex2byte(txt);
+		if (a < 0)
+			return NULL;
+		txt += 2;
+		addr[i] = a;
+		if (i < ETH_ALEN - 1 && *txt++ != ':')
+			return NULL;
+	}
+	return txt;
+}
+
+void rm_dbg_list_sta(_adapter *padapter, char *s)
+{
+	int i;
+	_irqL irqL;
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	_list *plist, *phead;
+
+
+	sprintf(pstr(s), "\n");
+	_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+	for (i = 0; i < NUM_STA; i++) {
+		phead = &(pstapriv->sta_hash[i]);
+		plist = get_next(phead);
+
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+			psta = LIST_CONTAINOR(plist,
+				struct sta_info, hash_list);
+
+			plist = get_next(plist);
+
+			sprintf(pstr(s), "=========================================\n");
+			sprintf(pstr(s), "mac=" MAC_FMT "\n",
+				MAC_ARG(psta->cmn.mac_addr));
+			sprintf(pstr(s), "state=0x%x, aid=%d, macid=%d\n",
+				psta->state, psta->cmn.aid, psta->cmn.mac_id);
+			sprintf(pstr(s), "rm_cap="RM_CAP_FMT"\n",
+				RM_CAP_ARG(psta->rm_en_cap));
+		}
+
+	}
+	_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+	sprintf(pstr(s), "=========================================\n");
+}
+
+void rm_dbg_help(_adapter *padapter, char *s)
+{
+	int i;
+
+
+	sprintf(pstr(s), "\n");
+	sprintf(pstr(s), "rrm list_sta\n");
+	sprintf(pstr(s), "rrm list_meas\n");
+
+	sprintf(pstr(s), "rrm add_meas <aid=1|mac=>,m=<bcn|clm|nhm|nb>,rpt=\n");
+	sprintf(pstr(s), "rrm run_meas <aid=1|evid=>\n");
+	sprintf(pstr(s), "rrm del_meas\n");
+
+	sprintf(pstr(s), "rrm run_meas rmid=xxxx,ev=xx\n");
+	sprintf(pstr(s), "rrm activate\n");
+
+	for (i=0;i<RM_EV_max;i++)
+		sprintf(pstr(s), "\t%2d %s\n",i, rm_event_name(i) );
+	sprintf(pstr(s), "\n");
+}
+
+struct sta_info *rm_get_sta(_adapter *padapter, u16 aid, u8* pbssid)
+{
+	int i;
+	_irqL irqL;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	_list *plist, *phead;
+
+
+	_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+	for (i = 0; i < NUM_STA; i++) {
+		phead = &(pstapriv->sta_hash[i]);
+		plist = get_next(phead);
+
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+			psta = LIST_CONTAINOR(plist,
+				struct sta_info, hash_list);
+
+			plist = get_next(plist);
+
+			if (psta->cmn.aid == aid)
+				goto done;
+
+			if (pbssid && _rtw_memcmp(psta->cmn.mac_addr,
+				pbssid, 6))
+				goto done;
+		}
+
+	}
+	psta = NULL;
+done:
+	_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+	return psta;
+}
+
+static int rm_dbg_modify_meas(_adapter *padapter, char *s)
+{
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	struct mlme_ext_info *pmlmeinfo = &padapter->mlmeextpriv.mlmext_info;
+	struct rm_obj *prm;
+	struct sta_info *psta;
+	char *pmac, *ptr, *paid, *prpt, *pnbp, *pclm, *pnhm, *pbcn;
+	unsigned val;
+	u8 bssid[ETH_ALEN];
+
+
+	/* example :
+	* rrm add_meas <aid=1|mac=>,m=<nb|clm|nhm|bcn>,<rept=>
+	* rrm run_meas <aid=1|evid=>
+	*/
+	paid = strstr(s, "aid=");
+	pmac = strstr(s, "mac=");
+	pbcn = strstr(s, "m=bcn");
+	pclm = strstr(s, "m=clm");
+	pnhm = strstr(s, "m=nhm");
+	pnbp = strstr(s, "m=nb");
+	prpt = strstr(s, "rpt=");
+
+	/* set all ',' to NULL (end of line) */
+	ptr = s;
+	while (ptr) {
+		ptr = strchr(ptr, ',');
+		if (ptr) {
+			*(ptr) = 0x0;
+			ptr++;
+		}
+	}
+	prm = (struct rm_obj *)prmpriv->prm_sel;
+	prm->q.m_token = 1;
+	psta = prm->psta;
+
+	if (paid) { /* find sta_info according to aid */
+		paid += 4; /* skip aid= */
+		sscanf(paid, "%u", &val); /* aid=x */
+		psta = rm_get_sta(padapter, val, NULL);
+
+	} else if (pmac) { /* find sta_info according to bssid */
+		pmac += 4; /* skip mac= */
+		if (hwaddr_parse(pmac, bssid) == NULL) {
+			sprintf(pstr(s), "Err: \nincorrect mac format\n");
+			return _FAIL;
+		}
+		psta = rm_get_sta(padapter, 0xff, bssid);
+	}
+
+	if (psta) {
+		prm->psta = psta;
+
+#if 0
+		prm->q.diag_token = psta->rm_diag_token++;
+#else
+		/* TODO dialog should base on sta_info */
+		prm->q.diag_token = pmlmeinfo->dialogToken++;
+#endif
+		prm->rmid = psta->cmn.aid << 16
+			| prm->q.diag_token << 8
+			| RM_MASTER;
+	} else
+		return _FAIL;
+
+	prm->q.action_code = RM_ACT_RADIO_MEAS_REQ;
+	if (pbcn) {
+		prm->q.m_type = bcn_req;
+	} else if (pnhm) {
+		prm->q.m_type = noise_histo_req;
+	} else if (pclm) {
+		prm->q.m_type = ch_load_req;
+	} else if (pnbp) {
+		prm->q.action_code = RM_ACT_NB_REP_REQ;
+	} else
+		return _FAIL;
+
+	if (prpt) {
+		prpt += 4; /* skip rpt= */
+		sscanf(prpt, "%u", &val);
+		prm->q.rpt = (u8)val;
+	}
+
+	return _SUCCESS;
+}
+
+static void rm_dbg_activate_meas(_adapter *padapter, char *s)
+{
+	struct rm_priv *prmpriv = &(padapter->rmpriv);
+	struct rm_obj *prm;
+
+
+	if (prmpriv->prm_sel == NULL) {
+		sprintf(pstr(s), "\nErr: No inActivate measurement\n");
+		return;
+	}
+	prm = (struct rm_obj *)prmpriv->prm_sel;
+
+	/* verify attributes */
+	if (prm->psta == NULL) {
+		sprintf(pstr(s), "\nErr: inActivate meas has no psta\n");
+		return;
+	}
+
+	/* measure current channel */
+	prm->q.ch_num = padapter->mlmeextpriv.cur_channel;
+	prm->q.op_class = rm_get_oper_class_via_ch(prm->q.ch_num);
+
+	/* enquee rmobj */
+	rm_enqueue_rmobj(padapter, prm, _FALSE);
+
+	sprintf(pstr(s), "\nActivate rmid=%x, state=%s, meas_type=%s\n",
+		prm->rmid, rm_state_name(prm->state),
+		rm_type_req_name(prm->q.m_type));
+
+	sprintf(pstr(s), "aid=%d, mac=" MAC_FMT "\n",
+		prm->psta->cmn.aid, MAC_ARG(prm->psta->cmn.mac_addr));
+
+	/* clearn inActivate prm info */
+	prmpriv->prm_sel = NULL;
+}
+
+static void rm_dbg_add_meas(_adapter *padapter, char *s)
+{
+	struct rm_priv *prmpriv = &(padapter->rmpriv);
+	struct rm_obj *prm;
+	char *pact;
+
+
+	/* example :
+	* rrm add_meas <aid=1|mac=>,m=<nb_req|clm_req|nhm_req>
+	* rrm run_meas <aid=1|evid=>
+	*/
+	prm = (struct rm_obj *)prmpriv->prm_sel;
+	if (prm == NULL)
+		prm = rm_alloc_rmobj(padapter);
+
+	if (prm == NULL) {
+		sprintf(pstr(s), "\nErr: alloc meas fail\n");
+		return;
+	}
+
+        prmpriv->prm_sel = prm;
+
+	pact = strstr(s, "act");
+	if (rm_dbg_modify_meas(padapter, s) == _FAIL) {
+
+		sprintf(pstr(s), "\nErr: add meas fail\n");
+		rm_free_rmobj(prm);
+		prmpriv->prm_sel = NULL;
+		return;
+	}
+	prm->q.category = RTW_WLAN_CATEGORY_RADIO_MEAS;
+	prm->q.e_id = _MEAS_REQ_IE_; /* 38 */
+
+	if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ)
+		sprintf(pstr(s), "\nAdd rmid=%x, meas_type=%s ok\n",
+			prm->rmid, rm_type_req_name(prm->q.m_type));
+	else  if (prm->q.action_code == RM_ACT_NB_REP_REQ) 
+		sprintf(pstr(s), "\nAdd rmid=%x, meas_type=bcn_req ok\n",
+			prm->rmid);
+
+	if (prm->psta)
+		sprintf(pstr(s), "mac="MAC_FMT"\n",
+			MAC_ARG(prm->psta->cmn.mac_addr));
+
+	if (pact)
+		rm_dbg_activate_meas(padapter, pstr(s));
+}
+
+static void rm_dbg_del_meas(_adapter *padapter, char *s)
+{
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	struct rm_obj *prm = (struct rm_obj *)prmpriv->prm_sel;
+
+
+	if (prm) {
+		sprintf(pstr(s), "\ndelete rmid=%x\n",prm->rmid);
+
+		/* free inActivate meas - enqueue yet  */
+		prmpriv->prm_sel = NULL;
+		rtw_mfree(prmpriv->prm_sel, sizeof(struct rm_obj));
+	} else
+		sprintf(pstr(s), "Err: no inActivate measurement\n");
+}
+
+static void rm_dbg_run_meas(_adapter *padapter, char *s)
+{
+	struct rm_obj *prm;
+	char *pevid, *prmid;
+	u32 rmid, evid;
+
+
+	prmid = strstr(s, "rmid="); /* hex */
+	pevid = strstr(s, "evid="); /* dec */
+
+	if (prmid && pevid) {
+		prmid += 5; /* rmid= */
+		sscanf(prmid, "%x", &rmid);
+
+		pevid += 5; /* evid= */
+		sscanf(pevid, "%u", &evid);
+	} else {
+		sprintf(pstr(s), "\nErr: incorrect attribute\n");
+		return;
+	}
+
+	prm = rm_get_rmobj(padapter, rmid);
+
+	if (!prm) {
+		sprintf(pstr(s), "\nErr: measurement not found\n");
+		return;
+	}
+
+	if (evid >= RM_EV_max) {
+		sprintf(pstr(s), "\nErr: wrong event id\n");
+		return;
+	}
+
+	rm_post_event(padapter, prm->rmid, evid);
+	sprintf(pstr(s), "\npost %s to rmid=%x\n",rm_event_name(evid), rmid);
+}
+
+static void rm_dbg_show_meas(struct rm_obj *prm, char *s)
+{
+	struct sta_info *psta;
+
+	psta = prm->psta;
+
+	if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ) {
+
+		sprintf(pstr(s), "\nrmid=%x, meas_type=%s\n",
+			prm->rmid, rm_type_req_name(prm->q.m_type));
+
+	} else  if (prm->q.action_code == RM_ACT_NB_REP_REQ) {
+
+		sprintf(pstr(s), "\nrmid=%x, action=neighbor_req\n",
+			prm->rmid);
+	} else
+		sprintf(pstr(s), "\nrmid=%x, action=unknown\n",
+			prm->rmid);
+
+	if (psta)
+		sprintf(pstr(s), "aid=%d, mac="MAC_FMT"\n",
+			psta->cmn.aid, MAC_ARG(psta->cmn.mac_addr));
+
+	sprintf(pstr(s), "clock=%d, state=%s, rpt=%u/%u\n",
+		(int)ATOMIC_READ(&prm->pclock->counter),
+		rm_state_name(prm->state), prm->p.rpt, prm->q.rpt);
+}
+
+static void rm_dbg_list_meas(_adapter *padapter, char *s)
+{
+	int meas_amount;
+	_irqL irqL;
+	struct rm_obj *prm;
+	struct sta_info *psta;
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	_queue *queue = &prmpriv->rm_queue;
+	_list *plist, *phead;
+
+
+	sprintf(pstr(s), "\n");
+	_enter_critical(&queue->lock, &irqL);
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+	meas_amount = 0;
+
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		prm = LIST_CONTAINOR(plist, struct rm_obj, list);
+		meas_amount++;
+		plist = get_next(plist);
+		psta = prm->psta;
+		sprintf(pstr(s), "=========================================\n");
+
+		rm_dbg_show_meas(prm, s);
+	}
+	_exit_critical(&queue->lock, &irqL);
+
+	sprintf(pstr(s), "=========================================\n");
+
+	if (meas_amount==0) {
+		sprintf(pstr(s), "No Activate measurement\n");
+		sprintf(pstr(s), "=========================================\n");
+	}
+
+	if (prmpriv->prm_sel == NULL)
+		sprintf(pstr(s), "\nNo inActivate measurement\n");
+	else {
+		sprintf(pstr(s), "\ninActivate measurement\n");
+		rm_dbg_show_meas((struct rm_obj *)prmpriv->prm_sel, s);
+	}
+}
+#endif /* RM_SUPPORT_IWPRIV_DBG */
+
+void rm_dbg_cmd(_adapter *padapter, char *s)
+{
+	unsigned val;
+	char *paid;
+	struct sta_info *psta=NULL;
+
+#if (RM_SUPPORT_IWPRIV_DBG)
+	if (_rtw_memcmp(s, "help", 4)) {
+		rm_dbg_help(padapter, s);
+
+	} else if (_rtw_memcmp(s, "list_sta", 8)) {
+		rm_dbg_list_sta(padapter, s);
+
+	} else if (_rtw_memcmp(s, "list_meas", 9)) {
+		rm_dbg_list_meas(padapter, s);
+
+	} else if (_rtw_memcmp(s, "add_meas", 8)) {
+		rm_dbg_add_meas(padapter, s);
+
+	} else if (_rtw_memcmp(s, "del_meas", 8)) {
+		rm_dbg_del_meas(padapter, s);
+
+	} else if (_rtw_memcmp(s, "activate", 8)) {
+		rm_dbg_activate_meas(padapter, s);
+
+	} else if (_rtw_memcmp(s, "run_meas", 8)) {
+		rm_dbg_run_meas(padapter, s);
+	} else if (_rtw_memcmp(s, "nb", 2)) {
+
+		paid = strstr(s, "aid=");
+
+		if (paid) { /* find sta_info according to aid */
+			paid += 4; /* skip aid= */
+			sscanf(paid, "%u", &val); /* aid=x */
+			psta = rm_get_sta(padapter, val, NULL);
+
+			if (psta)
+				rm_add_nb_req(padapter, psta);
+		}
+	}
+#else
+	sprintf(pstr(s), "\n");
+	sprintf(pstr(s), "rrm debug command was disabled\n");
+#endif
+}
+#endif /* CONFIG_RTW_80211K */

+ 998 - 0
core/rtw_rm_fsm.c

@@ -0,0 +1,998 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+
+#include <drv_types.h>
+#include <hal_data.h>
+#include "rtw_rm_fsm.h"
+
+#ifdef CONFIG_RTW_80211K
+
+struct fsm_state {
+	u8 *name;
+	int(*fsm_func)(struct rm_obj *prm, enum RM_EV_ID evid);
+};
+
+static void rm_state_initial(struct rm_obj *prm);
+static void rm_state_goto(struct rm_obj *prm, enum RM_STATE rm_state);
+static void rm_state_run(struct rm_obj *prm, enum RM_EV_ID evid);
+static struct rm_event *rm_dequeue_ev(_queue *queue);
+static struct rm_obj *rm_dequeue_rm(_queue *queue);
+
+void rm_timer_callback(void *data)
+{
+	int i;
+	_adapter *padapter = (_adapter *)data;
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	struct rm_clock *pclock;
+
+
+	/* deal with clock */
+	for (i=0;i<RM_TIMER_NUM;i++) {
+		pclock = &prmpriv->clock[i];
+		if (pclock->prm == NULL
+			||(ATOMIC_READ(&(pclock->counter)) == 0))
+			continue;
+
+		ATOMIC_DEC(&(pclock->counter));
+
+		if (ATOMIC_READ(&(pclock->counter)) == 0)
+			rm_post_event(pclock->prm->psta->padapter,
+				pclock->prm->rmid, prmpriv->clock[i].evid);
+	}
+	_set_timer(&prmpriv->rm_timer, CLOCK_UNIT);
+}
+
+int rtw_init_rm(_adapter *padapter)
+{
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+
+
+	RTW_INFO("RM: %s\n",__func__);
+	_rtw_init_queue(&(prmpriv->rm_queue));
+	_rtw_init_queue(&(prmpriv->ev_queue));
+
+	/* bit 0-7 */
+	prmpriv->rm_en_cap_def[0] = 0
+		/*| BIT(RM_LINK_MEAS_CAP_EN)*/
+		| BIT(RM_NB_REP_CAP_EN)
+		/*| BIT(RM_PARAL_MEAS_CAP_EN)*/
+		| BIT(RM_REPEAT_MEAS_CAP_EN)
+		| BIT(RM_BCN_PASSIVE_MEAS_CAP_EN)
+		| BIT(RM_BCN_ACTIVE_MEAS_CAP_EN)
+		| BIT(RM_BCN_TABLE_MEAS_CAP_EN)
+		/*| BIT(RM_BCN_MEAS_REP_COND_CAP_EN)*/;
+
+	/* bit  8-15 */
+	prmpriv->rm_en_cap_def[1] = 0
+		/*| BIT(RM_FRAME_MEAS_CAP_EN - 8)*/
+#ifdef CONFIG_RTW_ACS
+		| BIT(RM_CH_LOAD_CAP_EN - 8)
+		| BIT(RM_NOISE_HISTO_CAP_EN - 8)
+#endif
+		/*| BIT(RM_STATIS_MEAS_CAP_EN - 8)*/
+		/*| BIT(RM_LCI_MEAS_CAP_EN - 8)*/
+		/*| BIT(RM_LCI_AMIMUTH_CAP_EN - 8)*/
+		/*| BIT(RM_TRANS_STREAM_CAT_MEAS_CAP_EN - 8)*/
+		/*| BIT(RM_TRIG_TRANS_STREAM_CAT_MEAS_CAP_EN - 8)*/;
+
+	/* bit 16-23 */
+	prmpriv->rm_en_cap_def[2] = 0
+		/*| BIT(RM_AP_CH_REP_CAP_EN - 16)*/
+		/*| BIT(RM_RM_MIB_CAP_EN - 16)*/
+		/*| BIT(RM_OP_CH_MAX_MEAS_DUR0 - 16)*/
+		/*| BIT(RM_OP_CH_MAX_MEAS_DUR1 - 16)*/
+		/*| BIT(RM_OP_CH_MAX_MEAS_DUR2 - 16)*/
+		/*| BIT(RM_NONOP_CH_MAX_MEAS_DUR0 - 16)*/
+		/*| BIT(RM_NONOP_CH_MAX_MEAS_DUR1 - 16)*/
+		/*| BIT(RM_NONOP_CH_MAX_MEAS_DUR2 - 16)*/;
+
+	/* bit 24-31 */
+	prmpriv->rm_en_cap_def[3] = 0
+		/*| BIT(RM_MEAS_PILOT_CAP0 - 24)*/
+		/*| BIT(RM_MEAS_PILOT_CAP1 - 24)*/
+		/*| BIT(RM_MEAS_PILOT_CAP2 - 24)*/
+		/*| BIT(RM_MEAS_PILOT_TRANS_INFO_CAP_EN - 24)*/
+		/*| BIT(RM_NB_REP_TSF_OFFSET_CAP_EN - 24)*/
+		| BIT(RM_RCPI_MEAS_CAP_EN - 24)
+		| BIT(RM_RSNI_MEAS_CAP_EN - 24)
+		/*| BIT(RM_BSS_AVG_ACCESS_DELAY_CAP_EN - 24)*/;
+
+	/* bit 32-39 */
+	prmpriv->rm_en_cap_def[4] = 0
+		/*| BIT(RM_BSS_AVG_ACCESS_DELAY_CAP_EN - 32)*/
+		/*| BIT(RM_AVALB_ADMIS_CAPACITY_CAP_EN - 32)*/
+		/*| BIT(RM_ANT_CAP_EN - 32)*/;
+
+	prmpriv->enable = _TRUE;
+
+	/* clock timer */
+	rtw_init_timer(&prmpriv->rm_timer,
+		padapter, rm_timer_callback, padapter);
+	_set_timer(&prmpriv->rm_timer, CLOCK_UNIT);
+
+	return _SUCCESS;
+}
+
+int rtw_deinit_rm(_adapter *padapter)
+{
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	struct rm_obj *prm;
+	struct rm_event *pev;
+
+
+	RTW_INFO("RM: %s\n",__func__);
+	prmpriv->enable = _FALSE;
+	_cancel_timer_ex(&prmpriv->rm_timer);
+
+	/* free all events and measurements */
+	while((pev = rm_dequeue_ev(&prmpriv->ev_queue)) != NULL)
+		rtw_mfree((void *)pev, sizeof(struct rm_event));
+
+	while((prm = rm_dequeue_rm(&prmpriv->rm_queue)) != NULL)
+		rm_state_run(prm, RM_EV_cancel);
+
+	_rtw_deinit_queue(&(prmpriv->rm_queue));
+	_rtw_deinit_queue(&(prmpriv->ev_queue));
+
+	return _SUCCESS;
+}
+
+int rtw_free_rm_priv(_adapter *padapter)
+{
+	return rtw_deinit_rm(padapter);
+}
+
+static int rm_enqueue_ev(_queue *queue, struct rm_event *obj, bool to_head)
+{
+	_irqL irqL;
+
+
+	if (obj == NULL)
+		return _FAIL;
+
+	_enter_critical(&queue->lock, &irqL);
+
+	if (to_head)
+		rtw_list_insert_head(&obj->list, &queue->queue);
+	else
+		rtw_list_insert_tail(&obj->list, &queue->queue);
+
+	_exit_critical(&queue->lock, &irqL);
+
+	return _SUCCESS;
+}
+
+static void rm_set_clock(struct rm_obj *prm, u32 ms, enum RM_EV_ID evid)
+{
+	ATOMIC_SET(&(prm->pclock->counter), (ms/CLOCK_UNIT));
+	prm->pclock->evid = evid;
+}
+
+static struct rm_clock *rm_alloc_clock(_adapter *padapter, struct rm_obj *prm)
+{
+	int i;
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	struct rm_clock *pclock = NULL;
+
+
+	for (i=0;i<RM_TIMER_NUM;i++) {
+		pclock = &prmpriv->clock[i];
+
+		if (pclock->prm == NULL) {
+			pclock->prm = prm;
+			ATOMIC_SET(&(pclock->counter), 0);
+			pclock->evid = RM_EV_max;
+			break;
+		}
+	}
+	return pclock;
+}
+
+static void rm_cancel_clock(struct rm_obj *prm)
+{
+	ATOMIC_SET(&(prm->pclock->counter), 0);
+	prm->pclock->evid = RM_EV_max;
+}
+
+static void rm_free_clock(struct rm_clock *pclock)
+{
+	pclock->prm = NULL;
+	ATOMIC_SET(&(pclock->counter), 0);
+	pclock->evid = RM_EV_max;
+}
+
+static int is_list_linked(const struct list_head *head)
+{
+	return head->prev != NULL;
+}
+
+void rm_free_rmobj(struct rm_obj *prm)
+{
+	if (is_list_linked(&prm->list))
+		rtw_list_delete(&prm->list);
+
+	if (prm->q.pssid)
+		rtw_mfree(prm->q.pssid, strlen(prm->q.pssid)+1);
+
+	if (prm->q.opt.bcn.req_start)
+		rtw_mfree(prm->q.opt.bcn.req_start,
+			prm->q.opt.bcn.req_len);
+
+	if (prm->pclock)
+		rm_free_clock(prm->pclock);
+
+	rtw_mfree((void *)prm, sizeof(struct rm_obj));
+}
+
+struct rm_obj *rm_alloc_rmobj(_adapter *padapter)
+{
+	struct rm_obj *prm;
+
+
+	prm = (struct rm_obj *)rtw_malloc(sizeof(struct rm_obj));
+	if (prm == NULL)
+		return NULL;
+
+	_rtw_memset(prm, 0, sizeof(struct rm_obj));
+
+	/* alloc timer */
+	if ((prm->pclock = rm_alloc_clock(padapter, prm)) == NULL) {
+		rm_free_rmobj(prm);
+		return NULL;
+	}
+	return prm;
+}
+
+int rm_enqueue_rmobj(_adapter *padapter, struct rm_obj *prm, bool to_head)
+{
+	_irqL irqL;
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	_queue *queue = &prmpriv->rm_queue;
+
+
+	if (prm == NULL)
+		return _FAIL;
+
+	_enter_critical(&queue->lock, &irqL);
+	if (to_head)
+		rtw_list_insert_head(&prm->list, &queue->queue);
+	else
+		rtw_list_insert_tail(&prm->list, &queue->queue);
+	_exit_critical(&queue->lock, &irqL);
+
+	rm_state_initial(prm);
+
+	return _SUCCESS;
+}
+
+static struct rm_obj *rm_dequeue_rm(_queue *queue)
+{
+	_irqL irqL;
+	struct rm_obj *prm;
+
+
+	_enter_critical(&queue->lock, &irqL);
+	if (rtw_is_list_empty(&(queue->queue)))
+		prm = NULL;
+	else {
+		prm = LIST_CONTAINOR(get_next(&(queue->queue)),
+			struct rm_obj, list);
+		/* rtw_list_delete(&prm->list); */
+	}
+	_exit_critical(&queue->lock, &irqL);
+
+	return prm;
+}
+
+static struct rm_event *rm_dequeue_ev(_queue *queue)
+{
+	_irqL irqL;
+	struct rm_event *ev;
+
+
+	_enter_critical(&queue->lock, &irqL);
+	if (rtw_is_list_empty(&(queue->queue)))
+		ev = NULL;
+	else {
+		ev = LIST_CONTAINOR(get_next(&(queue->queue)),
+			struct rm_event, list);
+		rtw_list_delete(&ev->list);
+	}
+	_exit_critical(&queue->lock, &irqL);
+
+	return ev;
+}
+
+static struct rm_obj *_rm_get_rmobj(_queue *queue, u32 rmid)
+{
+	_irqL irqL;
+	_list *phead, *plist;
+	struct rm_obj *prm = NULL;
+
+
+	if (rmid == 0)
+		return NULL;
+
+	_enter_critical(&queue->lock, &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+
+		prm = LIST_CONTAINOR(plist, struct rm_obj, list);
+		if (rmid == (prm->rmid)) {
+			_exit_critical(&queue->lock, &irqL);
+			return prm;
+		}
+		plist = get_next(plist);
+	}
+	_exit_critical(&queue->lock, &irqL);
+
+	return NULL;
+}
+
+struct sta_info *rm_get_psta(_adapter *padapter, u32 rmid)
+{
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	struct rm_obj *prm;
+
+
+	prm = _rm_get_rmobj(&prmpriv->rm_queue, rmid);
+
+	if (prm)
+		return prm->psta;
+
+	return NULL;
+}
+
+struct rm_obj *rm_get_rmobj(_adapter *padapter, u32 rmid)
+{
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+
+	return _rm_get_rmobj(&prmpriv->rm_queue, rmid);
+}
+
+u8 rtw_rm_post_envent_cmd(_adapter *padapter, u32 rmid, u8 evid)
+{
+	struct cmd_obj *pcmd;
+	struct rm_event *pev;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8 res = _SUCCESS;
+
+
+	pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	pev = (struct rm_event*)rtw_zmalloc(sizeof(struct rm_event));
+
+	if (pev == NULL) {
+		rtw_mfree((u8 *) pcmd, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+	pev->rmid = rmid;
+	pev->evid = evid;
+
+	init_h2fwcmd_w_parm_no_rsp(pcmd, pev, GEN_CMD_CODE(_RM_POST_EVENT));
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+	return res;
+}
+
+int rm_post_event(_adapter *padapter, u32 rmid, enum RM_EV_ID evid)
+{
+	if (padapter->rmpriv.enable == _FALSE)
+		return _FALSE;
+
+	RTW_INFO("RM: post asyn %s to rmid=%x\n", rm_event_name(evid), rmid);
+	rtw_rm_post_envent_cmd(padapter, rmid, evid);
+	return _SUCCESS;
+}
+
+int _rm_post_event(_adapter *padapter, u32 rmid, enum RM_EV_ID evid)
+{
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	struct rm_event *pev;
+
+	if (evid >= RM_EV_max || rmid == 0)
+		return _FALSE;
+
+	pev = (struct rm_event *)rtw_malloc(sizeof(struct rm_event));
+	if (pev == NULL)
+		return _FALSE;
+
+	pev->rmid = rmid;
+	pev->evid = evid;
+
+	RTW_INFO("RM: post sync %s to rmid=%x\n", rm_event_name(evid), rmid);
+	rm_enqueue_ev(&prmpriv->ev_queue, pev, FALSE);
+
+	return _SUCCESS;
+}
+
+static void rm_bcast_aid_handler(_adapter *padapter, struct rm_event *pev)
+{
+	_irqL irqL;
+	_list *phead, *plist;
+	_queue *queue = &padapter->rmpriv.rm_queue;
+	struct rm_obj *prm;
+
+
+	_enter_critical(&queue->lock, &irqL);
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+
+		prm = LIST_CONTAINOR(plist, struct rm_obj, list);
+		plist = get_next(plist);
+		if (RM_GET_AID(pev->rmid) == RM_GET_AID(prm->rmid)) {
+			_exit_critical(&queue->lock, &irqL);
+			rm_state_run(prm, pev->evid);
+			_enter_critical(&queue->lock, &irqL);
+		}
+	}
+	_exit_critical(&queue->lock, &irqL);
+	return;
+}
+
+/* main handler of RM (Resource Management) */
+void rm_handler(_adapter *padapter, struct rm_event *pe)
+{
+	int i;
+	struct rm_priv *prmpriv = &padapter->rmpriv;
+	struct rm_obj *prm;
+	struct rm_event *pev;
+
+
+	/* dequeue event */
+	while((pev = rm_dequeue_ev(&prmpriv->ev_queue)) != NULL)
+	{
+		if (RM_IS_ID_FOR_ALL(pev->rmid)) {
+			/* apply to all aid mateched measurement */
+			rm_bcast_aid_handler(padapter, pev);
+			rtw_mfree((void *)pev, sizeof(struct rm_event));
+			continue;
+		}
+
+		/* retrieve rmobj */
+		prm = _rm_get_rmobj(&prmpriv->rm_queue, pev->rmid);
+		if (prm == NULL) {
+			RTW_ERR("RM: rmid=%x event=%s doesn't find rm obj\n",
+				pev->rmid, rm_event_name(pev->evid));
+			rtw_mfree((void *)pev, sizeof(struct rm_event));
+			return;
+		}
+		/* run state machine */
+		rm_state_run(prm, pev->evid);
+		rtw_mfree((void *)pev, sizeof(struct rm_event));
+	}
+}
+
+static int rm_issue_meas_req(struct rm_obj *prm)
+{
+	switch (prm->q.action_code) {
+	case RM_ACT_RADIO_MEAS_REQ:
+		switch (prm->q.m_type) {
+		case bcn_req:
+		case ch_load_req:
+		case noise_histo_req:
+			issue_radio_meas_req(prm);
+			break;
+		default:
+			break;
+		} /* meas_type */
+		break;
+	case RM_ACT_NB_REP_REQ:
+		/* issue neighbor request */
+		issue_nb_req(prm);
+		break;
+	case RM_ACT_LINK_MEAS_REQ:
+	default:
+		return _FALSE;
+	} /* action_code */
+
+	return _SUCCESS;
+}
+
+/*
+* RM state machine
+*/
+
+static int rm_state_idle(struct rm_obj *prm, enum RM_EV_ID evid)
+{
+	_adapter *padapter = prm->psta->padapter;
+	u8 val8;
+	u32 val32;
+
+
+	prm->p.category = RTW_WLAN_CATEGORY_RADIO_MEAS;
+
+	switch (evid) {
+	case RM_EV_state_in:
+		switch (prm->q.action_code) {
+		case RM_ACT_RADIO_MEAS_REQ:
+			/* copy attrib from meas_req to meas_rep */
+			prm->p.action_code = RM_ACT_RADIO_MEAS_REP;
+			prm->p.diag_token = prm->q.diag_token;
+			prm->p.e_id = _MEAS_RSP_IE_;
+			prm->p.m_token = prm->q.m_token;
+			prm->p.m_type = prm->q.m_type;
+			prm->p.rpt = prm->q.rpt;
+			prm->p.ch_num = prm->q.ch_num;
+			prm->p.op_class = prm->q.op_class;
+
+			if (prm->q.m_type == ch_load_req
+				|| prm->q.m_type == noise_histo_req) {
+				/*
+				 * phydm measure current ch periodically
+				 * scan current ch is not necessary
+				 */
+				val8 = padapter->mlmeextpriv.cur_channel;
+				if (prm->q.ch_num == val8)
+					prm->poll_mode = 1;
+			}
+			RTW_INFO("RM: rmid=%x %s switch in repeat=%u\n",
+				prm->rmid, rm_type_req_name(prm->q.m_type),
+				prm->q.rpt);
+			break;
+		case RM_ACT_NB_REP_REQ:
+			prm->p.action_code = RM_ACT_NB_REP_RESP;
+			RTW_INFO("RM: rmid=%x Neighbor request switch in\n",
+				prm->rmid);
+			break;
+		case RM_ACT_LINK_MEAS_REQ:
+			prm->p.action_code = RM_ACT_LINK_MEAS_REP;
+			rm_set_rep_mode(prm, MEAS_REP_MOD_INCAP);
+			RTW_INFO("RM: rmid=%x Link meas switch in\n",
+				prm->rmid);
+			break;
+		default:
+			prm->p.action_code = prm->q.action_code;
+			rm_set_rep_mode(prm, MEAS_REP_MOD_INCAP);
+			RTW_INFO("RM: rmid=%x recv unknown action %d\n",
+				prm->rmid,prm->p.action_code);
+			break;
+		} /* switch() */
+
+		if (prm->rmid & RM_MASTER) {
+			if (rm_issue_meas_req(prm) == _SUCCESS)
+				rm_state_goto(prm, RM_ST_WAIT_MEAS);
+			else
+				rm_state_goto(prm, RM_ST_END);
+			return _SUCCESS;
+		} else {
+			rm_state_goto(prm, RM_ST_DO_MEAS);
+			return _SUCCESS;
+		}
+
+		if (prm->p.m_mode) {
+			issue_null_reply(prm);
+			rm_state_goto(prm, RM_ST_END);
+			return _SUCCESS;
+		}
+		if (prm->q.rand_intvl) {
+			/* get low tsf to generate random interval */
+			val32 = rtw_read32(padapter, REG_TSFTR);
+			val32 = val32 % prm->q.rand_intvl;
+			RTW_INFO("RM: rmid=%x rand_intval=%d, rand=%d\n",
+				prm->rmid, (int)prm->q.rand_intvl,val32);
+			rm_set_clock(prm, prm->q.rand_intvl,
+				RM_EV_delay_timer_expire);
+			return _SUCCESS;
+		}
+		break;
+	case RM_EV_delay_timer_expire:
+		rm_state_goto(prm, RM_ST_DO_MEAS);
+		break;
+	case RM_EV_cancel:
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_state_out:
+		rm_cancel_clock(prm);
+		break;
+	default:
+		break;
+	}
+	return _SUCCESS;
+}
+
+/* we do the measuring */
+static int rm_state_do_meas(struct rm_obj *prm, enum RM_EV_ID evid)
+{
+	_adapter *padapter = prm->psta->padapter;
+	u8 val8;
+	u64 val64;
+
+
+	switch (evid) {
+	case RM_EV_state_in:
+		if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ) {
+			switch (prm->q.m_type) {
+			case bcn_req:
+				if (prm->q.m_mode == bcn_req_bcn_table) {
+					RTW_INFO("RM: rmid=%x Beacon table\n",
+						prm->rmid);
+					_rm_post_event(padapter, prm->rmid,
+						RM_EV_survey_done);
+					return _SUCCESS;
+				}
+				break;
+			case ch_load_req:
+			case noise_histo_req:
+				if (prm->poll_mode)
+					_rm_post_event(padapter, prm->rmid,
+						RM_EV_survey_done);
+				return _SUCCESS;
+			default:
+				rm_state_goto(prm, RM_ST_END);
+				return _SUCCESS;
+			}
+
+			if (!ready_for_scan(prm)) {
+				prm->wait_busy = RM_BUSY_TRAFFIC_TIMES;
+				RTW_INFO("RM: wait busy traffic - %d\n",
+					prm->wait_busy);
+				rm_set_clock(prm, RM_WAIT_BUSY_TIMEOUT,
+					RM_EV_busy_timer_expire);
+				return _SUCCESS;
+			}
+		}
+		_rm_post_event(padapter, prm->rmid, RM_EV_start_meas);
+		break;
+	case RM_EV_start_meas:
+		if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ) {
+			/* resotre measurement start time */
+			prm->meas_start_time = rtw_hal_get_tsftr_by_port(padapter
+									, rtw_hal_get_port(padapter));
+
+			switch (prm->q.m_type) {
+			case bcn_req:
+				val8 = 1; /* Enable free run counter */
+				rtw_hal_set_hwreg(padapter,
+					HW_VAR_FREECNT, &val8);
+				rm_sitesurvey(prm);
+				break;
+			case ch_load_req:
+			case noise_histo_req:
+				rm_sitesurvey(prm);
+				break;
+			default:
+				rm_state_goto(prm, RM_ST_END);
+				return _SUCCESS;
+				break;
+			}
+		}
+		/* handle measurement timeout */
+		rm_set_clock(prm, RM_MEAS_TIMEOUT, RM_EV_meas_timer_expire);
+		break;
+	case RM_EV_survey_done:
+		if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ) {
+			switch (prm->q.m_type) {
+			case bcn_req:
+				rm_cancel_clock(prm);
+				rm_state_goto(prm, RM_ST_SEND_REPORT);
+				return _SUCCESS;
+			case ch_load_req:
+			case noise_histo_req:
+				retrieve_radio_meas_result(prm);
+
+				if (rm_radio_meas_report_cond(prm) == _SUCCESS)
+					rm_state_goto(prm, RM_ST_SEND_REPORT);
+				else
+					rm_set_clock(prm, RM_COND_INTVL,
+						RM_EV_retry_timer_expire);
+				break;
+			default:
+				rm_state_goto(prm, RM_ST_END);
+				return _SUCCESS;
+			}
+		}
+		break;
+	case RM_EV_meas_timer_expire:
+		RTW_INFO("RM: rmid=%x measurement timeount\n",prm->rmid);
+		rm_set_rep_mode(prm, MEAS_REP_MOD_REFUSE);
+		issue_null_reply(prm);
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_busy_timer_expire:
+		if (!ready_for_scan(prm) && prm->wait_busy--) {
+			RTW_INFO("RM: wait busy - %d\n",prm->wait_busy);
+			rm_set_clock(prm, RM_WAIT_BUSY_TIMEOUT,
+				RM_EV_busy_timer_expire);
+			break;
+		}
+		else if (prm->wait_busy <= 0) {
+			RTW_INFO("RM: wait busy timeout\n");
+			rm_set_rep_mode(prm, MEAS_REP_MOD_REFUSE);
+			issue_null_reply(prm);
+			rm_state_goto(prm, RM_ST_END);
+			return _SUCCESS;
+		}
+		_rm_post_event(padapter, prm->rmid, RM_EV_start_meas);
+		break;
+	case RM_EV_request_timer_expire:
+		rm_set_rep_mode(prm, MEAS_REP_MOD_REFUSE);
+		issue_null_reply(prm);
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_retry_timer_expire:
+		/* expired due to meas condition mismatch, meas again */
+		_rm_post_event(padapter, prm->rmid, RM_EV_start_meas);
+		break;
+	case RM_EV_cancel:
+		rm_set_rep_mode(prm, MEAS_REP_MOD_REFUSE);
+		issue_null_reply(prm);
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_state_out:
+		rm_cancel_clock(prm);
+		/* resotre measurement end time */
+		prm->meas_end_time = rtw_hal_get_tsftr_by_port(padapter
+								, rtw_hal_get_port(padapter));
+
+		val8 = 0; /* Disable free run counter */
+		rtw_hal_set_hwreg(padapter, HW_VAR_FREECNT, &val8);
+		break;
+	default:
+		break;
+	}
+
+	return _SUCCESS;
+}
+
+static int rm_state_wait_meas(struct rm_obj *prm, enum RM_EV_ID evid)
+{
+	u8 val8;
+	u64 val64;
+
+
+	switch (evid) {
+	case RM_EV_state_in:
+		/* we create meas_req, waiting for peer report */
+		rm_set_clock(prm, RM_REQ_TIMEOUT,
+			RM_EV_request_timer_expire);
+		break;
+	case RM_EV_recv_rep:
+		rm_state_goto(prm, RM_ST_RECV_REPORT);
+		break;
+	case RM_EV_request_timer_expire:
+	case RM_EV_cancel:
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_state_out:
+		rm_cancel_clock(prm);
+		break;
+	default:
+		break;
+	}
+	return _SUCCESS;
+}
+
+static int rm_state_send_report(struct rm_obj *prm, enum RM_EV_ID evid)
+{
+	u8 val8;
+
+
+	switch (evid) {
+	case RM_EV_state_in:
+		/* we have to issue report */
+		switch (prm->q.m_type) {
+		case bcn_req:
+			issue_beacon_rep(prm);
+			break;
+		case ch_load_req:
+		case noise_histo_req:
+			issue_radio_meas_rep(prm);
+			break;
+		default:
+			rm_state_goto(prm, RM_ST_END);
+			return _SUCCESS;
+		}
+
+		/* check repeat */
+		if (prm->p.rpt) {
+			RTW_INFO("RM: rmid=%x repeat=%u/%u\n",
+				prm->rmid, prm->p.rpt,
+				prm->q.rpt);
+			prm->p.rpt--;
+			/*
+			* we recv meas_req,
+			* delay for a wihile and than meas again
+			*/
+			if (prm->poll_mode)
+				rm_set_clock(prm, RM_REPT_POLL_INTVL,
+					RM_EV_repeat_delay_expire);
+			else
+				rm_set_clock(prm, RM_REPT_SCAN_INTVL,
+					RM_EV_repeat_delay_expire);
+			return _SUCCESS;
+		}
+		/* we are done */
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_repeat_delay_expire:
+		rm_state_goto(prm, RM_ST_DO_MEAS);
+		break;
+	case RM_EV_cancel:
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_state_out:
+		rm_cancel_clock(prm);
+		break;
+	default:
+		break;
+	}
+	return _SUCCESS;
+}
+
+static int rm_state_recv_report(struct rm_obj *prm, enum RM_EV_ID evid)
+{
+	u8 val8;
+
+
+	switch (evid) {
+	case RM_EV_state_in:
+		/* we issue meas_req, got peer's meas report */
+		switch (prm->p.action_code) {
+		case RM_ACT_RADIO_MEAS_REP:
+			/* check refuse, incapable and repeat */
+			val8 = prm->p.m_mode;
+			if (val8) {
+				RTW_INFO("RM: rmid=%x peer reject (%s repeat=%d)\n",
+					prm->rmid,
+					val8|MEAS_REP_MOD_INCAP?"INCAP":
+					val8|MEAS_REP_MOD_REFUSE?"REFUSE":
+					val8|MEAS_REP_MOD_LATE?"LATE":"",
+					prm->p.rpt);
+				rm_state_goto(prm, RM_ST_END);
+				return _SUCCESS;
+			}
+			break;
+		case RM_ACT_NB_REP_RESP:
+			/* report to upper layer if needing */
+			rm_state_goto(prm, RM_ST_END);
+			return _SUCCESS;
+		default:
+			rm_state_goto(prm, RM_ST_END);
+			return _SUCCESS;
+		}
+		/* check repeat */
+		if (prm->p.rpt) {
+			RTW_INFO("RM: rmid=%x repeat=%u/%u\n",
+				prm->rmid, prm->p.rpt,
+				prm->q.rpt);
+			prm->p.rpt--;
+			/* waitting more report */
+			rm_state_goto(prm, RM_ST_WAIT_MEAS);
+			break;
+		}
+		/* we are done */
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_cancel:
+		rm_state_goto(prm, RM_ST_END);
+		break;
+	case RM_EV_state_out:
+		rm_cancel_clock(prm);
+		break;
+	default:
+		break;
+	}
+	return _SUCCESS;
+}
+
+static int rm_state_end(struct rm_obj *prm, enum RM_EV_ID evid)
+{
+	switch (evid) {
+	case RM_EV_state_in:
+		_rm_post_event(prm->psta->padapter, prm->rmid, RM_EV_state_out);
+		break;
+
+	case RM_EV_cancel:
+	case RM_EV_state_out:
+	default:
+		rm_free_rmobj(prm);
+		break;
+	}
+	return _SUCCESS;
+}
+
+struct fsm_state rm_fsm[] = {
+	{"RM_ST_IDLE",		rm_state_idle},
+	{"RM_ST_DO_MEAS",	rm_state_do_meas},
+	{"RM_ST_WAIT_MEAS", 	rm_state_wait_meas},
+	{"RM_ST_SEND_REPORT", 	rm_state_send_report},
+	{"RM_ST_RECV_REPORT", 	rm_state_recv_report},
+	{"RM_ST_END", 		rm_state_end}
+};
+
+char *rm_state_name(enum RM_STATE state)
+{
+	return rm_fsm[state].name;
+}
+
+char *rm_event_name(enum RM_EV_ID evid)
+{
+	switch(evid) {
+	case RM_EV_state_in:
+		return "RM_EV_state_in";
+	case RM_EV_busy_timer_expire:
+		return "RM_EV_busy_timer_expire";
+	case RM_EV_delay_timer_expire:
+		return "RM_EV_delay_timer_expire";
+	case RM_EV_meas_timer_expire:
+		return "RM_EV_meas_timer_expire";
+	case RM_EV_repeat_delay_expire:
+		return "RM_EV_repeat_delay_expire";
+	case RM_EV_retry_timer_expire:
+		return "RM_EV_retry_timer_expire";
+	case RM_EV_request_timer_expire:
+		return "RM_EV_request_timer_expire";
+	case RM_EV_wait_report:
+		return "RM_EV_wait_report";
+	case RM_EV_start_meas:
+		return "RM_EV_start_meas";
+	case RM_EV_survey_done:
+		return "RM_EV_survey_done";
+	case RM_EV_recv_rep:
+		return "RM_EV_recv_report";
+	case RM_EV_cancel:
+		return "RM_EV_cancel";
+	case RM_EV_state_out:
+		return "RM_EV_state_out";
+	case RM_EV_max:
+		return "RM_EV_max";
+	default:
+		return "RM_EV_unknown";
+	}
+	return "UNKNOWN";
+}
+
+static void rm_state_initial(struct rm_obj *prm)
+{
+	prm->state = RM_ST_IDLE;
+
+	RTW_INFO("\n");
+	RTW_INFO("RM: rmid=%x %-18s -> %s\n",prm->rmid,
+		"new measurement", rm_fsm[prm->state].name);
+
+	rm_post_event(prm->psta->padapter, prm->rmid, RM_EV_state_in);
+}
+
+static void rm_state_run(struct rm_obj *prm, enum RM_EV_ID evid)
+{
+	RTW_INFO("RM: rmid=%x %-18s    %s\n",prm->rmid,
+		rm_fsm[prm->state].name,rm_event_name(evid));
+
+	rm_fsm[prm->state].fsm_func(prm, evid);
+}
+
+static void rm_state_goto(struct rm_obj *prm, enum RM_STATE rm_state)
+{
+	if (prm->state == rm_state)
+		return;
+
+	rm_state_run(prm, RM_EV_state_out);
+
+	RTW_INFO("\n");
+	RTW_INFO("RM: rmid=%x %-18s -> %s\n",prm->rmid,
+		rm_fsm[prm->state].name, rm_fsm[rm_state].name);
+
+	prm->state = rm_state;
+	rm_state_run(prm, RM_EV_state_in);
+}
+#endif /* CONFIG_RTW_80211K */

+ 595 - 0
core/rtw_rson.c

@@ -0,0 +1,595 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_RSON_C_
+
+#include <drv_types.h>
+
+#ifdef CONFIG_RTW_REPEATER_SON
+
+/********	Custommize Part	***********************/
+
+unsigned char	RTW_RSON_OUI[] = {0xFA, 0xFA, 0xFA};
+#define RSON_SCORE_DIFF_TH				8
+
+/*
+	Calculate the corresponding score.
+*/
+inline u8 rtw_cal_rson_score(struct rtw_rson_struct *cand_rson_data, NDIS_802_11_RSSI  Rssi)
+{
+	if ((cand_rson_data->hopcnt == RTW_RSON_HC_NOTREADY)
+		|| (cand_rson_data->connectible == RTW_RSON_DENYCONNECT))
+		return RTW_RSON_SCORE_NOTCNNT;
+
+	return RTW_RSON_SCORE_MAX - (cand_rson_data->hopcnt * 10) + (Rssi/10);
+}
+
+/*************************************************/
+
+
+static u8 rtw_rson_block_bssid_idx = 0;
+u8 rtw_rson_block_bssid[10][6] = {
+			/*{0x02, 0xE0, 0x4C, 0x07, 0xC3, 0xF6}*/
+};
+
+/* fake root, regard a real AP as a SO root */
+static u8 rtw_rson_root_bssid_idx = 0;
+u8 rtw_rson_root_bssid[10][6] = {
+			/*{0x1c, 0x5f, 0x2b, 0x5a, 0x60, 0x24}*/
+};
+
+int is_match_bssid(u8 *mac, u8 bssid_array[][6], int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++)
+		if (_rtw_memcmp(mac, bssid_array[i], 6) == _TRUE)
+			return _TRUE;
+	return _FALSE;
+}
+
+void init_rtw_rson_data(struct dvobj_priv *dvobj)
+{
+	/*Aries  todo.  if pdvobj->rson_data.ver == 1 */
+	dvobj->rson_data.ver = RTW_RSON_VER;
+	dvobj->rson_data.id = CONFIG_RTW_REPEATER_SON_ID;
+#ifdef CONFIG_RTW_REPEATER_SON_ROOT
+	dvobj->rson_data.hopcnt = RTW_RSON_HC_ROOT;
+	dvobj->rson_data.connectible = RTW_RSON_ALLOWCONNECT;
+#else
+	dvobj->rson_data.hopcnt = RTW_RSON_HC_NOTREADY;
+	dvobj->rson_data.connectible = RTW_RSON_DENYCONNECT;
+#endif
+	dvobj->rson_data.loading = 0;
+	_rtw_memset(dvobj->rson_data.res, 0xAA, sizeof(dvobj->rson_data.res));
+}
+
+void	rtw_rson_get_property_str(_adapter *padapter, char *rson_data_str)
+{
+	struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+
+	sprintf(rson_data_str, "version : \t%d\nid : \t\t%08x\nhop count : \t%d\nconnectible : \t%s\nloading : \t%d\nreserve : \t%16ph\n",
+		pdvobj->rson_data.ver,
+		pdvobj->rson_data.id,
+		pdvobj->rson_data.hopcnt,
+		pdvobj->rson_data.connectible ? "connectable":"unconnectable",
+		pdvobj->rson_data.loading,
+		pdvobj->rson_data.res);
+}
+
+int str2hexbuf(char *str, u8 *hexbuf, int len)
+{
+	u8 *p;
+	int i, slen, idx = 0;
+
+	p = (unsigned char *)str;
+	if ((*p != '0') || (*(p+1) != 'x'))
+		return _FALSE;
+	slen = strlen(str);
+	if (slen > (len*2) + 2)
+		return _FALSE;
+	p += 2;
+	for (i = 0 ; i < len; i++, idx = idx+2) {
+		hexbuf[i] = key_2char2num(p[idx], p[idx + 1]);
+		if (slen <= idx+2)
+			break;
+	}
+	return _TRUE;
+}
+
+int rtw_rson_set_property(_adapter *padapter, char *field, char *value)
+{
+	struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+	int num = 0;
+
+	if (_rtw_memcmp(field, (u8 *)"ver", 3) == _TRUE)
+		pdvobj->rson_data.ver = rtw_atoi(value);
+	else if (_rtw_memcmp(field, (u8 *)"id", 2) == _TRUE)
+		num = sscanf(value, "%08x",   &(pdvobj->rson_data.id));
+	else if (_rtw_memcmp(field, (u8 *)"hc", 2) == _TRUE)
+		num = sscanf(value, "%hhu", &(pdvobj->rson_data.hopcnt));
+	else if (_rtw_memcmp(field, (u8 *)"cnt", 3) == _TRUE)
+		num = sscanf(value, "%hhu", &(pdvobj->rson_data.connectible));
+	else if (_rtw_memcmp(field, (u8 *)"loading", 2) == _TRUE)
+		num = sscanf(value, "%hhu", &(pdvobj->rson_data.loading));
+	else if (_rtw_memcmp(field, (u8 *)"res", 2) == _TRUE) {
+		str2hexbuf(value, pdvobj->rson_data.res, 16);
+		return 1;
+	} else
+		return _FALSE;
+	return num;
+}
+
+/*
+	return :	TRUE  -- competitor is taking advantage than condidate
+			FALSE -- we should continue keeping candidate
+*/
+int rtw_rson_choose(struct wlan_network **candidate, struct wlan_network *competitor)
+{
+	s16 comp_score = 0, cand_score = 0;
+	struct rtw_rson_struct rson_cand, rson_comp;
+
+	if (is_match_bssid(competitor->network.MacAddress, rtw_rson_block_bssid, rtw_rson_block_bssid_idx) == _TRUE)
+		return _FALSE;
+
+	if ((competitor == NULL)
+		|| (rtw_get_rson_struct(&(competitor->network), &rson_comp) != _TRUE)
+		|| (rson_comp.id != CONFIG_RTW_REPEATER_SON_ID))
+		return _FALSE;
+
+	comp_score = rtw_cal_rson_score(&rson_comp, competitor->network.Rssi);
+	if (comp_score == RTW_RSON_SCORE_NOTCNNT)
+		return _FALSE;
+
+	if (*candidate == NULL)
+		return _TRUE;
+	if (rtw_get_rson_struct(&((*candidate)->network), &rson_cand) != _TRUE)
+		return _FALSE;
+
+	cand_score = rtw_cal_rson_score(&rson_cand, (*candidate)->network.Rssi);
+	RTW_INFO("%s: competitor_score=%d,  candidate_score=%d\n", __func__, comp_score, cand_score);
+	if (comp_score - cand_score > RSON_SCORE_DIFF_TH)
+		return _TRUE;
+
+	return _FALSE;
+}
+
+inline u8 rtw_rson_varify_ie(u8 *p)
+{
+	u8 *ptr = NULL;
+	u8 ver;
+	u32 id;
+	u8 hopcnt;
+	u8 allcnnt;
+
+	ptr = p + 2 + sizeof(RTW_RSON_OUI);
+	ver = *ptr;
+
+	/*	for (ver == 1)	*/
+	if (ver != 1)
+		return _FALSE;
+
+	return _TRUE;
+}
+
+/*
+	Parsing RTK self-organization vendor IE
+*/
+int rtw_get_rson_struct(WLAN_BSSID_EX *bssid, struct  rtw_rson_struct *rson_data)
+{
+	sint  limit = 0;
+	u32	len;
+	u8	*p;
+
+	if ((rson_data == NULL) || (bssid == NULL))
+		return -EINVAL;
+
+	/*	Default		*/
+	rson_data->id = 0;
+	rson_data->ver = 0;
+	rson_data->hopcnt = 0;
+	rson_data->connectible = 0;
+	rson_data->loading = 0;
+	/*	fake root		*/
+	if (is_match_bssid(bssid->MacAddress, rtw_rson_root_bssid, rtw_rson_root_bssid_idx) == _TRUE) {
+		rson_data->id = CONFIG_RTW_REPEATER_SON_ID;
+		rson_data->ver = RTW_RSON_VER;
+		rson_data->hopcnt = RTW_RSON_HC_ROOT;
+		rson_data->connectible = RTW_RSON_ALLOWCONNECT;
+		rson_data->loading = 0;
+		return _TRUE;
+	}
+	limit = bssid->IELength - _BEACON_IE_OFFSET_;
+
+	for (p = bssid->IEs + _BEACON_IE_OFFSET_; ; p += (len + 2)) {
+		p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &len, limit);
+		limit -= len;
+		if ((p == NULL) || (len == 0))
+			break;
+		if (p && (_rtw_memcmp(p + 2, RTW_RSON_OUI, sizeof(RTW_RSON_OUI)) == _TRUE)
+			&& rtw_rson_varify_ie(p)) {
+			p = p + 2 + sizeof(RTW_RSON_OUI);
+			rson_data->ver = *p;
+			/*	for (ver == 1)		*/
+			p = p + 1;
+			rson_data->id = le32_to_cpup((__le32 *)p);
+			p = p + 4;
+			rson_data->hopcnt = *p;
+			p = p + 1;
+			rson_data->connectible = *p;
+			p = p + 1;
+			rson_data->loading = *p;
+
+			return _TRUE;
+		}
+	}
+	return -EBADMSG;
+}
+
+u32 rtw_rson_append_ie(_adapter *padapter, unsigned char *pframe, u32 *len)
+{
+	u8 *ptr, *ori, ie_len = 0;
+	struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+/*	static int iii = 0;*/
+
+	if ((!pdvobj) || (!pframe))
+		return 0;
+	ptr = ori = pframe;
+	*ptr++ = _VENDOR_SPECIFIC_IE_;
+	*ptr++ = ie_len = sizeof(RTW_RSON_OUI)+sizeof(pdvobj->rson_data);
+	_rtw_memcpy(ptr, RTW_RSON_OUI, sizeof(RTW_RSON_OUI));
+	ptr = ptr + sizeof(RTW_RSON_OUI);
+	*ptr++ = pdvobj->rson_data.ver;
+	*(s32 *)ptr = cpu_to_le32(pdvobj->rson_data.id);
+	ptr = ptr + sizeof(pdvobj->rson_data.id);
+	*ptr++ = pdvobj->rson_data.hopcnt;
+	*ptr++ = pdvobj->rson_data.connectible;
+	*ptr++ = pdvobj->rson_data.loading;
+	_rtw_memcpy(ptr, pdvobj->rson_data.res, sizeof(pdvobj->rson_data.res));
+	pframe = ptr;
+/*
+	iii = iii % 20;
+	if (iii++ == 0)
+		RTW_INFO("%s : RTW RSON IE : %20ph\n", __func__, ori);
+*/
+	*len += (ie_len+2);
+	return ie_len;
+
+}
+
+void rtw_rson_do_disconnect(_adapter *padapter)
+{
+	struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+
+	RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+#ifndef CONFIG_RTW_REPEATER_SON_ROOT
+	pdvobj->rson_data.ver = RTW_RSON_VER;
+	pdvobj->rson_data.id = CONFIG_RTW_REPEATER_SON_ID;
+	pdvobj->rson_data.hopcnt = RTW_RSON_HC_NOTREADY;
+	pdvobj->rson_data.connectible = RTW_RSON_DENYCONNECT;
+	pdvobj->rson_data.loading = 0;
+	rtw_mi_tx_beacon_hdl(padapter);
+#endif
+}
+
+void rtw_rson_join_done(_adapter *padapter)
+{
+	struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+	WLAN_BSSID_EX	*cur_network = NULL;
+	struct rtw_rson_struct  rson_data;
+
+	RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+	if (!padapter->mlmepriv.cur_network_scanned)
+		return;
+	cur_network = &(padapter->mlmepriv.cur_network_scanned->network);
+	if (rtw_get_rson_struct(cur_network, &rson_data) != _TRUE) {
+		RTW_ERR("%s: try to join a improper network(%s)\n", __func__, cur_network->Ssid.Ssid);
+		return;
+	}
+
+#ifndef CONFIG_RTW_REPEATER_SON_ROOT
+	/* update rson_data */
+	pdvobj->rson_data.ver = RTW_RSON_VER;
+	pdvobj->rson_data.id = rson_data.id;
+	pdvobj->rson_data.hopcnt = rson_data.hopcnt + 1;
+	pdvobj->rson_data.connectible = RTW_RSON_ALLOWCONNECT;
+	pdvobj->rson_data.loading = 0;
+	rtw_mi_tx_beacon_hdl(padapter);
+#endif
+}
+
+int rtw_rson_isupdate_roamcan(struct mlme_priv *mlme
+	, struct wlan_network **candidate, struct wlan_network *competitor)
+{
+	struct rtw_rson_struct  rson_cand, rson_comp, rson_curr;
+	s16 comp_score, cand_score, curr_score;
+
+	if ((competitor == NULL)
+		|| (rtw_get_rson_struct(&(competitor->network), &rson_comp) != _TRUE)
+		|| (rson_comp.id != CONFIG_RTW_REPEATER_SON_ID))
+		return _FALSE;
+
+	if (is_match_bssid(competitor->network.MacAddress, rtw_rson_block_bssid, rtw_rson_block_bssid_idx) == _TRUE)
+		return _FALSE;
+
+	if ((!mlme->cur_network_scanned)
+		|| (mlme->cur_network_scanned == competitor)
+		|| (rtw_get_rson_struct(&(mlme->cur_network_scanned->network), &rson_curr)) != _TRUE)
+		return _FALSE;
+
+	if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= mlme->roam_scanr_exp_ms)
+		return _FALSE;
+
+	comp_score = rtw_cal_rson_score(&rson_comp, competitor->network.Rssi);
+	curr_score = rtw_cal_rson_score(&rson_curr, mlme->cur_network_scanned->network.Rssi);
+	if (comp_score - curr_score < RSON_SCORE_DIFF_TH)
+		return _FALSE;
+
+	if (*candidate == NULL)
+		return _TRUE;
+
+	if (rtw_get_rson_struct(&((*candidate)->network), &rson_cand) != _TRUE) {
+		RTW_ERR("%s : Unable to get rson_struct from candidate(%s -- " MAC_FMT")\n",
+				__func__, (*candidate)->network.Ssid.Ssid, MAC_ARG((*candidate)->network.MacAddress));
+		return _FALSE;
+	}
+	cand_score = rtw_cal_rson_score(&rson_cand, (*candidate)->network.Rssi);
+	RTW_DBG("comp_score=%d , cand_score=%d , curr_score=%d\n", comp_score, cand_score, curr_score);
+	if (cand_score < comp_score)
+		return _TRUE;
+
+#if 0		/*	Handle 11R protocol	*/
+#ifdef CONFIG_RTW_80211R
+	if (rtw_chk_ft_flags(adapter, RTW_FT_SUPPORTED)) {
+		ptmp = rtw_get_ie(&competitor->network.IEs[12], _MDIE_, &mdie_len, competitor->network.IELength-12);
+		if (ptmp) {
+			if (!_rtw_memcmp(&pftpriv->mdid, ptmp+2, 2))
+				goto exit;
+
+			/*The candidate don't support over-the-DS*/
+			if (rtw_chk_ft_flags(adapter, RTW_FT_STA_OVER_DS_SUPPORTED)) {
+				if ((rtw_chk_ft_flags(adapter, RTW_FT_OVER_DS_SUPPORTED) && !(*(ptmp+4) & 0x01)) ||
+					(!rtw_chk_ft_flags(adapter, RTW_FT_OVER_DS_SUPPORTED) && (*(ptmp+4) & 0x01))) {
+					RTW_INFO("FT: ignore the candidate(" MAC_FMT ") for over-the-DS\n", MAC_ARG(competitor->network.MacAddress));
+					rtw_clr_ft_flags(adapter, RTW_FT_OVER_DS_SUPPORTED);
+					goto exit;
+				}
+			}
+		} else
+			goto exit;
+	}
+#endif
+#endif
+	return _FALSE;
+}
+
+void rtw_rson_show_survey_info(struct seq_file *m, _list *plist, _list *phead)
+{
+	struct wlan_network	*pnetwork = NULL;
+	struct rtw_rson_struct  rson_data;
+	s16 rson_score;
+	u16  index = 0;
+
+	RTW_PRINT_SEL(m, "%5s  %-17s  %3s  %5s %14s  %10s  %-3s  %5s %32s\n", "index", "bssid", "ch", "id", "hop_cnt", "loading", "RSSI", "score", "ssid");
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		if (!pnetwork)
+			break;
+
+		_rtw_memset(&rson_data, 0, sizeof(rson_data));
+		rson_score = 0;
+		if (rtw_get_rson_struct(&(pnetwork->network), &rson_data) == _TRUE)
+			rson_score = rtw_cal_rson_score(&rson_data, pnetwork->network.Rssi);
+		RTW_PRINT_SEL(m, "%5d  "MAC_FMT" %3d  0x%08x %6d %10d   %6d %6d   %32s\n",
+			      ++index,
+			      MAC_ARG(pnetwork->network.MacAddress),
+			      pnetwork->network.Configuration.DSConfig,
+			      rson_data.id,
+			      rson_data.hopcnt,
+			      rson_data.loading,
+			      (int)pnetwork->network.Rssi,
+			      rson_score,
+			      pnetwork->network.Ssid.Ssid);
+		plist = get_next(plist);
+		}
+
+}
+
+/*
+	Description :	As a AP role, We need to check the qualify of associating STA.
+					We also need to check if we are ready to be associated.
+
+	return :	TRUE  -- AP REJECT this STA
+				FALSE -- AP ACCEPT this STA
+*/
+u8 rtw_rson_ap_check_sta(_adapter *padapter, u8 *pframe, uint pkt_len, unsigned short ie_offset)
+{
+	struct wlan_network	*pnetwork = NULL;
+	struct rtw_rson_struct  rson_target;
+	struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+	int len = 0;
+	u8 ret = _FALSE;
+	u8 *p;
+
+#ifndef CONFIG_RTW_REPEATER_SON_ROOT
+	_rtw_memset(&rson_target, 0, sizeof(rson_target));
+	for (p = pframe + WLAN_HDR_A3_LEN + ie_offset; ; p += (len + 2)) {
+		p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &len, pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+
+		if ((p == NULL) || (len == 0))
+			break;
+
+		if (p && (_rtw_memcmp(p + 2, RTW_RSON_OUI, sizeof(RTW_RSON_OUI)) == _TRUE)
+			&& rtw_rson_varify_ie(p)) {
+			p = p + 2 + sizeof(RTW_RSON_OUI);
+			rson_target.ver = *p;
+			/*	for (ver == 1)		*/
+			p = p + 1;
+			rson_target.id = le32_to_cpup((__le32 *)p);
+			p = p + 4;
+			rson_target.hopcnt = *p;
+			p = p + 1;
+			rson_target.connectible = *p;
+			p = p + 1;
+			rson_target.loading = *p;
+			break;
+		}
+	}
+
+	if (rson_target.id == 0)		/*	Normal STA, not a RSON STA	*/
+		ret = _FALSE;
+	else if (rson_target.id != pdvobj->rson_data.id) {
+		ret = _TRUE;
+		RTW_INFO("%s : Reject AssoReq because RSON ID not match, STA=%08x, our=%08x\n",
+				__func__, rson_target.id, pdvobj->rson_data.id);
+	} else if ((pdvobj->rson_data.hopcnt == RTW_RSON_HC_NOTREADY)
+		|| (pdvobj->rson_data.connectible == RTW_RSON_DENYCONNECT)) {
+		ret = _TRUE;
+		RTW_INFO("%s : Reject AssoReq becuase our hopcnt=%d or connectbile=%d\n",
+				__func__, pdvobj->rson_data.hopcnt, pdvobj->rson_data.connectible);
+	}
+#endif
+	return ret;
+}
+
+u8 rtw_rson_scan_wk_cmd(_adapter *padapter, int op)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8 *extra_cmd_buf;
+	u8 res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+	pdrvextra_cmd_parm->ec_id = RSON_SCAN_WK_CID;
+	pdrvextra_cmd_parm->type = op;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+	return res;
+
+}
+
+void rtw_rson_scan_cmd_hdl(_adapter *padapter, int op)
+{
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	u8 val8;
+
+	if (mlmeext_chk_scan_state(pmlmeext, SCAN_DISABLE) != _TRUE)
+		return;
+	if (op == RSON_SCAN_PROCESS) {
+		padapter->rtw_rson_scanstage = RSON_SCAN_PROCESS;
+		val8 = 0x1e;
+		rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &val8, _FALSE);
+		val8 = 1;
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+		issue_probereq(padapter, NULL, NULL);
+		/*	stop rson_scan after 100ms	*/
+		_set_timer(&(pmlmeext->rson_scan_timer), 100);
+	} else if  (op == RSON_SCAN_DISABLE) {
+		padapter->rtw_rson_scanstage = RSON_SCAN_DISABLE;
+		val8 = 0;
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+		val8 = 0xff;
+		rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &val8, _FALSE);
+		/*	report_surveydone_event(padapter);*/
+		if (pmlmepriv->to_join == _TRUE) {
+			if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) != _TRUE) {
+				int s_ret;
+
+				set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+				pmlmepriv->to_join = _FALSE;
+				s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
+				if (s_ret == _SUCCESS)
+					_set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
+				else if (s_ret == 2) {
+					_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+					rtw_indicate_connect(padapter);
+				} else {
+					RTW_INFO("try_to_join, but select scanning queue fail, to_roam:%d\n", rtw_to_roam(padapter));
+					if (rtw_to_roam(padapter) != 0) {
+						if (rtw_dec_to_roam(padapter) == 0) {
+							rtw_set_to_roam(padapter, 0);
+#ifdef CONFIG_INTEL_WIDI
+							if (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) {
+								_rtw_memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN);
+								intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_WK, NULL, 0);
+								RTW_INFO("change to widi listen\n");
+							}
+#endif /* CONFIG_INTEL_WIDI */
+							rtw_free_assoc_resources(padapter, _TRUE);
+							rtw_indicate_disconnect(padapter, 0, _FALSE);
+						} else
+							pmlmepriv->to_join = _TRUE;
+					} else
+						rtw_indicate_disconnect(padapter, 0, _FALSE);
+					_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+				}
+			}
+		} else {
+			if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE)) {
+				if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)
+				    && check_fwstate(pmlmepriv, _FW_LINKED)) {
+					if (rtw_select_roaming_candidate(pmlmepriv) == _SUCCESS) {
+#ifdef CONFIG_RTW_80211R
+						if (rtw_chk_ft_flags(padapter, RTW_FT_OVER_DS_SUPPORTED)) {
+							start_clnt_ft_action(adapter, (u8 *)pmlmepriv->roam_network->network.MacAddress);
+						} else {
+							/*wait a little time to retrieve packets buffered in the current ap while scan*/
+							_set_timer(&pmlmeext->ft_roam_timer, 30);
+						}
+#else
+						receive_disconnect(padapter, pmlmepriv->cur_network.network.MacAddress
+							, WLAN_REASON_ACTIVE_ROAM, _FALSE);
+#endif
+					}
+				}
+			}
+			issue_action_BSSCoexistPacket(padapter);
+			issue_action_BSSCoexistPacket(padapter);
+			issue_action_BSSCoexistPacket(padapter);
+		}
+	} else {
+		RTW_ERR("%s : improper parameter -- op = %d\n", __func__, op);
+	}
+}
+
+#endif	/* CONFIG_RTW_REPEATER_SON */

+ 52 - 20
core/rtw_sdio.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2015 - 2017 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
@@ -11,11 +11,7 @@
  * 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
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_SDIO_C_
 
 #include <drv_types.h>		/* struct dvobj_priv and etc. */
@@ -39,22 +35,61 @@
  */
 static u8 sdio_io(struct dvobj_priv *d, u32 addr, void *buf, size_t len, u8 write, u8 cmd52)
 {
+	u32 addr_drv;	/* address with driver defined bit */
 	int err;
+	u8 retry = 0;
+	u8 stop_retry = _FALSE;	/* flag for stopping retry or not */
 
 
-	if (cmd52)
-		addr = RTW_SDIO_ADDR_CMD52_GEN(addr);
-
-	if (write)
-		err = d->intf_ops->write(d, addr, buf, len, 0);
-	else
-		err = d->intf_ops->read(d, addr, buf, len, 0);
-	if (err) {
-		RTW_INFO("%s: [ERROR] %s FAIL! error(%d)\n",
-			 __FUNCTION__, write ? "write" : "read", err);
+	if (rtw_is_surprise_removed(dvobj_get_primary_adapter(d))) {
+		RTW_ERR("%s: bSurpriseRemoved, skip %s 0x%05x, %zu bytes\n",
+			__FUNCTION__, write?"write":"read", addr, len);
 		return _FAIL;
 	}
 
+	addr_drv = addr;
+	if (cmd52)
+		addr_drv = RTW_SDIO_ADDR_CMD52_GEN(addr_drv);
+
+	do {
+		if (write)
+			err = d->intf_ops->write(d, addr_drv, buf, len, 0);
+		else
+			err = d->intf_ops->read(d, addr_drv, buf, len, 0);
+		if (!err) {
+			if (retry) {
+				RTW_INFO("%s: Retry %s OK! addr=0x%05x %zu bytes, retry=%u,%u\n",
+					 __FUNCTION__, write?"write":"read",
+					 addr, len, retry, ATOMIC_READ(&d->continual_io_error));
+				RTW_INFO_DUMP("Data: ", buf, len);
+			}
+			rtw_reset_continual_io_error(d);
+			break;
+		}
+		RTW_ERR("%s: %s FAIL! error(%d) addr=0x%05x %zu bytes, retry=%u,%u\n",
+			__FUNCTION__, write?"write":"read", err, addr, len,
+			retry, ATOMIC_READ(&d->continual_io_error));
+
+		retry++;
+		stop_retry = rtw_inc_and_chk_continual_io_error(d);
+		if ((err == -1) || (stop_retry == _TRUE) || (retry > SD_IO_TRY_CNT)) {
+			/* critical error, unrecoverable */
+			RTW_ERR("%s: Fatal error! Set surprise remove flag ON! (retry=%u,%u)\n",
+				__FUNCTION__, retry, ATOMIC_READ(&d->continual_io_error));
+			rtw_set_surprise_removed(dvobj_get_primary_adapter(d));
+			return _FAIL;
+		}
+
+		/* WLAN IOREG or SDIO Local */
+		if ((addr & 0x10000) || !(addr & 0xE000)) {
+			RTW_WARN("%s: Retry %s addr=0x%05x %zu bytes, retry=%u,%u\n",
+				 __FUNCTION__, write?"write":"read", addr, len,
+				 retry, ATOMIC_READ(&d->continual_io_error));
+			continue;
+		}
+		return _FAIL;
+	} while (1);
+
 	return _SUCCESS;
 }
 
@@ -88,11 +123,8 @@ u8 rtw_sdio_f0_read(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
 	addr = RTW_SDIO_ADDR_F0_GEN(addr);
 
 	err = d->intf_ops->read(d, addr, buf, len, 0);
-	if (err) {
-		RTW_INFO("%s: [ERROR] Read f0 register FAIL!\n", __FUNCTION__);
+	if (err)
 		ret = _FAIL;
-	}
-
 
 	return ret;
 }

+ 348 - 118
core/rtw_security.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define  _RTW_SECURITY_C_
 
 #include <drv_types.h>
@@ -826,7 +821,7 @@ u32 rtw_tkip_decrypt(_adapter *padapter, u8 *precvframe)
 		if (stainfo != NULL) {
 
 			if (IS_MCAST(prxattrib->ra)) {
-				static u32 start = 0;
+				static systime start = 0;
 				static u32 no_gkey_bc_cnt = 0;
 				static u32 no_gkey_mc_cnt = 0;
 
@@ -987,13 +982,6 @@ static void next_key(u8 *key, sint round);
 static void byte_sub(u8 *in, u8 *out);
 static void shift_row(u8 *in, u8 *out);
 static void mix_column(u8 *in, u8 *out);
-#ifndef PLATFORM_FREEBSD
-static void add_round_key(u8 *shiftrow_in,
-			  u8 *mcol_in,
-			  u8 *block_in,
-			  sint round,
-			  u8 *out);
-#endif /* PLATFORM_FREEBSD */
 static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext);
 
 
@@ -1190,11 +1178,11 @@ static void construct_mic_iv(
 		mic_iv[1] = mpdu[24] & 0x0f;   /* mute bits 7-4   */
 	if (!qc_exists)
 		mic_iv[1] = 0x00;
-#ifdef CONFIG_IEEE80211W
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_RTW_MESH)
 	/* 802.11w management frame should set management bit(4) */
 	if (frtype == WIFI_MGT_TYPE)
 		mic_iv[1] |= BIT(4);
-#endif /* CONFIG_IEEE80211W */
+#endif
 	for (i = 2; i < 8; i++)
 		mic_iv[i] = mpdu[i + 8];                    /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */
 #ifdef CONSISTENT_PN_ORDER
@@ -1224,12 +1212,12 @@ static void construct_mic_header1(
 {
 	mic_header1[0] = (u8)((header_length - 2) / 256);
 	mic_header1[1] = (u8)((header_length - 2) % 256);
-#ifdef CONFIG_IEEE80211W
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_RTW_MESH)
 	/* 802.11w management frame don't AND subtype bits 4,5,6 of frame control field */
 	if (frtype == WIFI_MGT_TYPE)
 		mic_header1[2] = mpdu[0];
 	else
-#endif /* CONFIG_IEEE80211W */
+#endif
 		mic_header1[2] = mpdu[0] & 0xcf;    /* Mute CF poll & CF ack bits */
 
 	mic_header1[3] = mpdu[1] & 0xc7;    /* Mute retry, more data and pwr mgt bits */
@@ -1325,11 +1313,11 @@ static void construct_ctr_preload(
 		ctr_preload[1] = mpdu[30] & 0x0f;   /* QoC_Control */
 	if (qc_exists && !a4_exists)
 		ctr_preload[1] = mpdu[24] & 0x0f;
-#ifdef CONFIG_IEEE80211W
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_RTW_MESH)
 	/* 802.11w management frame should set management bit(4) */
 	if (frtype == WIFI_MGT_TYPE)
 		ctr_preload[1] |= BIT(4);
-#endif /* CONFIG_IEEE80211W */
+#endif
 	for (i = 2; i < 8; i++)
 		ctr_preload[i] = mpdu[i + 8];                       /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */
 #ifdef CONSISTENT_PN_ORDER
@@ -1399,8 +1387,7 @@ static sint aes_cipher(u8 *key, uint	hdrlen,
 		((frtype | frsubtype) == WIFI_DATA_CFPOLL) ||
 		((frtype | frsubtype) == WIFI_DATA_CFACKPOLL)) {
 		qc_exists = 1;
-		if (hdrlen !=  WLAN_HDR_A3_QOS_LEN)
-
+		if (hdrlen != WLAN_HDR_A3_QOS_LEN && hdrlen != WLAN_HDR_A4_QOS_LEN)
 			hdrlen += 2;
 	}
 	/* add for CONFIG_IEEE80211W, none 11w also can use */
@@ -1409,8 +1396,7 @@ static sint aes_cipher(u8 *key, uint	hdrlen,
 		  (frsubtype == 0x09) ||
 		  (frsubtype == 0x0a) ||
 		  (frsubtype == 0x0b))) {
-		if (hdrlen !=  WLAN_HDR_A3_QOS_LEN)
-
+		if (hdrlen != WLAN_HDR_A3_QOS_LEN && hdrlen != WLAN_HDR_A4_QOS_LEN)
 			hdrlen += 2;
 		qc_exists = 1;
 	} else
@@ -1720,8 +1706,7 @@ static sint aes_decipher(u8 *key, uint	hdrlen,
 		((frtype | frsubtype) == WIFI_DATA_CFPOLL) ||
 		((frtype | frsubtype) == WIFI_DATA_CFACKPOLL)) {
 		qc_exists = 1;
-		if (hdrlen !=  WLAN_HDR_A3_QOS_LEN)
-
+		if (hdrlen != WLAN_HDR_A3_QOS_LEN && hdrlen != WLAN_HDR_A4_QOS_LEN)
 			hdrlen += 2;
 	} /* only for data packet . add for CONFIG_IEEE80211W, none 11w also can use */
 	else if ((frtype == WIFI_DATA) &&
@@ -1729,8 +1714,7 @@ static sint aes_decipher(u8 *key, uint	hdrlen,
 		  (frsubtype == 0x09) ||
 		  (frsubtype == 0x0a) ||
 		  (frsubtype == 0x0b))) {
-		if (hdrlen !=  WLAN_HDR_A3_QOS_LEN)
-
+		if (hdrlen != WLAN_HDR_A3_QOS_LEN && hdrlen != WLAN_HDR_A4_QOS_LEN)
 			hdrlen += 2;
 		qc_exists = 1;
 	} else
@@ -1938,7 +1922,6 @@ u32	rtw_aes_decrypt(_adapter *padapter, u8 *precvframe)
 
 
 	sint		length;
-	u32	prwskeylen;
 	u8	*pframe, *prwskey;	/* , *payload,*iv */
 	struct	sta_info		*stainfo;
 	struct	rx_pkt_attrib	*prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
@@ -1953,13 +1936,17 @@ u32	rtw_aes_decrypt(_adapter *padapter, u8 *precvframe)
 		if (stainfo != NULL) {
 
 			if (IS_MCAST(prxattrib->ra)) {
-				static u32 start = 0;
+				static systime start = 0;
 				static u32 no_gkey_bc_cnt = 0;
 				static u32 no_gkey_mc_cnt = 0;
 
 				/* RTW_INFO("rx bc/mc packets, to perform sw rtw_aes_decrypt\n"); */
 				/* prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; */
-				if (psecuritypriv->binstallGrpkey == _FALSE) {
+				if ((!MLME_IS_MESH(padapter) && psecuritypriv->binstallGrpkey == _FALSE)
+					#ifdef CONFIG_RTW_MESH
+					|| !(stainfo->gtk_bmp | BIT(prxattrib->key_index))
+					#endif
+				) {
 					res = _FAIL;
 
 					if (start == 0)
@@ -1991,12 +1978,20 @@ u32	rtw_aes_decrypt(_adapter *padapter, u8 *precvframe)
 				no_gkey_bc_cnt = 0;
 				no_gkey_mc_cnt = 0;
 
-				prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
-				if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) {
-					RTW_DBG("not match packet_index=%d, install_index=%d\n"
-						, prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid);
-					res = _FAIL;
-					goto exit;
+				#ifdef CONFIG_RTW_MESH
+				if (MLME_IS_MESH(padapter)) {
+					/* TODO: multiple GK? */
+					prwskey = &stainfo->gtk.skey[0];
+				} else
+				#endif
+				{
+					prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
+					if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) {
+						RTW_DBG("not match packet_index=%d, install_index=%d\n"
+							, prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid);
+						res = _FAIL;
+						goto exit;
+					}
 				}
 			} else
 				prwskey = &stainfo->dot118021x_UncstKey.skey[0];
@@ -2038,94 +2033,96 @@ exit:
 }
 
 #ifdef CONFIG_IEEE80211W
-u32	rtw_BIP_verify(_adapter *padapter, u8 *precvframe)
+u32	rtw_BIP_verify(_adapter *padapter, u8 *whdr_pos, sint flen
+	, const u8 *key, u16 keyid, u64* ipn)
 {
-	struct rx_pkt_attrib *pattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
-	u8 *pframe;
-	u8 *BIP_AAD, *p;
+	u8 *BIP_AAD, *mme;
 	u32	res = _FAIL;
 	uint len, ori_len;
+	u16 pkt_keyid = 0;
+	u64 pkt_ipn = 0;
 	struct rtw_ieee80211_hdr *pwlanhdr;
 	u8 mic[16];
-	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
-	ori_len = pattrib->pkt_len - WLAN_HDR_A3_LEN + BIP_AAD_SIZE;
-	BIP_AAD = rtw_zmalloc(ori_len);
 
+	mme = whdr_pos + flen - 18;
+	if (*mme != _MME_IE_)
+		return RTW_RX_HANDLED;
+
+	/* copy key index */
+	_rtw_memcpy(&pkt_keyid, mme + 2, 2);
+	pkt_keyid = le16_to_cpu(pkt_keyid);
+	if (pkt_keyid != keyid) {
+		RTW_INFO("BIP key index error!\n");
+		return _FAIL;
+	}
+
+	/* save packet number */
+	_rtw_memcpy(&pkt_ipn, mme + 4, 6);
+	pkt_ipn = le64_to_cpu(pkt_ipn);
+	/* BIP packet number should bigger than previous BIP packet */
+	if (pkt_ipn <= *ipn) { /* wrap around? */
+		RTW_INFO("replay BIP packet\n");
+		return _FAIL;
+	}
+
+	ori_len = flen - WLAN_HDR_A3_LEN + BIP_AAD_SIZE;
+	BIP_AAD = rtw_zmalloc(ori_len);
 	if (BIP_AAD == NULL) {
 		RTW_INFO("BIP AAD allocate fail\n");
 		return _FAIL;
 	}
-	/* PKT start */
-	pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+
 	/* mapping to wlan header */
-	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)whdr_pos;
+
 	/* save the frame body + MME */
-	_rtw_memcpy(BIP_AAD + BIP_AAD_SIZE, pframe + WLAN_HDR_A3_LEN, pattrib->pkt_len - WLAN_HDR_A3_LEN);
-	/* find MME IE pointer */
-	p = rtw_get_ie(BIP_AAD + BIP_AAD_SIZE, _MME_IE_, &len, pattrib->pkt_len - WLAN_HDR_A3_LEN);
-	/* Baron */
-	if (p) {
-		u16 keyid = 0;
-		u64 temp_ipn = 0;
-		/* save packet number */
-		_rtw_memcpy(&temp_ipn, p + 4, 6);
-		temp_ipn = le64_to_cpu(temp_ipn);
-		/* BIP packet number should bigger than previous BIP packet */
-		if (temp_ipn < pmlmeext->mgnt_80211w_IPN_rx) {
-			RTW_INFO("replay BIP packet\n");
-			goto BIP_exit;
-		}
-		/* copy key index */
-		_rtw_memcpy(&keyid, p + 2, 2);
-		keyid = le16_to_cpu(keyid);
-		if (keyid != padapter->securitypriv.dot11wBIPKeyid) {
-			RTW_INFO("BIP key index error!\n");
-			goto BIP_exit;
-		}
-		/* clear the MIC field of MME to zero */
-		_rtw_memset(p + 2 + len - 8, 0, 8);
+	_rtw_memcpy(BIP_AAD + BIP_AAD_SIZE, whdr_pos + WLAN_HDR_A3_LEN, flen - WLAN_HDR_A3_LEN);
+
+	/* point mme to the copy */
+	mme = BIP_AAD + ori_len - 18;
 
-		/* conscruct AAD, copy frame control field */
-		_rtw_memcpy(BIP_AAD, &pwlanhdr->frame_ctl, 2);
-		ClearRetry(BIP_AAD);
-		ClearPwrMgt(BIP_AAD);
-		ClearMData(BIP_AAD);
-		/* conscruct AAD, copy address 1 to address 3 */
-		_rtw_memcpy(BIP_AAD + 2, pwlanhdr->addr1, 18);
+	/* clear the MIC field of MME to zero */
+	_rtw_memset(mme + 10, 0, 8);
 
-		if (omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey
-				  , BIP_AAD, ori_len, mic))
-			goto BIP_exit;
+	/* conscruct AAD, copy frame control field */
+	_rtw_memcpy(BIP_AAD, &pwlanhdr->frame_ctl, 2);
+	ClearRetry(BIP_AAD);
+	ClearPwrMgt(BIP_AAD);
+	ClearMData(BIP_AAD);
+	/* conscruct AAD, copy address 1 to address 3 */
+	_rtw_memcpy(BIP_AAD + 2, pwlanhdr->addr1, 18);
+
+	if (omac1_aes_128(key, BIP_AAD, ori_len, mic))
+		goto BIP_exit;
 
 #if 0
-		/* management packet content */
-		{
-			int pp;
-			RTW_INFO("pkt: ");
-			for (pp = 0; pp < pattrib->pkt_len; pp++)
-				printk(" %02x ", pframe[pp]);
-			RTW_INFO("\n");
-			/* BIP AAD + management frame body + MME(MIC is zero) */
-			RTW_INFO("AAD+PKT: ");
-			for (pp = 0; pp < ori_len; pp++)
-				RTW_INFO(" %02x ", BIP_AAD[pp]);
-			RTW_INFO("\n");
-			/* show the MIC result */
-			RTW_INFO("mic: ");
-			for (pp = 0; pp < 16; pp++)
-				RTW_INFO(" %02x ", mic[pp]);
-			RTW_INFO("\n");
-		}
+	/* management packet content */
+	{
+		int pp;
+		RTW_INFO("pkt: ");
+		for (pp = 0; pp < flen; pp++)
+			printk(" %02x ", whdr_pos[pp]);
+		RTW_INFO("\n");
+		/* BIP AAD + management frame body + MME(MIC is zero) */
+		RTW_INFO("AAD+PKT: ");
+		for (pp = 0; pp < ori_len; pp++)
+			RTW_INFO(" %02x ", BIP_AAD[pp]);
+		RTW_INFO("\n");
+		/* show the MIC result */
+		RTW_INFO("mic: ");
+		for (pp = 0; pp < 16; pp++)
+			RTW_INFO(" %02x ", mic[pp]);
+		RTW_INFO("\n");
+	}
 #endif
-		/* MIC field should be last 8 bytes of packet (packet without FCS) */
-		if (_rtw_memcmp(mic, pframe + pattrib->pkt_len - 8, 8)) {
-			pmlmeext->mgnt_80211w_IPN_rx = temp_ipn;
-			res = _SUCCESS;
-		} else
-			RTW_INFO("BIP MIC error!\n");
 
+	/* MIC field should be last 8 bytes of packet (packet without FCS) */
+	if (_rtw_memcmp(mic, whdr_pos + flen - 8, 8)) {
+		*ipn = pkt_ipn;
+		res = _SUCCESS;
 	} else
-		res = RTW_RX_HANDLED;
+		RTW_INFO("BIP MIC error!\n");
+
 BIP_exit:
 
 	rtw_mfree(BIP_AAD, ori_len);
@@ -2134,6 +2131,7 @@ BIP_exit:
 #endif /* CONFIG_IEEE80211W */
 
 #ifndef PLATFORM_FREEBSD
+#if defined(CONFIG_TDLS)
 /* compress 512-bits */
 static int sha256_compress(struct sha256_state *md, unsigned char *buf)
 {
@@ -2210,7 +2208,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in,
 	unsigned long n;
 #define block_size 64
 
-	if (md->curlen > sizeof(md->buf))
+	if (md->curlen >= sizeof(md->buf))
 		return -1;
 
 	while (inlen > 0) {
@@ -2314,10 +2312,12 @@ static u8 os_strlen(const char *s)
 		p++;
 	return p - s;
 }
+#endif
 
-static int os_memcmp(void *s1, void *s2, u8 n)
+#if defined(CONFIG_TDLS) || defined(CONFIG_RTW_MESH_AEK)
+static int os_memcmp(const void *s1, const void *s2, u8 n)
 {
-	unsigned char *p1 = s1, *p2 = s2;
+	const unsigned char *p1 = s1, *p2 = s2;
 
 	if (n == 0)
 		return 0;
@@ -2332,6 +2332,7 @@ static int os_memcmp(void *s1, void *s2, u8 n)
 
 	return *p1 - *p2;
 }
+#endif
 
 /**
  * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
@@ -2342,6 +2343,7 @@ static int os_memcmp(void *s1, void *s2, u8 n)
  * @len: Lengths of the data blocks
  * @mac: Buffer for the hash (32 bytes)
  */
+#if defined(CONFIG_TDLS)
 static void hmac_sha256_vector(u8 *key, size_t key_len, size_t num_elem,
 			       u8 *addr[], size_t *len, u8 *mac)
 {
@@ -2403,6 +2405,7 @@ static void hmac_sha256_vector(u8 *key, size_t key_len, size_t num_elem,
 	_len[1] = 32;
 	sha256_vector(2, _addr, _len, mac);
 }
+#endif /* CONFIG_TDLS */
 #endif /* PLATFORM_FREEBSD */
 /**
  * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
@@ -2418,6 +2421,7 @@ static void hmac_sha256_vector(u8 *key, size_t key_len, size_t num_elem,
  * given key.
  */
 #ifndef PLATFORM_FREEBSD /* Baron */
+#if defined(CONFIG_TDLS)
 static void sha256_prf(u8 *key, size_t key_len, char *label,
 		       u8 *data, size_t data_len, u8 *buf, size_t buf_len)
 {
@@ -2454,6 +2458,7 @@ static void sha256_prf(u8 *key, size_t key_len, char *label,
 		counter++;
 	}
 }
+#endif
 #endif /* PLATFORM_FREEBSD Baron */
 
 /* AES tables*/
@@ -2723,7 +2728,7 @@ static void rijndaelEncrypt(u32 rk[/*44*/], u8 pt[16], u8 ct[16])
 	PUTU32(ct + 12, s3);
 }
 
-static void *aes_encrypt_init(u8 *key, size_t len)
+static void *aes_encrypt_init(const u8 *key, size_t len)
 {
 	u32 *rk;
 	if (len != 16)
@@ -2773,12 +2778,12 @@ static void aes_encrypt_deinit(void *ctx)
  * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
  * (SP) 800-38B.
  */
-static int omac1_aes_128_vector(u8 *key, size_t num_elem,
-				u8 *addr[], size_t *len, u8 *mac)
+static int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
 {
 	void *ctx;
 	u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
-	u8 *pos, *end;
+	const u8 *pos, *end;
 	size_t i, e, left, total_len;
 
 	ctx = aes_encrypt_init(key, 16);
@@ -2846,12 +2851,237 @@ static int omac1_aes_128_vector(u8 *key, size_t num_elem,
  * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
  * (SP) 800-38B.
  */ /* modify for CONFIG_IEEE80211W */
-int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac)
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
 {
 	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
 }
 #endif /* PLATFORM_FREEBSD Baron */
 
+#ifdef CONFIG_RTW_MESH_AEK
+/* for AES-SIV */
+#define os_memset _rtw_memset
+#define os_memcpy _rtw_memcpy
+#define os_malloc rtw_malloc
+#define bin_clear_free(bin, len) \
+	do { \
+		if (bin) { \
+			os_memset(bin, 0, len); \
+			rtw_mfree(bin, len); \
+		} \
+	} while (0)
+
+static const u8 zero[AES_BLOCK_SIZE];
+
+static void dbl(u8 *pad)
+{
+	int i, carry;
+
+	carry = pad[0] & 0x80;
+	for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+		pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+	pad[AES_BLOCK_SIZE - 1] <<= 1;
+	if (carry)
+		pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+static void xor(u8 *a, const u8 *b)
+{
+	int i;
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++)
+		*a++ ^= *b++;
+}
+
+static void xorend(u8 *a, int alen, const u8 *b, int blen)
+{
+	int i;
+
+	if (alen < blen)
+		return;
+
+	for (i = 0; i < blen; i++)
+		a[alen - blen + i] ^= b[i];
+}
+
+static void pad_block(u8 *pad, const u8 *addr, size_t len)
+{
+	os_memset(pad, 0, AES_BLOCK_SIZE);
+	os_memcpy(pad, addr, len);
+
+	if (len < AES_BLOCK_SIZE)
+		pad[len] = 0x80;
+}
+
+static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
+		   size_t *len, u8 *mac)
+{
+	u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
+	u8 *buf = NULL;
+	int ret;
+	size_t i;
+
+	if (!num_elem) {
+		os_memcpy(tmp, zero, sizeof(zero));
+		tmp[AES_BLOCK_SIZE - 1] = 1;
+		return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+	}
+
+	ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num_elem - 1; i++) {
+		ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+		if (ret)
+			return ret;
+
+		dbl(tmp);
+		xor(tmp, tmp2);
+	}
+	if (len[i] >= AES_BLOCK_SIZE) {
+		buf = os_malloc(len[i]);
+		if (!buf)
+			return -ENOMEM;
+
+		os_memcpy(buf, addr[i], len[i]);
+		xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
+		ret = omac1_aes_128(key, buf, len[i], mac);
+		bin_clear_free(buf, len[i]);
+		return ret;
+	}
+
+	dbl(tmp);
+	pad_block(tmp2, addr[i], len[i]);
+	xor(tmp, tmp2);
+
+	return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+}
+
+/**
+ * aes_128_ctr_encrypt - AES-128 CTR mode encryption
+ * @key: Key for encryption (16 bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+			u8 *data, size_t data_len)
+{
+	void *ctx;
+	size_t j, len, left = data_len;
+	int i;
+	u8 *pos = data;
+	u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memcpy(counter, nonce, AES_BLOCK_SIZE);
+
+	while (left > 0) {
+		#if 0
+		aes_encrypt(ctx, counter, buf);
+		#else
+		aes_128_encrypt(ctx, counter, buf);
+		#endif
+
+		len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE;
+		for (j = 0; j < len; j++)
+			pos[j] ^= buf[j];
+		pos += len;
+		left -= len;
+
+		for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+			counter[i]++;
+			if (counter[i])
+				break;
+		}
+	}
+	aes_encrypt_deinit(ctx);
+	return 0;
+}
+
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+		    size_t pwlen, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *out)
+{
+	const u8 *_addr[6];
+	size_t _len[6];
+	const u8 *k1 = key, *k2 = key + 16;
+	u8 v[AES_BLOCK_SIZE];
+	size_t i;
+	u8 *iv, *crypt_pw;
+
+	if (num_elem > ARRAY_SIZE(_addr) - 1)
+		return -1;
+
+	for (i = 0; i < num_elem; i++) {
+		_addr[i] = addr[i];
+		_len[i] = len[i];
+	}
+	_addr[num_elem] = pw;
+	_len[num_elem] = pwlen;
+
+	if (aes_s2v(k1, num_elem + 1, _addr, _len, v))
+		return -1;
+
+	iv = out;
+	crypt_pw = out + AES_BLOCK_SIZE;
+
+	os_memcpy(iv, v, AES_BLOCK_SIZE);
+	os_memcpy(crypt_pw, pw, pwlen);
+
+	/* zero out 63rd and 31st bits of ctr (from right) */
+	v[8] &= 0x7f;
+	v[12] &= 0x7f;
+	return aes_128_ctr_encrypt(k2, v, crypt_pw, pwlen);
+}
+
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+		    size_t num_elem, const u8 *addr[], const size_t *len,
+		    u8 *out)
+{
+	const u8 *_addr[6];
+	size_t _len[6];
+	const u8 *k1 = key, *k2 = key + 16;
+	size_t crypt_len;
+	size_t i;
+	int ret;
+	u8 iv[AES_BLOCK_SIZE];
+	u8 check[AES_BLOCK_SIZE];
+
+	if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1)
+		return -1;
+	crypt_len = iv_c_len - AES_BLOCK_SIZE;
+
+	for (i = 0; i < num_elem; i++) {
+		_addr[i] = addr[i];
+		_len[i] = len[i];
+	}
+	_addr[num_elem] = out;
+	_len[num_elem] = crypt_len;
+
+	os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
+	os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
+
+	iv[8] &= 0x7f;
+	iv[12] &= 0x7f;
+
+	ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+	if (ret)
+		return ret;
+
+	ret = aes_s2v(k1, num_elem + 1, _addr, _len, check);
+	if (ret)
+		return ret;
+	if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
+		return 0;
+
+	return -1;
+}
+#endif /* CONFIG_RTW_MESH_AEK */
+
 #ifdef CONFIG_TDLS
 void wpa_tdls_generate_tpk(_adapter *padapter, PVOID sta)
 {
@@ -2888,11 +3118,11 @@ void wpa_tdls_generate_tpk(_adapter *padapter, PVOID sta)
 	 * added by the KDF anyway..
 	 */
 
-	if (os_memcmp(adapter_mac_addr(padapter), psta->hwaddr, ETH_ALEN) < 0) {
+	if (os_memcmp(adapter_mac_addr(padapter), psta->cmn.mac_addr, ETH_ALEN) < 0) {
 		_rtw_memcpy(data, adapter_mac_addr(padapter), ETH_ALEN);
-		_rtw_memcpy(data + ETH_ALEN, psta->hwaddr, ETH_ALEN);
+		_rtw_memcpy(data + ETH_ALEN, psta->cmn.mac_addr, ETH_ALEN);
 	} else {
-		_rtw_memcpy(data, psta->hwaddr, ETH_ALEN);
+		_rtw_memcpy(data, psta->cmn.mac_addr, ETH_ALEN);
 		_rtw_memcpy(data + ETH_ALEN, adapter_mac_addr(padapter), ETH_ALEN);
 	}
 	_rtw_memcpy(data + 2 * ETH_ALEN, get_bssid(pmlmepriv), ETH_ALEN);

+ 29 - 61
core/rtw_sreset.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 
 #include <drv_types.h>
 #include <hal_data.h>
@@ -52,10 +47,9 @@ u8 sreset_get_wifi_status(_adapter *padapter)
 #if defined(DBG_CONFIG_ERROR_DETECT)
 	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
 	struct sreset_priv *psrtpriv = &pHalData->srestpriv;
-
 	u8 status = WIFI_STATUS_SUCCESS;
 	u32 val32 = 0;
-	_irqL irqL;
+
 	if (psrtpriv->silent_reset_inprogress == _TRUE)
 		return status;
 	val32 = rtw_read32(padapter, REG_TXDMA_STATUS);
@@ -109,11 +103,9 @@ bool sreset_inprogress(_adapter *padapter)
 
 void sreset_restore_security_station(_adapter *padapter)
 {
-	u8 EntryId = 0;
 	struct mlme_priv *mlmepriv = &padapter->mlmepriv;
 	struct sta_priv *pstapriv = &padapter->stapriv;
 	struct sta_info *psta;
-	struct security_priv *psecuritypriv = &(padapter->securitypriv);
 	struct mlme_ext_info	*pmlmeinfo = &padapter->mlmeextpriv.mlmext_info;
 
 	{
@@ -131,31 +123,18 @@ void sreset_restore_security_station(_adapter *padapter)
 		rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
 	}
 
-#if 0
-	if ((padapter->securitypriv.dot11PrivacyAlgrthm == _WEP40_) ||
-	    (padapter->securitypriv.dot11PrivacyAlgrthm == _WEP104_)) {
-
-		for (EntryId = 0; EntryId < 4; EntryId++) {
-			if (EntryId == psecuritypriv->dot11PrivacyKeyIndex)
-				rtw_set_key(padapter, &padapter->securitypriv, EntryId, 1, _FALSE);
-			else
-				rtw_set_key(padapter, &padapter->securitypriv, EntryId, 0, _FALSE);
-		}
-
-	} else
-#endif
-		if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
-		    (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
-			psta = rtw_get_stainfo(pstapriv, get_bssid(mlmepriv));
-			if (psta == NULL) {
-				/* DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail\n")); */
-			} else {
-				/* pairwise key */
-				rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, _FALSE);
-				/* group key */
-				rtw_set_key(padapter, &padapter->securitypriv, padapter->securitypriv.dot118021XGrpKeyid, 0, _FALSE);
-			}
+	if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+	    (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
+		psta = rtw_get_stainfo(pstapriv, get_bssid(mlmepriv));
+		if (psta == NULL) {
+			/* DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail\n")); */
+		} else {
+			/* pairwise key */
+			rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, _FALSE);
+			/* group key */
+			rtw_set_key(padapter, &padapter->securitypriv, padapter->securitypriv.dot118021XGrpKeyid, 0, _FALSE);
 		}
+	}
 }
 
 void sreset_restore_network_station(_adapter *padapter)
@@ -165,32 +144,14 @@ void sreset_restore_network_station(_adapter *padapter)
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 	u8 doiqk = _FALSE;
 
-#if 0
-	{
-		/* ======================================================= */
-		/* reset related register of Beacon control */
-
-		/* set MSR to nolink */
-		Set_MSR(padapter, _HW_STATE_NOLINK_);
-		/* reject all data frame */
-		rtw_write16(padapter, REG_RXFLTMAP2, 0x00);
-		/* reset TSF */
-		rtw_write8(padapter, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
-
-		/* disable update TSF */
-		SetBcnCtrlReg(padapter, BIT(4), 0);
-
-		/* ======================================================= */
-	}
-#endif
-
-	rtw_setopmode_cmd(padapter, Ndis802_11Infrastructure, _FALSE);
+	rtw_setopmode_cmd(padapter, Ndis802_11Infrastructure, RTW_CMDF_DIRECTLY);
 
 	{
 		u8 threshold;
 #ifdef CONFIG_USB_HCI
 		/* TH=1 => means that invalidate usb rx aggregation */
 		/* TH=0 => means that validate usb rx aggregation, use init value. */
+#ifdef CONFIG_80211N_HT
 		if (mlmepriv->htpriv.ht_option) {
 			if (padapter->registrypriv.wifi_spec == 1)
 				threshold = 1;
@@ -201,6 +162,7 @@ void sreset_restore_network_station(_adapter *padapter)
 			threshold = 1;
 			rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
 		}
+#endif /* CONFIG_80211N_HT */
 #endif
 	}
 
@@ -218,6 +180,8 @@ void sreset_restore_network_station(_adapter *padapter)
 
 	{
 		u8	join_type = 0;
+
+		rtw_hal_rcr_set_chk_bssid(padapter, MLME_STA_CONNECTING);
 		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
 	}
 
@@ -234,14 +198,12 @@ void sreset_restore_network_station(_adapter *padapter)
 void sreset_restore_network_status(_adapter *padapter)
 {
 	struct mlme_priv *mlmepriv = &padapter->mlmepriv;
-	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
-	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 
 	if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) {
 		RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
 		sreset_restore_network_station(padapter);
-	} else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) {
-		RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
+	} else if (MLME_IS_AP(padapter) || MLME_IS_MESH(padapter)) {
+		RTW_INFO(FUNC_ADPT_FMT" %s\n", FUNC_ADPT_ARG(padapter), MLME_IS_AP(padapter) ? "AP" : "MESH");
 		rtw_ap_restore_network(padapter);
 	} else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE))
 		RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
@@ -273,7 +235,7 @@ void sreset_stop_adapter(_adapter *padapter)
 
 	if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
 		rtw_set_to_roam(padapter, 0);
-		rtw_join_timeout(pmlmepriv);
+		rtw_join_timeout_handler(padapter);
 	}
 
 }
@@ -311,7 +273,7 @@ void sreset_reset(_adapter *padapter)
 	struct mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
 	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
 	_irqL irqL;
-	u32 start = rtw_get_current_time();
+	systime start = rtw_get_current_time();
 	struct dvobj_priv *psdpriv = padapter->dvobj;
 	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
 
@@ -333,6 +295,9 @@ void sreset_reset(_adapter *padapter)
 #ifdef CONFIG_IPS
 	_ips_enter(padapter);
 	_ips_leave(padapter);
+#endif
+#ifdef CONFIG_CONCURRENT_MODE
+	rtw_mi_ap_info_restore(padapter);
 #endif
 	rtw_mi_sreset_adapter_hdl(padapter, _TRUE);/*sreset_start_adapter*/
 
@@ -342,5 +307,8 @@ void sreset_reset(_adapter *padapter)
 
 	RTW_INFO("%s done in %d ms\n", __FUNCTION__, rtw_get_passing_time_ms(start));
 	pdbgpriv->dbg_sreset_cnt++;
+
+	psrtpriv->self_dect_fw = _FALSE;
+	psrtpriv->rx_cnt = 0;
 #endif
 }

+ 235 - 98
core/rtw_sta_mgt.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_STA_MGT_C_
 
 #include <drv_types.h>
@@ -133,6 +128,46 @@ inline bool rtw_st_ctl_chk_reg_rule(struct st_ctl_t *st_ctl, _adapter *adapter,
 	return ret;
 }
 
+void rtw_st_ctl_rx(struct sta_info *sta, u8 *ehdr_pos)
+{
+	_adapter *adapter = sta->padapter;
+	struct ethhdr *etherhdr = (struct ethhdr *)ehdr_pos;
+
+	if (ntohs(etherhdr->h_proto) == ETH_P_IP) {
+		u8 *ip = ehdr_pos + ETH_HLEN;
+
+		if (GET_IPV4_PROTOCOL(ip) == 0x06  /* TCP */
+			&& rtw_st_ctl_chk_reg_s_proto(&sta->st_ctl, 0x06) == _TRUE
+		) {
+			u8 *tcp = ip + GET_IPV4_IHL(ip) * 4;
+
+			if (rtw_st_ctl_chk_reg_rule(&sta->st_ctl, adapter, IPV4_DST(ip), TCP_DST(tcp), IPV4_SRC(ip), TCP_SRC(tcp)) == _TRUE) {
+				if (GET_TCP_SYN(tcp) && GET_TCP_ACK(tcp)) {
+					session_tracker_add_cmd(adapter, sta
+						, IPV4_DST(ip), TCP_DST(tcp)
+						, IPV4_SRC(ip), TCP_SRC(tcp));
+					if (DBG_SESSION_TRACKER)
+						RTW_INFO(FUNC_ADPT_FMT" local:"IP_FMT":"PORT_FMT", remote:"IP_FMT":"PORT_FMT" SYN-ACK\n"
+							, FUNC_ADPT_ARG(adapter)
+							, IP_ARG(IPV4_DST(ip)), PORT_ARG(TCP_DST(tcp))
+							, IP_ARG(IPV4_SRC(ip)), PORT_ARG(TCP_SRC(tcp)));
+				}
+				if (GET_TCP_FIN(tcp)) {
+					session_tracker_del_cmd(adapter, sta
+						, IPV4_DST(ip), TCP_DST(tcp)
+						, IPV4_SRC(ip), TCP_SRC(tcp));
+					if (DBG_SESSION_TRACKER)
+						RTW_INFO(FUNC_ADPT_FMT" local:"IP_FMT":"PORT_FMT", remote:"IP_FMT":"PORT_FMT" FIN\n"
+							, FUNC_ADPT_ARG(adapter)
+							, IP_ARG(IPV4_DST(ip)), PORT_ARG(TCP_DST(tcp))
+							, IP_ARG(IPV4_SRC(ip)), PORT_ARG(TCP_SRC(tcp)));
+				}
+			}
+
+		}
+	}
+}
+
 #define SESSION_TRACKER_FMT IP_FMT":"PORT_FMT" "IP_FMT":"PORT_FMT" %u %d"
 #define SESSION_TRACKER_ARG(st) IP_ARG(&(st)->local_naddr), PORT_ARG(&(st)->local_port), IP_ARG(&(st)->remote_naddr), PORT_ARG(&(st)->remote_port), (st)->status, rtw_get_passing_time_ms((st)->set_time)
 
@@ -165,8 +200,6 @@ void dump_st_ctl(void *sel, struct st_ctl_t *st_ctl)
 void _rtw_init_stainfo(struct sta_info *psta);
 void _rtw_init_stainfo(struct sta_info *psta)
 {
-
-
 	_rtw_memset((u8 *)psta, 0, sizeof(struct sta_info));
 
 	_rtw_spinlock_init(&psta->lock);
@@ -177,62 +210,36 @@ void _rtw_init_stainfo(struct sta_info *psta)
 	/* _rtw_init_listhead(&psta->wakeup_list);	 */
 
 	_rtw_init_queue(&psta->sleep_q);
-	psta->sleepq_len = 0;
 
 	_rtw_init_sta_xmit_priv(&psta->sta_xmitpriv);
 	_rtw_init_sta_recv_priv(&psta->sta_recvpriv);
 
 #ifdef CONFIG_AP_MODE
-
 	_rtw_init_listhead(&psta->asoc_list);
-
 	_rtw_init_listhead(&psta->auth_list);
-
-	psta->expire_to = 0;
-
-	psta->flags = 0;
-
-	psta->capability = 0;
-
 	psta->bpairwise_key_installed = _FALSE;
 
 #ifdef CONFIG_RTW_80211R
 	psta->ft_pairwise_key_installed = _FALSE;
 #endif
-
-#ifdef CONFIG_NATIVEAP_MLME
-	psta->nonerp_set = 0;
-	psta->no_short_slot_time_set = 0;
-	psta->no_short_preamble_set = 0;
-	psta->no_ht_gf_set = 0;
-	psta->no_ht_set = 0;
-	psta->ht_20mhz_set = 0;
-	psta->ht_40mhz_intolerant = 0;
-#endif
-
-#ifdef CONFIG_TX_MCAST2UNI
-	psta->under_exist_checking = 0;
-#endif /* CONFIG_TX_MCAST2UNI */
-
-	psta->keep_alive_trycnt = 0;
-
 #endif /* CONFIG_AP_MODE	 */
 
 	rtw_st_ctl_init(&psta->st_ctl);
-
-
 }
 
 u32	_rtw_init_sta_priv(struct	sta_priv *pstapriv)
 {
+	_adapter *adapter = container_of(pstapriv, _adapter, stapriv);
+	struct macid_ctl_t *macid_ctl = adapter_to_macidctl(adapter);
 	struct sta_info *psta;
 	s32 i;
+	u32 ret = _FAIL;
 
+	pstapriv->padapter = adapter;
 
 	pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA + 4);
-
 	if (!pstapriv->pallocated_stainfo_buf)
-		return _FAIL;
+		goto exit;
 
 	pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 -
 			 ((SIZE_PTR)(pstapriv->pallocated_stainfo_buf) & 3);
@@ -262,9 +269,19 @@ u32	_rtw_init_sta_priv(struct	sta_priv *pstapriv)
 	pstapriv->adhoc_expire_to = 4; /* 4 * 2 = 8 sec */
 
 #ifdef CONFIG_AP_MODE
-
-	pstapriv->sta_dz_bitmap = 0;
-	pstapriv->tim_bitmap = 0;
+	pstapriv->max_aid = macid_ctl->num;
+	pstapriv->rr_aid = 0;
+	pstapriv->started_aid = 1;
+	pstapriv->sta_aid = rtw_zmalloc(pstapriv->max_aid * sizeof(struct sta_info *));
+	if (!pstapriv->sta_aid)
+		goto exit;
+	pstapriv->aid_bmp_len = AID_BMP_LEN(pstapriv->max_aid);
+	pstapriv->sta_dz_bitmap = rtw_zmalloc(pstapriv->aid_bmp_len);
+	if (!pstapriv->sta_dz_bitmap)
+		goto exit;
+	pstapriv->tim_bitmap = rtw_zmalloc(pstapriv->aid_bmp_len);
+	if (!pstapriv->tim_bitmap)
+		goto exit;
 
 	_rtw_init_listhead(&pstapriv->asoc_list);
 	_rtw_init_listhead(&pstapriv->auth_list);
@@ -290,15 +307,29 @@ u32	_rtw_init_sta_priv(struct	sta_priv *pstapriv)
 #endif
 
 #if CONFIG_RTW_MACADDR_ACL
-	_rtw_init_queue(&(pstapriv->acl_list.acl_node_q));
+	for (i = 0; i < RTW_ACL_PERIOD_NUM; i++)
+		rtw_macaddr_acl_init(adapter, i);
 #endif
 
 #if CONFIG_RTW_PRE_LINK_STA
 	rtw_pre_link_sta_ctl_init(pstapriv);
 #endif
 
-	return _SUCCESS;
+	ret = _SUCCESS;
 
+exit:
+	if (ret != _SUCCESS) {
+		if (pstapriv->pallocated_stainfo_buf)
+			rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info) * NUM_STA + 4);
+		#ifdef CONFIG_AP_MODE
+		if (pstapriv->sta_aid)
+			rtw_mfree(pstapriv->sta_aid, pstapriv->max_aid * sizeof(struct sta_info *));
+		if (pstapriv->sta_dz_bitmap)
+			rtw_mfree(pstapriv->sta_dz_bitmap, pstapriv->aid_bmp_len);
+		#endif
+	}
+
+	return ret;
 }
 
 inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta)
@@ -431,7 +462,8 @@ u32	_rtw_free_sta_priv(struct	sta_priv *pstapriv)
 		rtw_mfree_sta_priv_lock(pstapriv);
 
 #if CONFIG_RTW_MACADDR_ACL
-		_rtw_deinit_queue(&(pstapriv->acl_list.acl_node_q));
+		for (index = 0; index < RTW_ACL_PERIOD_NUM; index++)
+			rtw_macaddr_acl_deinit(pstapriv->padapter, index);
 #endif
 
 #if CONFIG_RTW_PRE_LINK_STA
@@ -440,6 +472,14 @@ u32	_rtw_free_sta_priv(struct	sta_priv *pstapriv)
 
 		if (pstapriv->pallocated_stainfo_buf)
 			rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info) * NUM_STA + 4);
+		#ifdef CONFIG_AP_MODE
+		if (pstapriv->sta_aid)
+			rtw_mfree(pstapriv->sta_aid, pstapriv->max_aid * sizeof(struct sta_info *));
+		if (pstapriv->sta_dz_bitmap)
+			rtw_mfree(pstapriv->sta_dz_bitmap, pstapriv->aid_bmp_len);
+		if (pstapriv->tim_bitmap)
+			rtw_mfree(pstapriv->tim_bitmap, pstapriv->aid_bmp_len);
+		#endif
 	}
 
 	return _SUCCESS;
@@ -450,15 +490,15 @@ static void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
 {
 	_adapter *padapter = preorder_ctrl->padapter;
 
-	rtw_init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter, rtw_reordering_ctrl_timeout_handler);
-
+#if defined(CONFIG_80211N_HT) && defined(CONFIG_RECV_REORDERING_CTRL)
+	rtw_init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter, rtw_reordering_ctrl_timeout_handler, preorder_ctrl);
+#endif
 }
 
 /* struct	sta_info *rtw_alloc_stainfo(_queue *pfree_sta_queue, unsigned char *hwaddr) */
-struct	sta_info *rtw_alloc_stainfo(struct	sta_priv *pstapriv, u8 *hwaddr)
+struct	sta_info *rtw_alloc_stainfo(struct	sta_priv *pstapriv, const u8 *hwaddr)
 {
-	_irqL irqL, irqL2;
-	uint tmp_aid;
+	_irqL irqL2;
 	s32	index;
 	_list	*phash_list;
 	struct sta_info	*psta;
@@ -482,14 +522,11 @@ struct	sta_info *rtw_alloc_stainfo(struct	sta_priv *pstapriv, u8 *hwaddr)
 		rtw_list_delete(&(psta->list));
 
 		/* _exit_critical_bh(&(pfree_sta_queue->lock), &irqL); */
-
-		tmp_aid = psta->aid;
-
 		_rtw_init_stainfo(psta);
 
 		psta->padapter = pstapriv->padapter;
 
-		_rtw_memcpy(psta->hwaddr, hwaddr, ETH_ALEN);
+		_rtw_memcpy(psta->cmn.mac_addr, hwaddr, ETH_ALEN);
 
 		index = wifi_mac_hash(hwaddr);
 
@@ -513,10 +550,13 @@ struct	sta_info *rtw_alloc_stainfo(struct	sta_priv *pstapriv, u8 *hwaddr)
 		 * In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable.
 		 * So, we initialize the tid_rxseq variable as the 0xffff. */
 
-		for (i = 0; i < 16; i++)
+		for (i = 0; i < 16; i++) {
 			_rtw_memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2);
+			_rtw_memcpy(&psta->sta_recvpriv.bmc_tid_rxseq[i], &wRxSeqInitialValue, 2);
+			_rtw_memset(&psta->sta_recvpriv.rxcache.iv[i], 0, sizeof(psta->sta_recvpriv.rxcache.iv[i]));
+		}
 
-		rtw_init_timer(&psta->addba_retry_timer, psta->padapter, addba_timer_hdl);
+		rtw_init_timer(&psta->addba_retry_timer, psta->padapter, addba_timer_hdl, psta);
 #ifdef CONFIG_IEEE80211W
 		rtw_init_timer(&psta->dot11w_expire_timer, psta->padapter, sa_query_timer_hdl, psta);
 #endif /* CONFIG_IEEE80211W */
@@ -527,16 +567,14 @@ struct	sta_info *rtw_alloc_stainfo(struct	sta_priv *pstapriv, u8 *hwaddr)
 		/* for A-MPDU Rx reordering buffer control */
 		for (i = 0; i < 16 ; i++) {
 			preorder_ctrl = &psta->recvreorder_ctrl[i];
-
 			preorder_ctrl->padapter = pstapriv->padapter;
-
+			preorder_ctrl->tid = i;
 			preorder_ctrl->enable = _FALSE;
-
 			preorder_ctrl->indicate_seq = 0xffff;
-#ifdef DBG_RX_SEQ
-			RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d\n", __FUNCTION__, __LINE__,
-				 preorder_ctrl->indicate_seq);
-#endif
+			#ifdef DBG_RX_SEQ
+			RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u SN_CLEAR indicate_seq:%d\n"
+				, FUNC_ADPT_ARG(pstapriv->padapter), i, preorder_ctrl->indicate_seq);
+			#endif
 			preorder_ctrl->wend_b = 0xffff;
 			/* preorder_ctrl->wsize_b = (NR_RECVBUFF-2); */
 			preorder_ctrl->wsize_b = 64;/* 64; */
@@ -549,14 +587,15 @@ struct	sta_info *rtw_alloc_stainfo(struct	sta_priv *pstapriv, u8 *hwaddr)
 
 
 		/* init for DM */
-		psta->rssi_stat.undecorated_smoothed_pwdb = (-1);
-		psta->rssi_stat.undecorated_smoothed_cck = (-1);
+		psta->cmn.rssi_stat.rssi = (-1);
+		psta->cmn.rssi_stat.rssi_cck = (-1);
+		psta->cmn.rssi_stat.rssi_ofdm = (-1);
 #ifdef CONFIG_ATMEL_RC_PATCH
 		psta->flag_atmel_rc = 0;
 #endif
 		/* init for the sequence number of received management frame */
 		psta->RxMgmtFrameSeqNum = 0xffff;
-		psta->ra_rpt_linked = _FALSE;
+		_rtw_memset(&psta->sta_stats, 0, sizeof(struct stainfo_stats));
 
 		rtw_alloc_macid(pstapriv->padapter, psta);
 
@@ -585,13 +624,20 @@ u32	rtw_free_stainfo(_adapter *padapter , struct sta_info *psta)
 	struct	xmit_priv	*pxmitpriv = &padapter->xmitpriv;
 	struct	sta_priv *pstapriv = &padapter->stapriv;
 	struct hw_xmit *phwxmit;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
 	int pending_qcnt[4];
 	u8 is_pre_link_sta = _FALSE;
 
 	if (psta == NULL)
 		goto exit;
 
-	is_pre_link_sta = rtw_is_pre_link_sta(pstapriv, psta->hwaddr);
+#ifdef CONFIG_RTW_80211K
+	rm_post_event(padapter, RM_ID_FOR_ALL(psta->cmn.aid), RM_EV_cancel);
+#endif
+
+	is_pre_link_sta = rtw_is_pre_link_sta(pstapriv, psta->cmn.mac_addr);
 
 	if (is_pre_link_sta == _FALSE) {
 		_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL0);
@@ -678,7 +724,6 @@ u32	rtw_free_stainfo(_adapter *padapter , struct sta_info *psta)
 
 #ifdef CONFIG_TDLS
 	psta->tdls_sta_state = TDLS_STATE_NONE;
-	rtw_free_tdls_timer(psta);
 #endif /* CONFIG_TDLS */
 
 	/* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */
@@ -715,7 +760,7 @@ u32	rtw_free_stainfo(_adapter *padapter , struct sta_info *psta)
 
 	}
 
-	if (!((psta->state & WIFI_AP_STATE) || MacAddr_isBcst(psta->hwaddr)) && is_pre_link_sta == _FALSE)
+	if (!((psta->state & WIFI_AP_STATE) || MacAddr_isBcst(psta->cmn.mac_addr)) && is_pre_link_sta == _FALSE)
 		rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _FALSE);
 
 
@@ -754,14 +799,16 @@ u32	rtw_free_stainfo(_adapter *padapter , struct sta_info *psta)
 
 #ifdef CONFIG_NATIVEAP_MLME
 
-	pstapriv->sta_dz_bitmap &= ~BIT(psta->aid);
-	pstapriv->tim_bitmap &= ~BIT(psta->aid);
+	if (pmlmeinfo->state == _HW_STATE_AP_) {
+		rtw_tim_map_clear(padapter, pstapriv->sta_dz_bitmap, psta->cmn.aid);
+		rtw_tim_map_clear(padapter, pstapriv->tim_bitmap, psta->cmn.aid);
 
-	/* rtw_indicate_sta_disassoc_event(padapter, psta); */
+		/* rtw_indicate_sta_disassoc_event(padapter, psta); */
 
-	if ((psta->aid > 0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) {
-		pstapriv->sta_aid[psta->aid - 1] = NULL;
-		psta->aid = 0;
+		if ((psta->cmn.aid > 0) && (pstapriv->sta_aid[psta->cmn.aid - 1] == psta)) {
+			pstapriv->sta_aid[psta->cmn.aid - 1] = NULL;
+			psta->cmn.aid = 0;
+		}
 	}
 
 #endif /* CONFIG_NATIVEAP_MLME	 */
@@ -817,7 +864,7 @@ void rtw_free_all_stainfo(_adapter *padapter)
 			plist = get_next(plist);
 
 			if (pbcmc_stainfo != psta) {
-				if (rtw_is_pre_link_sta(pstapriv, psta->hwaddr) == _FALSE)
+				if (rtw_is_pre_link_sta(pstapriv, psta->cmn.mac_addr) == _FALSE)
 					rtw_list_delete(&psta->hash_list);
 
 				stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
@@ -841,7 +888,7 @@ exit:
 }
 
 /* any station allocated can be searched by hash list */
-struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
+struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, const u8 *hwaddr)
 {
 
 	_irqL	 irqL;
@@ -852,7 +899,7 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
 
 	u32	index;
 
-	u8 *addr;
+	const u8 *addr;
 
 	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
@@ -877,7 +924,7 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
 
 		psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
 
-		if ((_rtw_memcmp(psta->hwaddr, addr, ETH_ALEN)) == _TRUE) {
+		if ((_rtw_memcmp(psta->cmn.mac_addr, addr, ETH_ALEN)) == _TRUE) {
 			/* if found the matched address */
 			break;
 		}
@@ -909,9 +956,10 @@ u32 rtw_init_bcmc_stainfo(_adapter *padapter)
 		goto exit;
 	}
 #ifdef CONFIG_BEAMFORMING
-	psta->txbf_gid = 63;
-	psta->txbf_paid = 0;
+	psta->cmn.bf_info.g_id = 63;
+	psta->cmn.bf_info.p_aid = 0;
 #endif
+
 	ptxservq = &(psta->sta_xmitpriv.be_q);
 
 	/*
@@ -939,14 +987,75 @@ struct sta_info *rtw_get_bcmc_stainfo(_adapter *padapter)
 
 }
 
+#ifdef CONFIG_AP_MODE
+u16 rtw_aid_alloc(_adapter *adapter, struct sta_info *sta)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	u16 aid, i, used_cnt = 0;
+
+	for (i = 0; i < stapriv->max_aid; i++) {
+		aid = ((i + stapriv->started_aid - 1) % stapriv->max_aid) + 1;
+		if (stapriv->sta_aid[aid - 1] == NULL)
+			break;
+		if (++used_cnt >= stapriv->max_num_sta)
+			break;
+	}
+
+	/* check for aid limit and assoc limit  */
+	if (i >= stapriv->max_aid || used_cnt >= stapriv->max_num_sta)
+		aid = 0;
+
+	sta->cmn.aid = aid;
+	if (aid) {
+		stapriv->sta_aid[aid - 1] = sta;
+		if (stapriv->rr_aid)
+			stapriv->started_aid = (aid % stapriv->max_aid) + 1;
+	}
+
+	return aid;
+}
+
+void dump_aid_status(void *sel, _adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	u8 *aid_bmp;
+	u16 i, used_cnt = 0;
+
+	aid_bmp = rtw_zmalloc(stapriv->aid_bmp_len);
+	if (!aid_bmp)
+		return;
+
+	for (i = 1; i <= stapriv->max_aid; i++) {
+		if (stapriv->sta_aid[i - 1]) {
+			aid_bmp[i / 8] |= BIT(i % 8);
+			++used_cnt;
+		}
+	}
+
+	RTW_PRINT_SEL(sel, "used_cnt:%u/%u\n", used_cnt, stapriv->max_aid);
+	RTW_MAP_DUMP_SEL(sel, "aid_map:", aid_bmp, stapriv->aid_bmp_len);
+	RTW_PRINT_SEL(sel, "\n");
+
+	RTW_PRINT_SEL(sel, "%-2s %-11s\n", "rr", "started_aid");
+	RTW_PRINT_SEL(sel, "%2d %11d\n", stapriv->rr_aid, stapriv->started_aid);
+
+	rtw_mfree(aid_bmp, stapriv->aid_bmp_len);
+}
+#endif /* CONFIG_AP_MODE */
+
 #if CONFIG_RTW_MACADDR_ACL
-const char *const _acl_mode_str[] = {
+const char *const _acl_period_str[RTW_ACL_PERIOD_NUM] = {
+	"DEV",
+	"BSS",
+};
+
+const char *const _acl_mode_str[RTW_ACL_MODE_MAX] = {
 	"DISABLED",
 	"ACCEPT_UNLESS_LISTED",
 	"DENY_UNLESS_LISTED",
 };
 
-u8 rtw_access_ctrl(_adapter *adapter, u8 *mac_addr)
+u8 _rtw_access_ctrl(_adapter *adapter, u8 period, const u8 *mac_addr)
 {
 	u8 res = _TRUE;
 	_irqL irqL;
@@ -954,8 +1063,20 @@ u8 rtw_access_ctrl(_adapter *adapter, u8 *mac_addr)
 	struct rtw_wlan_acl_node *acl_node;
 	u8 match = _FALSE;
 	struct sta_priv *stapriv = &adapter->stapriv;
-	struct wlan_acl_pool *acl = &stapriv->acl_list;
-	_queue	*acl_node_q = &acl->acl_node_q;
+	struct wlan_acl_pool *acl;
+	_queue	*acl_node_q;
+
+	if (period >= RTW_ACL_PERIOD_NUM) {
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	acl = &stapriv->acl_list[period];
+	acl_node_q = &acl->acl_node_q;
+
+	if (acl->mode != RTW_ACL_MODE_ACCEPT_UNLESS_LISTED
+		&& acl->mode != RTW_ACL_MODE_DENY_UNLESS_LISTED)
+		goto exit;
 
 	_enter_critical_bh(&(acl_node_q->lock), &irqL);
 	head = get_list_head(acl_node_q);
@@ -975,26 +1096,42 @@ u8 rtw_access_ctrl(_adapter *adapter, u8 *mac_addr)
 
 	if (acl->mode == RTW_ACL_MODE_ACCEPT_UNLESS_LISTED)
 		res = (match == _TRUE) ?  _FALSE : _TRUE;
-	else if (acl->mode == RTW_ACL_MODE_DENY_UNLESS_LISTED)
+	else /* RTW_ACL_MODE_DENY_UNLESS_LISTED */
 		res = (match == _TRUE) ?  _TRUE : _FALSE;
-	else
-		res = _TRUE;
 
+exit:
 	return res;
 }
 
-void dump_macaddr_acl(void *sel, _adapter *adapter)
+u8 rtw_access_ctrl(_adapter *adapter, const u8 *mac_addr)
 {
-	struct sta_priv *stapriv = &adapter->stapriv;
-	struct wlan_acl_pool *acl = &stapriv->acl_list;
 	int i;
 
-	RTW_PRINT_SEL(sel, "mode:%s(%d)\n", acl_mode_str(acl->mode), acl->mode);
-	RTW_PRINT_SEL(sel, "num:%d/%d\n", acl->num, NUM_ACL);
-	for (i = 0; i < NUM_ACL; i++) {
-		if (acl->aclnode[i].valid == _FALSE)
-			continue;
-		RTW_PRINT_SEL(sel, MAC_FMT"\n", MAC_ARG(acl->aclnode[i].addr));
+	for (i = 0; i < RTW_ACL_PERIOD_NUM; i++)
+		if (_rtw_access_ctrl(adapter, i, mac_addr) == _FALSE)
+			return _FALSE;
+
+	return _TRUE;
+}
+
+void dump_macaddr_acl(void *sel, _adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl;
+	int i, j;
+
+	for (j = 0; j < RTW_ACL_PERIOD_NUM; j++) {
+		RTW_PRINT_SEL(sel, "period:%s(%d)\n", acl_period_str(j), j);
+
+		acl = &stapriv->acl_list[j];
+		RTW_PRINT_SEL(sel, "mode:%s(%d)\n", acl_mode_str(acl->mode), acl->mode);
+		RTW_PRINT_SEL(sel, "num:%d/%d\n", acl->num, NUM_ACL);
+		for (i = 0; i < NUM_ACL; i++) {
+			if (acl->aclnode[i].valid == _FALSE)
+				continue;
+			RTW_PRINT_SEL(sel, MAC_FMT"\n", MAC_ARG(acl->aclnode[i].addr));
+		}
+		RTW_PRINT_SEL(sel, "\n");
 	}
 }
 #endif /* CONFIG_RTW_MACADDR_ACL */

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 374 - 169
core/rtw_tdls.c


+ 451 - 119
core/rtw_vht.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,18 +11,100 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _RTW_VHT_C
 
 #include <drv_types.h>
 #include <hal_data.h>
 
 #ifdef CONFIG_80211AC_VHT
+const u16 _vht_max_mpdu_len[] = {
+	3895,
+	7991,
+	11454,
+	0,
+};
+
+const u8 _vht_sup_ch_width_set_to_bw_cap[] = {
+	BW_CAP_80M,
+	BW_CAP_80M | BW_CAP_160M,
+	BW_CAP_80M | BW_CAP_160M | BW_CAP_80_80M,
+	0,
+};
+
+const char *const _vht_sup_ch_width_set_str[] = {
+	"80MHz",
+	"160MHz",
+	"160MHz & 80+80MHz",
+	"BW-RSVD",
+};
+
+void dump_vht_cap_ie_content(void *sel, const u8 *buf, u32 buf_len)
+{
+	if (buf_len != VHT_CAP_IE_LEN) {
+		RTW_PRINT_SEL(sel, "Invalid VHT capability IE len:%d != %d\n", buf_len, VHT_CAP_IE_LEN);
+		return;
+	}
+
+	RTW_PRINT_SEL(sel, "cap_info:%02x %02x %02x %02x: MAX_MPDU_LEN:%u %s%s%s%s%s RX-STBC:%u MAX_AMPDU_LEN:%u\n"
+		, *(buf), *(buf + 1), *(buf + 2), *(buf + 3)
+		, vht_max_mpdu_len(GET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(buf))
+		, vht_sup_ch_width_set_str(GET_VHT_CAPABILITY_ELE_CHL_WIDTH(buf))
+		, GET_VHT_CAPABILITY_ELE_RX_LDPC(buf) ? " RX-LDPC" : ""
+		, GET_VHT_CAPABILITY_ELE_SHORT_GI80M(buf) ? " SGI-80" : ""
+		, GET_VHT_CAPABILITY_ELE_SHORT_GI160M(buf) ? " SGI-160" : ""
+		, GET_VHT_CAPABILITY_ELE_TX_STBC(buf) ? " TX-STBC" : ""
+		, GET_VHT_CAPABILITY_ELE_RX_STBC(buf)
+		, VHT_MAX_AMPDU_LEN(GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(buf))
+	);
+}
+
+void dump_vht_cap_ie(void *sel, const u8 *ie, u32 ie_len)
+{
+	const u8 *vht_cap_ie;
+	sint vht_cap_ielen;
+
+	vht_cap_ie = rtw_get_ie(ie, WLAN_EID_VHT_CAPABILITY, &vht_cap_ielen, ie_len);
+	if (!ie || vht_cap_ie != ie)
+		return;
+
+	dump_vht_cap_ie_content(sel, vht_cap_ie + 2, vht_cap_ielen);
+}
+
+const char *const _vht_op_ch_width_str[] = {
+	"20 or 40MHz",
+	"80MHz",
+	"160MHz",
+	"80+80MHz",
+	"BW-RSVD",
+};
+
+void dump_vht_op_ie_content(void *sel, const u8 *buf, u32 buf_len)
+{
+	if (buf_len != VHT_OP_IE_LEN) {
+		RTW_PRINT_SEL(sel, "Invalid VHT operation IE len:%d != %d\n", buf_len, VHT_OP_IE_LEN);
+		return;
+	}
+
+	RTW_PRINT_SEL(sel, "%s, ch0:%u, ch1:%u\n"
+		, vht_op_ch_width_str(GET_VHT_OPERATION_ELE_CHL_WIDTH(buf))
+		, GET_VHT_OPERATION_ELE_CENTER_FREQ1(buf)
+		, GET_VHT_OPERATION_ELE_CENTER_FREQ2(buf)
+	);
+}
+
+void dump_vht_op_ie(void *sel, const u8 *ie, u32 ie_len)
+{
+	const u8 *vht_op_ie;
+	sint vht_op_ielen;
+
+	vht_op_ie = rtw_get_ie(ie, WLAN_EID_VHT_OPERATION, &vht_op_ielen, ie_len);
+	if (!ie || vht_op_ie != ie)
+		return;
+
+	dump_vht_op_ie_content(sel, vht_op_ie + 2, vht_op_ielen);
+}
+
 /*				20/40/80,	ShortGI,	MCS Rate  */
 const u16 VHT_MCS_DATA_RATE[3][2][30] = {
 	{	{
@@ -183,43 +265,53 @@ void	rtw_vht_use_default_setting(_adapter *padapter)
 	/* Beamforming setting */
 	CLEAR_FLAGS(pvhtpriv->beamform_cap);
 #ifdef CONFIG_BEAMFORMING
-	rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER, (u8 *)&bHwSupportBeamformer);
-	rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE, (u8 *)&bHwSupportBeamformee);
-	mu_bfer = _FALSE;
-	mu_bfee = _FALSE;
-	rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMER, &mu_bfer);
-	rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMEE, &mu_bfee);
-	if (TEST_FLAG(pregistrypriv->beamform_cap, BIT0) && bHwSupportBeamformer) {
+#ifdef RTW_BEAMFORMING_VERSION_2
+	/* only enable beamforming in STA client mode */
+	if (MLME_IS_STA(padapter) && !MLME_IS_GC(padapter)
+				  && !MLME_IS_ADHOC(padapter)
+				  && !MLME_IS_MESH(padapter))
+#endif
+	{
+		rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER,
+			(u8 *)&bHwSupportBeamformer);
+		rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE,
+			(u8 *)&bHwSupportBeamformee);
+		mu_bfer = _FALSE;
+		mu_bfee = _FALSE;
+		rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMER, &mu_bfer);
+		rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMEE, &mu_bfee);
+		if (TEST_FLAG(pregistrypriv->beamform_cap, BIT0) && bHwSupportBeamformer) {
 #ifdef CONFIG_CONCURRENT_MODE
-		if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
+			if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
+				SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);
+				RTW_INFO("[VHT] CONCURRENT AP Support Beamformer\n");
+				if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2))
+				    && (_TRUE == mu_bfer)) {
+					SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE);
+					RTW_INFO("[VHT] Support MU-MIMO AP\n");
+				}
+			} else
+				RTW_INFO("[VHT] CONCURRENT not AP ;not allow  Support Beamformer\n");
+#else
 			SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);
-			RTW_INFO("[VHT] CONCURRENT AP Support Beamformer\n");
+			RTW_INFO("[VHT] Support Beamformer\n");
 			if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2))
-			    && (_TRUE == mu_bfer)) {
+			    && (_TRUE == mu_bfer)
+			    && ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {
 				SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE);
 				RTW_INFO("[VHT] Support MU-MIMO AP\n");
 			}
-		} else
-			RTW_INFO("[VHT] CONCURRENT not AP ;not allow  Support Beamformer\n");
-#else
-		SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);
-		RTW_INFO("[VHT] Support Beamformer\n");
-		if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2))
-		    && (_TRUE == mu_bfer)
-		    && ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {
-			SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE);
-			RTW_INFO("[VHT] Support MU-MIMO AP\n");
-		}
 #endif
-	}
-	if (TEST_FLAG(pregistrypriv->beamform_cap, BIT1) && bHwSupportBeamformee) {
-		SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);
-		RTW_INFO("[VHT] Support Beamformee\n");
-		if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(3))
-		    && (_TRUE == mu_bfee)
-		    && ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)) {
-			SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE);
-			RTW_INFO("[VHT] Support MU-MIMO STA\n");
+		}
+		if (TEST_FLAG(pregistrypriv->beamform_cap, BIT1) && bHwSupportBeamformee) {
+			SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);
+			RTW_INFO("[VHT] Support Beamformee\n");
+			if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(3))
+			    && (_TRUE == mu_bfee)
+			    && ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)) {
+				SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE);
+				RTW_INFO("[VHT] Support MU-MIMO STA\n");
+			}
 		}
 	}
 #endif /* CONFIG_BEAMFORMING */
@@ -266,6 +358,38 @@ u64	rtw_vht_mcs_map_to_bitmap(u8 *mcs_map, u8 nss)
 	return bitmap;
 }
 
+#ifdef CONFIG_BEAMFORMING
+void update_sta_vht_info_apmode_bf_cap(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct vht_priv	*pvhtpriv_ap = &pmlmepriv->vhtpriv;
+	struct vht_priv	*pvhtpriv_sta = &psta->vhtpriv;
+	u16	cur_beamform_cap = 0;
+
+	/* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */
+	if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) &&
+	    GET_VHT_CAPABILITY_ELE_SU_BFEE(pvhtpriv_sta->vht_cap)) {
+		SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);
+		/*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/
+		SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pvhtpriv_sta->vht_cap) << 8);
+	}
+
+	/* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */
+	if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) &&
+	    GET_VHT_CAPABILITY_ELE_SU_BFER(pvhtpriv_sta->vht_cap)) {
+		SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);
+		/*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/
+		SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pvhtpriv_sta->vht_cap) << 12);
+	}
+
+	if (cur_beamform_cap)
+		RTW_INFO("Current STA(%d) VHT Beamforming Setting = %02X\n", psta->cmn.aid, cur_beamform_cap);
+
+	pvhtpriv_sta->beamform_cap = cur_beamform_cap;
+	psta->cmn.bf_info.vht_beamform_cap = cur_beamform_cap;
+}
+#endif
+
 void	update_sta_vht_info_apmode(_adapter *padapter, PVOID sta)
 {
 	struct sta_info	*psta = (struct sta_info *)sta;
@@ -273,35 +397,52 @@ void	update_sta_vht_info_apmode(_adapter *padapter, PVOID sta)
 	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
 	struct vht_priv	*pvhtpriv_ap = &pmlmepriv->vhtpriv;
 	struct vht_priv	*pvhtpriv_sta = &psta->vhtpriv;
-	struct ht_priv		*phtpriv_sta = &psta->htpriv;
-	u8	cur_ldpc_cap = 0, cur_stbc_cap = 0, bw_mode = 0;
-	u16	cur_beamform_cap = 0;
+	u8	cur_ldpc_cap = 0, cur_stbc_cap = 0;
+	s8 bw_mode = -1;
 	u8	*pcap_mcs;
 
 	if (pvhtpriv_sta->vht_option == _FALSE)
 		return;
 
-	bw_mode = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&pvhtpriv_sta->vht_op_mode_notify);
+	if (pvhtpriv_sta->op_present) {
+		switch (GET_VHT_OPERATION_ELE_CHL_WIDTH(pvhtpriv_sta->vht_op)) {
+		case 1: /* 80MHz */
+		case 2: /* 160MHz */
+		case 3: /* 80+80 */
+			bw_mode = CHANNEL_WIDTH_80; /* only support up to 80MHz for now */
+			break;
+		}
+	}
 
-	/* if (bw_mode > psta->bw_mode) */
-	psta->bw_mode = bw_mode;
+	if (pvhtpriv_sta->notify_present)
+		bw_mode = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&pvhtpriv_sta->vht_op_mode_notify);
+	else if (MLME_IS_AP(padapter)) {
+		/* for VHT client without Operating Mode Notify IE; minimal 80MHz */
+		if (bw_mode < CHANNEL_WIDTH_80)
+			bw_mode = CHANNEL_WIDTH_80;
+	}
+
+	if (bw_mode != -1)
+		psta->cmn.bw_mode = bw_mode; /* update bw_mode only if get value from VHT IEs */
+
+	psta->cmn.ra_info.is_vht_enable = _TRUE;
 
 	/* B4 Rx LDPC */
 	if (TEST_FLAG(pvhtpriv_ap->ldpc_cap, LDPC_VHT_ENABLE_TX) &&
 	    GET_VHT_CAPABILITY_ELE_RX_LDPC(pvhtpriv_sta->vht_cap)) {
 		SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX));
-		RTW_INFO("Current STA(%d) VHT LDPC = %02X\n", psta->aid, cur_ldpc_cap);
+		RTW_INFO("Current STA(%d) VHT LDPC = %02X\n", psta->cmn.aid, cur_ldpc_cap);
 	}
 	pvhtpriv_sta->ldpc_cap = cur_ldpc_cap;
 
-	if (psta->bw_mode > pmlmeext->cur_bwmode)
-		psta->bw_mode = pmlmeext->cur_bwmode;
+	if (psta->cmn.bw_mode > pmlmeext->cur_bwmode)
+		psta->cmn.bw_mode = pmlmeext->cur_bwmode;
 
-	if (psta->bw_mode == CHANNEL_WIDTH_80) {
+	if (psta->cmn.bw_mode == CHANNEL_WIDTH_80) {
 		/* B5 Short GI for 80 MHz */
 		pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE;
 		/* RTW_INFO("Current STA ShortGI80MHz = %d\n", pvhtpriv_sta->sgi_80m); */
-	} else if (psta->bw_mode >= CHANNEL_WIDTH_160) {
+	} else if (psta->cmn.bw_mode >= CHANNEL_WIDTH_160) {
 		/* B5 Short GI for 80 MHz */
 		pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE;
 		/* RTW_INFO("Current STA ShortGI160MHz = %d\n", pvhtpriv_sta->sgi_80m); */
@@ -311,29 +452,12 @@ void	update_sta_vht_info_apmode(_adapter *padapter, PVOID sta)
 	if (TEST_FLAG(pvhtpriv_ap->stbc_cap, STBC_VHT_ENABLE_TX) &&
 	    GET_VHT_CAPABILITY_ELE_RX_STBC(pvhtpriv_sta->vht_cap)) {
 		SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX));
-		RTW_INFO("Current STA(%d) VHT STBC = %02X\n", psta->aid, cur_stbc_cap);
+		RTW_INFO("Current STA(%d) VHT STBC = %02X\n", psta->cmn.aid, cur_stbc_cap);
 	}
 	pvhtpriv_sta->stbc_cap = cur_stbc_cap;
 
 #ifdef CONFIG_BEAMFORMING
-	/* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */
-	if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) &&
-	    GET_VHT_CAPABILITY_ELE_SU_BFEE(pvhtpriv_sta->vht_cap)) {
-		SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);
-		/*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/
-		SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pvhtpriv_sta->vht_cap) << 8);
-	}
-
-	/* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */
-	if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) &&
-	    GET_VHT_CAPABILITY_ELE_SU_BFER(pvhtpriv_sta->vht_cap)) {
-		SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);
-		/*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/
-		SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pvhtpriv_sta->vht_cap) << 12);
-	}
-	pvhtpriv_sta->beamform_cap = cur_beamform_cap;
-	if (cur_beamform_cap)
-		RTW_INFO("Current STA(%d) VHT Beamforming Setting = %02X\n", psta->aid, cur_beamform_cap);
+	update_sta_vht_info_apmode_bf_cap(padapter, psta);
 #endif
 
 	/* B23 B24 B25 Maximum A-MPDU Length Exponent */
@@ -358,6 +482,83 @@ void	update_hw_vht_param(_adapter *padapter)
 		rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len));
 }
 
+#ifdef ROKU_PRIVATE
+u8 VHT_get_ss_from_map(u8 *vht_mcs_map)
+{
+	u8 i, j;
+	u8 ss = 0;
+
+	for (i = 0; i < 2; i++) {
+		if (vht_mcs_map[i] != 0xff) {
+			for (j = 0; j < 8; j += 2) {
+				if (((vht_mcs_map[i] >> j) & 0x03) == 0x03)
+					break;
+				ss++;
+			}
+		}
+
+	}
+
+return ss;
+}
+
+void VHT_caps_handler_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE)
+{
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct vht_priv_infra_ap	*pvhtpriv = &pmlmepriv->vhtpriv_infra_ap;
+	u8      cur_stbc_cap_infra_ap = 0;
+	u16	cur_beamform_cap_infra_ap = 0;
+	u8	*pcap_mcs;
+	u8	*pcap_mcs_tx;
+	u8	Rx_ss = 0, Tx_ss = 0;
+
+	struct mlme_ext_priv		*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info		*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (pIE == NULL)
+		return;
+
+	pmlmeinfo->ht_vht_received |= BIT(1);
+
+	pvhtpriv->ldpc_cap_infra_ap = GET_VHT_CAPABILITY_ELE_RX_LDPC(pIE->data);
+
+	if (GET_VHT_CAPABILITY_ELE_RX_STBC(pIE->data))
+		SET_FLAG(cur_stbc_cap_infra_ap, STBC_VHT_ENABLE_RX);
+	if (GET_VHT_CAPABILITY_ELE_TX_STBC(pIE->data))
+		SET_FLAG(cur_stbc_cap_infra_ap, STBC_VHT_ENABLE_TX);
+	pvhtpriv->stbc_cap_infra_ap = cur_stbc_cap_infra_ap;
+
+	/*store ap info for channel bandwidth*/
+	pvhtpriv->channel_width_infra_ap = GET_VHT_CAPABILITY_ELE_CHL_WIDTH(pIE->data);
+
+	/*check B11: SU Beamformer Capable and B12: SU Beamformee B19: MU Beamformer B20:MU Beamformee*/
+	if (GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data))
+		SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);
+	if (GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data))
+		SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);
+	if (GET_VHT_CAPABILITY_ELE_MU_BFER(pIE->data))
+		SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE);
+	if (GET_VHT_CAPABILITY_ELE_MU_BFEE(pIE->data))
+		SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE);
+	pvhtpriv->beamform_cap_infra_ap = cur_beamform_cap_infra_ap;
+
+	/*store information about vht_mcs_set*/
+	pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pIE->data);
+	pcap_mcs_tx = GET_VHT_CAPABILITY_ELE_TX_MCS(pIE->data);
+	_rtw_memcpy(pvhtpriv->vht_mcs_map_infra_ap, pcap_mcs, 2);
+	_rtw_memcpy(pvhtpriv->vht_mcs_map_tx_infra_ap, pcap_mcs_tx, 2);
+
+	Rx_ss = VHT_get_ss_from_map(pvhtpriv->vht_mcs_map_infra_ap);
+	Tx_ss = VHT_get_ss_from_map(pvhtpriv->vht_mcs_map_tx_infra_ap);
+	if (Rx_ss >= Tx_ss) {
+		pvhtpriv->number_of_streams_infra_ap = Rx_ss;
+	} else{
+		pvhtpriv->number_of_streams_infra_ap = Tx_ss;
+	}
+
+}
+#endif /* ROKU_PRIVATE */
+
 void VHT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE)
 {
 	struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
@@ -489,24 +690,28 @@ void rtw_process_vht_op_mode_notify(_adapter *padapter, u8 *pframe, PVOID sta)
 	struct sta_info		*psta = (struct sta_info *)sta;
 	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
 	struct vht_priv		*pvhtpriv = &pmlmepriv->vhtpriv;
-	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
 	struct registry_priv *regsty = adapter_to_regsty(padapter);
 	u8	target_bw;
 	u8	target_rxss, current_rxss;
 	u8	update_ra = _FALSE;
+	u8 tx_nss = 0, rf_type = RF_1T1R;
+	struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
 
 	if (pvhtpriv->vht_option == _FALSE)
 		return;
 
 	target_bw = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(pframe);
-	target_rxss = (GET_VHT_OPERATING_MODE_FIELD_RX_NSS(pframe) + 1);
 
-	if (target_bw != psta->bw_mode) {
+	rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+	tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num);
+	target_rxss = rtw_min(tx_nss, (GET_VHT_OPERATING_MODE_FIELD_RX_NSS(pframe) + 1));
+
+	if (target_bw != psta->cmn.bw_mode) {
 		if (hal_is_bw_support(padapter, target_bw)
 		    && REGSTY_IS_BW_5G_SUPPORT(regsty, target_bw)
 		   ) {
 			update_ra = _TRUE;
-			psta->bw_mode = target_bw;
+			psta->cmn.bw_mode = target_bw;
 		}
 	}
 
@@ -519,7 +724,7 @@ void rtw_process_vht_op_mode_notify(_adapter *padapter, u8 *pframe, PVOID sta)
 		rtw_vht_nss_to_mcsmap(target_rxss, vht_mcs_map, psta->vhtpriv.vht_mcs_map);
 		_rtw_memcpy(psta->vhtpriv.vht_mcs_map, vht_mcs_map, 2);
 
-		rtw_hal_update_sta_rate_mask(padapter, psta);
+		rtw_hal_update_sta_ra_info(padapter, psta);
 	}
 
 	if (update_ra)
@@ -588,7 +793,7 @@ u32	rtw_build_vht_op_mode_notify_ie(_adapter *padapter, u8 *pbuf, u8 bw)
 
 u32	rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf)
 {
-	u8	bw, rf_type, rf_num, rx_stbc_nss = 0;
+	u8	bw, rf_num, rx_stbc_nss = 0;
 	u16	HighestRate;
 	u8	*pcap, *pcap_mcs;
 	u32	len = 0;
@@ -596,6 +801,8 @@ u32	rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf)
 	struct registry_priv *pregistrypriv = &padapter->registrypriv;
 	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
 	struct vht_priv	*pvhtpriv = &pmlmepriv->vhtpriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 
 	pcap = pvhtpriv->vht_cap;
 	_rtw_memset(pcap, 0, 32);
@@ -604,19 +811,19 @@ u32	rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf)
 	rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset);
 	rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz);
 
-	RTW_DBG("%s, line%d, Available RX buf size = %d bytes\n.", __FUNCTION__, __LINE__, max_recvbuf_sz - rx_packet_offset);
+	RTW_DBG("%s, line%d, Available RX buf size = %d bytes\n", __FUNCTION__, __LINE__, max_recvbuf_sz - rx_packet_offset);
 
 	if ((max_recvbuf_sz - rx_packet_offset) >= 11454) {
 		SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 2);
-		RTW_INFO("%s, line%d, Set MAX MPDU len = 11454 bytes\n.", __FUNCTION__, __LINE__);
+		RTW_INFO("%s, line%d, Set MAX MPDU len = 11454 bytes\n", __FUNCTION__, __LINE__);
 	} else if ((max_recvbuf_sz - rx_packet_offset) >= 7991) {
 		SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 1);
-		RTW_INFO("%s, line%d, Set MAX MPDU len = 7991 bytes\n.", __FUNCTION__, __LINE__);
+		RTW_INFO("%s, line%d, Set MAX MPDU len = 7991 bytes\n", __FUNCTION__, __LINE__);
 	} else if ((max_recvbuf_sz - rx_packet_offset) >= 3895) {
 		SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 0);
-		RTW_INFO("%s, line%d, Set MAX MPDU len = 3895 bytes\n.", __FUNCTION__, __LINE__);
+		RTW_INFO("%s, line%d, Set MAX MPDU len = 3895 bytes\n", __FUNCTION__, __LINE__);
 	} else
-		RTW_ERR("%s, line%d, Error!! Available RX buf size < 3895 bytes\n.", __FUNCTION__, __LINE__);
+		RTW_ERR("%s, line%d, Error!! Available RX buf size < 3895 bytes\n", __FUNCTION__, __LINE__);
 
 	/* B2 B3 Supported Channel Width Set */
 	if (hal_chk_bw_cap(padapter, BW_CAP_160M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_160)) {
@@ -654,7 +861,7 @@ u32	rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf)
 		SET_VHT_CAPABILITY_ELE_RX_STBC(pcap, rx_stbc_nss);
 		RTW_INFO("[VHT] Declare supporting RX STBC = %d\n", rx_stbc_nss);
 	}
-
+	#ifdef CONFIG_BEAMFORMING
 	/* B11 SU Beamformer Capable */
 	if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {
 		SET_VHT_CAPABILITY_ELE_SU_BFER(pcap, 1);
@@ -673,8 +880,16 @@ u32	rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf)
 	if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) {
 		SET_VHT_CAPABILITY_ELE_SU_BFEE(pcap, 1);
 		RTW_INFO("[VHT] Declare supporting SU Bfee\n");
-		/* B13 14 15 Compressed Steering Number of Beamformer Antennas Supported */
+
 		rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num);
+
+		/* IOT action suggested by Yu Chen 2017/3/3 */
+#ifdef CONFIG_80211AC_VHT
+		if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) &&
+			!pvhtpriv->ap_is_mu_bfer)
+			rf_num = (rf_num >= 2 ? 2 : rf_num);
+#endif
+		/* B13 14 15 Compressed Steering Number of Beamformer Antennas Supported */
 		SET_VHT_CAPABILITY_ELE_BFER_ANT_SUPP(pcap, rf_num);
 		/* B20 SU Beamformee Capable */
 		if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) {
@@ -682,6 +897,7 @@ u32	rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf)
 			RTW_INFO("[VHT] Declare supporting MU Bfee\n");
 		}
 	}
+	#endif/*CONFIG_BEAMFORMING*/
 
 	/* B21 VHT TXOP PS */
 	SET_VHT_CAPABILITY_ELE_TXOP_PS(pcap, 0);
@@ -717,61 +933,109 @@ u32	rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf)
 
 u32 rtw_restructure_vht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len)
 {
-	u32	ielen = 0, out_len = 0;
-	u8	cap_len = 0, notify_len = 0, notify_bw = 0, operation_bw = 0, supported_chnl_width = 0;
-	u8	*p, *pframe;
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
+	RT_CHANNEL_INFO *chset = rfctl->channel_set;
+	u32	ielen;
+	u8 max_bw;
+	u8 oper_ch, oper_bw = CHANNEL_WIDTH_20, oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	u8 *out_vht_op_ie, *ht_op_ie, *vht_cap_ie, *vht_op_ie;
 	struct registry_priv *pregistrypriv = &padapter->registrypriv;
 	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
 	struct vht_priv	*pvhtpriv = &pmlmepriv->vhtpriv;
 
 	rtw_vht_use_default_setting(padapter);
 
-	p = rtw_get_ie(in_ie + 12, EID_VHTCapability, &ielen, in_len - 12);
-	if (p && ielen > 0) {
-		supported_chnl_width = GET_VHT_CAPABILITY_ELE_CHL_WIDTH(p + 2);
+	ht_op_ie = rtw_get_ie(in_ie + 12, WLAN_EID_HT_OPERATION, &ielen, in_len - 12);
+	if (!ht_op_ie || ielen != HT_OP_IE_LEN)
+		goto exit;
+	vht_cap_ie = rtw_get_ie(in_ie + 12, EID_VHTCapability, &ielen, in_len - 12);
+	if (!vht_cap_ie || ielen != VHT_CAP_IE_LEN)
+		goto exit;
+	vht_op_ie = rtw_get_ie(in_ie + 12, EID_VHTOperation, &ielen, in_len - 12);
+	if (!vht_op_ie || ielen != VHT_OP_IE_LEN)
+		goto exit;
 
-		/* VHT Capabilities element */
-		cap_len = rtw_build_vht_cap_ie(padapter, out_ie + *pout_len);
-		*pout_len += cap_len;
+	/* VHT Capabilities element */
+	*pout_len += rtw_build_vht_cap_ie(padapter, out_ie + *pout_len);
 
-		/* Get HT BW */
-		p = rtw_get_ie(in_ie + 12, _HT_EXTRA_INFO_IE_, &ielen, in_len - 12);
-		if (p && ielen > 0) {
-			struct HT_info_element *pht_info = (struct HT_info_element *)(p + 2);
-			if (pht_info->infos[0] & BIT(2))
-				operation_bw = CHANNEL_WIDTH_40;
-			else
-				operation_bw = CHANNEL_WIDTH_20;
-		}
 
-		/* VHT Operation element */
-		p = rtw_get_ie(in_ie + 12, EID_VHTOperation, &ielen, in_len - 12);
-		if (p && ielen > 0) {
-			out_len = *pout_len;
-			if (GET_VHT_OPERATION_ELE_CHL_WIDTH(p + 2) >= 1) {
-				if (supported_chnl_width == 2)
-					operation_bw = CHANNEL_WIDTH_80_80;
-				else if (supported_chnl_width == 1)
-					operation_bw = CHANNEL_WIDTH_160;
-				else
-					operation_bw = CHANNEL_WIDTH_80;
+	/* VHT Operation element */
+	out_vht_op_ie = out_ie + *pout_len;
+	rtw_set_ie(out_vht_op_ie, EID_VHTOperation, VHT_OP_IE_LEN, vht_op_ie + 2 , pout_len);
+
+	/* get primary channel from HT_OP_IE */
+	oper_ch = GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2);
+
+	/* find the largest bw supported by both registry and hal */
+	max_bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv));
+
+	if (max_bw >= CHANNEL_WIDTH_40) {
+		/* get bw offset form HT_OP_IE */
+		if (GET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2)) {
+			switch (GET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2)) {
+			case SCA:
+				oper_bw = CHANNEL_WIDTH_40;
+				oper_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+				break;
+			case SCB:
+				oper_bw = CHANNEL_WIDTH_40;
+				oper_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+				break;
 			}
-			pframe = rtw_set_ie(out_ie + out_len, EID_VHTOperation, ielen, p + 2 , pout_len);
 		}
 
-		/* find the largest bw supported by both registry and hal */
-		notify_bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv));
-
-		if (notify_bw > operation_bw)
-			notify_bw = operation_bw;
+		if (oper_bw == CHANNEL_WIDTH_40) {
+			switch (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2)) {
+			case 1: /* 80MHz */
+			case 2: /* 160MHz */
+			case 3: /* 80+80 */
+				oper_bw = CHANNEL_WIDTH_80; /* only support up to 80MHz for now */
+				break;
+			}
 
-		/* Operating Mode Notification element */
-		notify_len = rtw_build_vht_op_mode_notify_ie(padapter, out_ie + *pout_len, notify_bw);
-		*pout_len += notify_len;
+			oper_bw = rtw_min(oper_bw, max_bw);
+
+			/* try downgrage bw to fit in channel plan setting */
+			while (!rtw_chset_is_chbw_valid(chset, oper_ch, oper_bw, oper_offset)
+				|| (IS_DFS_SLAVE_WITH_RD(rfctl)
+					&& !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))
+					&& rtw_chset_is_chbw_non_ocp(chset, oper_ch, oper_bw, oper_offset))
+			) {
+				oper_bw--;
+				if (oper_bw == CHANNEL_WIDTH_20) {
+					oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+					break;
+				}
+			}
+		}
+	}
 
-		pvhtpriv->vht_option = _TRUE;
+	rtw_warn_on(!rtw_chset_is_chbw_valid(chset, oper_ch, oper_bw, oper_offset));
+	if (IS_DFS_SLAVE_WITH_RD(rfctl) && !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl)))
+		rtw_warn_on(rtw_chset_is_chbw_non_ocp(chset, oper_ch, oper_bw, oper_offset));
+
+	/* update VHT_OP_IE */
+	if (oper_bw < CHANNEL_WIDTH_80) {
+		SET_VHT_OPERATION_ELE_CHL_WIDTH(out_vht_op_ie + 2, 0);
+		SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(out_vht_op_ie + 2, 0);
+		SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(out_vht_op_ie + 2, 0);
+	} else if (oper_bw == CHANNEL_WIDTH_80) {
+		u8 cch = rtw_get_center_ch(oper_ch, oper_bw, oper_offset);
+
+		SET_VHT_OPERATION_ELE_CHL_WIDTH(out_vht_op_ie + 2, 1);
+		SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(out_vht_op_ie + 2, cch);
+		SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(out_vht_op_ie + 2, 0);
+	} else {
+		RTW_ERR(FUNC_ADPT_FMT" unsupported BW:%u\n", FUNC_ADPT_ARG(padapter), oper_bw);
+		rtw_warn_on(1);
 	}
 
+	/* Operating Mode Notification element */
+	*pout_len += rtw_build_vht_op_mode_notify_ie(padapter, out_ie + *pout_len, oper_bw);
+
+	pvhtpriv->vht_option = _TRUE;
+
+exit:
 	return pvhtpriv->vht_option;
 
 }
@@ -800,4 +1064,72 @@ void VHTOnAssocRsp(_adapter *padapter)
 	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MAX_TIME, (u8 *)(&pvhtpriv->vht_highest_rate));
 }
 
+void rtw_vht_ies_attach(_adapter *padapter, WLAN_BSSID_EX *pnetwork)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8 cap_len, operation_len;
+	uint len = 0;
+	sint ie_len = 0;
+	u8 *p = NULL;
+
+	p = rtw_get_ie(pnetwork->IEs + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len,
+			(pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0)
+		return;
+
+	rtw_vht_use_default_setting(padapter);
+
+	/* VHT Operation mode notifiy bit in Extended IE (127) */
+	SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(pmlmepriv->ext_capab_ie_data, 1);
+	pmlmepriv->ext_capab_ie_len = 10;
+	rtw_set_ie(pnetwork->IEs + pnetwork->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len);
+	pnetwork->IELength += pmlmepriv->ext_capab_ie_len;
+
+	/* VHT Capabilities element */
+	cap_len = rtw_build_vht_cap_ie(padapter, pnetwork->IEs + pnetwork->IELength);
+	pnetwork->IELength += cap_len;
+
+	/* VHT Operation element */
+	operation_len = rtw_build_vht_operation_ie(padapter, pnetwork->IEs + pnetwork->IELength,
+										pnetwork->Configuration.DSConfig);
+	pnetwork->IELength += operation_len;
+
+	rtw_check_for_vht20(padapter, pnetwork->IEs + _BEACON_IE_OFFSET_, pnetwork->IELength - _BEACON_IE_OFFSET_);
+
+	pmlmepriv->vhtpriv.vht_option = _TRUE;
+}
+
+void rtw_vht_ies_detach(_adapter *padapter, WLAN_BSSID_EX *pnetwork)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	rtw_remove_bcn_ie(padapter, pnetwork, EID_EXTCapability);
+	rtw_remove_bcn_ie(padapter, pnetwork, EID_VHTCapability);
+	rtw_remove_bcn_ie(padapter, pnetwork, EID_VHTOperation);
+
+	pmlmepriv->vhtpriv.vht_option = _FALSE;
+}
+
+void rtw_check_for_vht20(_adapter *adapter, u8 *ies, int ies_len)
+{
+	u8 ht_ch, ht_bw, ht_offset;
+	u8 vht_ch, vht_bw, vht_offset;
+
+	rtw_ies_get_chbw(ies, ies_len, &ht_ch, &ht_bw, &ht_offset, 1, 0);
+	rtw_ies_get_chbw(ies, ies_len, &vht_ch, &vht_bw, &vht_offset, 1, 1);
+
+	if (ht_bw == CHANNEL_WIDTH_20 && vht_bw >= CHANNEL_WIDTH_80) {
+		u8 *vht_op_ie;
+		int vht_op_ielen;
+
+		RTW_INFO(FUNC_ADPT_FMT" vht80 is not allowed without ht40\n", FUNC_ADPT_ARG(adapter));
+		vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len);
+		if (vht_op_ie && vht_op_ielen) {
+			RTW_INFO(FUNC_ADPT_FMT" switch to vht20\n", FUNC_ADPT_ARG(adapter));
+			SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0);
+			SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0);
+			SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
+		}
+	}
+}
 #endif /* CONFIG_80211AC_VHT */

+ 79 - 7
core/rtw_wapi.c

@@ -1,3 +1,17 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 #ifdef CONFIG_WAPI_SUPPORT
 
 #include <linux/unistd.h>
@@ -438,7 +452,8 @@ add to support WAPI to N-mode
 *****************************************************************************/
 u8 rtw_wapi_check_for_drop(
 	_adapter *padapter,
-	union recv_frame *precv_frame
+	union recv_frame *precv_frame,
+	u8 *ehdr_ops
 )
 {
 	PRT_WAPI_T     pWapiInfo = &(padapter->wapiInfo);
@@ -449,7 +464,7 @@ u8 rtw_wapi_check_for_drop(
 	struct recv_frame_hdr *precv_hdr = &precv_frame->u.hdr;
 	u8					WapiAEPNInitialValueSrc[16] = {0x37, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
 	u8					WapiAEMultiCastPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
-	u8					*ptr = precv_frame->u.hdr.rx_data;
+	u8					*ptr = ehdr_ops;
 	int					i;
 
 	WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__);
@@ -1050,7 +1065,7 @@ void wapi_test_set_key(struct _adapter *padapter, u8 *buf)
 void wapi_test_init(struct _adapter *padapter)
 {
 	u8 keybuf[100];
-	u8 mac_addr[6] = {0x00, 0xe0, 0x4c, 0x72, 0x04, 0x70};
+	u8 mac_addr[ETH_ALEN] = {0x00, 0xe0, 0x4c, 0x72, 0x04, 0x70};
 	u8 UskDataKey[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
 	u8 UskMicKey[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
 	u8 UskId = 0;
@@ -1076,7 +1091,7 @@ void wapi_test_init(struct _adapter *padapter)
 	keybuf[2] = 1; 				/* AE */
 	keybuf[3] = 0; 				/* not update */
 
-	memcpy(keybuf + 4, mac_addr, 6);
+	memcpy(keybuf + 4, mac_addr, ETH_ALEN);
 	memcpy(keybuf + 10, UskDataKey, 16);
 	memcpy(keybuf + 26, UskMicKey, 16);
 	keybuf[42] = UskId;
@@ -1088,7 +1103,7 @@ void wapi_test_init(struct _adapter *padapter)
 	keybuf[2] = 0; 				/* AE */
 	keybuf[3] = 0; 				/* not update */
 
-	memcpy(keybuf + 4, mac_addr, 6);
+	memcpy(keybuf + 4, mac_addr, ETH_ALEN);
 	memcpy(keybuf + 10, UskDataKey, 16);
 	memcpy(keybuf + 26, UskMicKey, 16);
 	keybuf[42] = UskId;
@@ -1101,7 +1116,7 @@ void wapi_test_init(struct _adapter *padapter)
 	keybuf[1] = 1;                               /* Enable TX */
 	keybuf[2] = 1; 				/* AE */
 	keybuf[3] = 0;                              /* not update */
-	memcpy(keybuf + 4, mac_addr, 6);
+	memcpy(keybuf + 4, mac_addr, ETH_ALEN);
 	memcpy(keybuf + 10, MskDataKey, 16);
 	memcpy(keybuf + 26, MskMicKey, 16);
 	keybuf[42] = MskId;
@@ -1112,7 +1127,7 @@ void wapi_test_init(struct _adapter *padapter)
 	keybuf[1] = 1;                               /* Enable TX */
 	keybuf[2] = 0; 				/* AE */
 	keybuf[3] = 0;                              /* not update */
-	memcpy(keybuf + 4, mac_addr, 6);
+	memcpy(keybuf + 4, mac_addr, ETH_ALEN);
 	memcpy(keybuf + 10, MskDataKey, 16);
 	memcpy(keybuf + 26, MskMicKey, 16);
 	keybuf[42] = MskId;
@@ -1237,4 +1252,61 @@ bool rtw_wapi_drop_for_key_absent(_adapter *padapter, u8 *pRA)
 	return bDrop;
 }
 
+void rtw_wapi_set_set_encryption(_adapter *padapter, struct ieee_param *param)
+{
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	PRT_WAPI_T			pWapiInfo = &padapter->wapiInfo;
+	PRT_WAPI_STA_INFO	pWapiSta;
+	u8					WapiASUEPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+	u8					WapiAEPNInitialValueSrc[16] = {0x37, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+	u8					WapiAEMultiCastPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+
+	if (param->u.crypt.set_tx == 1) {
+		list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) {
+			if (_rtw_memcmp(pWapiSta->PeerMacAddr, param->sta_addr, 6)) {
+				_rtw_memcpy(pWapiSta->lastTxUnicastPN, WapiASUEPNInitialValueSrc, 16);
+
+				pWapiSta->wapiUsk.bSet = true;
+				_rtw_memcpy(pWapiSta->wapiUsk.dataKey, param->u.crypt.key, 16);
+				_rtw_memcpy(pWapiSta->wapiUsk.micKey, param->u.crypt.key + 16, 16);
+				pWapiSta->wapiUsk.keyId = param->u.crypt.idx ;
+				pWapiSta->wapiUsk.bTxEnable = true;
+
+				_rtw_memcpy(pWapiSta->lastRxUnicastPNBEQueue, WapiAEPNInitialValueSrc, 16);
+				_rtw_memcpy(pWapiSta->lastRxUnicastPNBKQueue, WapiAEPNInitialValueSrc, 16);
+				_rtw_memcpy(pWapiSta->lastRxUnicastPNVIQueue, WapiAEPNInitialValueSrc, 16);
+				_rtw_memcpy(pWapiSta->lastRxUnicastPNVOQueue, WapiAEPNInitialValueSrc, 16);
+				_rtw_memcpy(pWapiSta->lastRxUnicastPN, WapiAEPNInitialValueSrc, 16);
+				pWapiSta->wapiUskUpdate.bTxEnable = false;
+				pWapiSta->wapiUskUpdate.bSet = false;
+
+				if (psecuritypriv->sw_encrypt == false || psecuritypriv->sw_decrypt == false) {
+					/* set unicast key for ASUE */
+					rtw_wapi_set_key(padapter, &pWapiSta->wapiUsk, pWapiSta, false, false);
+				}
+			}
+		}
+	} else {
+		list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) {
+			if (_rtw_memcmp(pWapiSta->PeerMacAddr, get_bssid(pmlmepriv), 6)) {
+				pWapiSta->wapiMsk.bSet = true;
+				_rtw_memcpy(pWapiSta->wapiMsk.dataKey, param->u.crypt.key, 16);
+				_rtw_memcpy(pWapiSta->wapiMsk.micKey, param->u.crypt.key + 16, 16);
+				pWapiSta->wapiMsk.keyId = param->u.crypt.idx ;
+				pWapiSta->wapiMsk.bTxEnable = false;
+				if (!pWapiSta->bSetkeyOk)
+					pWapiSta->bSetkeyOk = true;
+				pWapiSta->bAuthenticateInProgress = false;
+
+				_rtw_memcpy(pWapiSta->lastRxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16);
+
+				if (psecuritypriv->sw_decrypt == false) {
+					/* set rx broadcast key for ASUE */
+					rtw_wapi_set_key(padapter, &pWapiSta->wapiMsk, pWapiSta, true, false);
+				}
+			}
+		}
+	}
+}
 #endif

+ 14 - 0
core/rtw_wapi_sms4.c

@@ -1,3 +1,17 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 #ifdef CONFIG_WAPI_SUPPORT
 
 #include <linux/unistd.h>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 407 - 274
core/rtw_wlan_util.c


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 547 - 297
core/rtw_xmit.c


+ 32 - 8
hal/HalPwrSeqCmd.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 /*++
 Copyright (c) Realtek Semiconductor Corp. All rights reserved.
 
@@ -54,9 +49,11 @@ u8 HalPwrSeqCmdParsing(
 {
 	WLAN_PWR_CFG	PwrCfgCmd = {0};
 	u8				bPollingBit = _FALSE;
+	u8				bHWICSupport = _FALSE;
 	u32				AryIdx = 0;
 	u8				value = 0;
 	u32				offset = 0;
+	u8				flag = 0;
 	u32				pollingCount = 0; /* polling autoload done. */
 	u32				maxPollingCnt = 5000;
 
@@ -111,6 +108,14 @@ u8 HalPwrSeqCmdParsing(
 
 				bPollingBit = _FALSE;
 				offset = GET_PWR_CFG_OFFSET(PwrCfgCmd);
+
+				rtw_hal_get_hwreg(padapter, HW_VAR_PWR_CMD, &bHWICSupport);
+				if (bHWICSupport && offset == 0x06) {
+					flag = 0;
+					maxPollingCnt = 100000;
+				} else
+					maxPollingCnt = 5000;
+
 #ifdef CONFIG_GSPI_HCI
 				if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO)
 					offset = SPI_LOCAL_OFFSET | offset;
@@ -131,7 +136,26 @@ u8 HalPwrSeqCmdParsing(
 
 					if (pollingCount++ > maxPollingCnt) {
 						RTW_ERR("HalPwrSeqCmdParsing: Fail to polling Offset[%#x]=%02x\n", offset, value);
-						return _FALSE;
+
+						/* For PCIE + USB package poll power bit timeout issue only modify 8821AE and 8723BE */
+						if (bHWICSupport && offset == 0x06  && flag == 0) {
+
+							RTW_ERR("[WARNING] PCIE polling(0x%X) timeout(%d), Toggle 0x04[3] and try again.\n", offset, maxPollingCnt);
+							if (IS_HARDWARE_TYPE_8723DE(padapter))
+								PlatformEFIOWrite1Byte(padapter, 0x40, (PlatformEFIORead1Byte(padapter, 0x40)) & (~BIT3));
+
+							PlatformEFIOWrite1Byte(padapter, 0x04, PlatformEFIORead1Byte(padapter, 0x04) | BIT3);
+							PlatformEFIOWrite1Byte(padapter, 0x04, PlatformEFIORead1Byte(padapter, 0x04) & ~BIT3);
+
+							if (IS_HARDWARE_TYPE_8723DE(padapter))
+								PlatformEFIOWrite1Byte(padapter, 0x40, PlatformEFIORead1Byte(padapter, 0x40)|BIT3);
+
+							/* Retry Polling Process one more time */
+							pollingCount = 0;
+							flag = 1;
+						} else {
+							return _FALSE;
+						}
 					}
 				} while (!bPollingBit);
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 899 - 932
hal/btc/halbtc8821c1ant.c


+ 348 - 366
hal/btc/halbtc8821c1ant.h

@@ -1,3 +1,17 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 
 #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1)
 
@@ -9,482 +23,450 @@
 #define	BT_8821C_1ANT_COEX_DBG					0
 #define	BT_AUTO_REPORT_ONLY_8821C_1ANT				1
 
-#define	BT_INFO_8821C_1ANT_B_FTP						BIT(7)
-#define	BT_INFO_8821C_1ANT_B_A2DP					BIT(6)
-#define	BT_INFO_8821C_1ANT_B_HID						BIT(5)
+#define	BT_INFO_8821C_1ANT_B_FTP				BIT(7)
+#define	BT_INFO_8821C_1ANT_B_A2DP				BIT(6)
+#define	BT_INFO_8821C_1ANT_B_HID				BIT(5)
 #define	BT_INFO_8821C_1ANT_B_SCO_BUSY				BIT(4)
 #define	BT_INFO_8821C_1ANT_B_ACL_BUSY				BIT(3)
 #define	BT_INFO_8821C_1ANT_B_INQ_PAGE				BIT(2)
 #define	BT_INFO_8821C_1ANT_B_SCO_ESCO				BIT(1)
 #define	BT_INFO_8821C_1ANT_B_CONNECTION				BIT(0)
 
-#define	BT_INFO_8821C_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_)	\
-	(((_BT_INFO_EXT_&BIT(0))) ? TRUE : FALSE)
-
 #define	BTC_RSSI_COEX_THRESH_TOL_8821C_1ANT		2
 
-#define  BT_8821C_1ANT_WIFI_NOISY_THRESH							30   /* max: 255 */
-#define  BT_8821C_1ANT_DEFAULT_ISOLATION						15	 /*  unit: dB */
-
-
-/* for Antenna detection */
-#define	BT_8821C_1ANT_ANTDET_PSDTHRES_BACKGROUND					50
-#define	BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION				70
-#define	BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION			55
-#define	BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT							35
-#define	BT_8821C_1ANT_ANTDET_RETRY_INTERVAL							10	/* retry timer if ant det is fail, unit: second */
-#define	BT_8821C_1ANT_ANTDET_SWEEPPOINT_DELAY							60000
-#define	BT_8821C_1ANT_ANTDET_ENABLE									0
-#define	BT_8821C_1ANT_ANTDET_BTTXTIME									100
-#define	BT_8821C_1ANT_ANTDET_BTTXCHANNEL								39
-#define	BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT						50
-
-#define	BT_8821C_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT		30000
+#define  BT_8821C_1ANT_WIFI_NOISY_THRESH			30
+#define  BT_8821C_1ANT_DEFAULT_ISOLATION			15
 
 enum bt_8821c_1ant_signal_state {
-	BT_8821C_1ANT_SIG_STA_SET_TO_LOW		= 0x0,
-	BT_8821C_1ANT_SIG_STA_SET_BY_HW		= 0x0,
-	BT_8821C_1ANT_SIG_STA_SET_TO_HIGH		= 0x1,
-	BT_8821C_1ANT_SIG_STA_MAX
+	BT_8821C_1ANT_GNT_SET_TO_LOW		= 0x0,
+	BT_8821C_1ANT_GNT_SET_TO_HIGH		= 0x1,
+	BT_8821C_1ANT_GNT_SET_BY_HW		= 0x2,
+	BT_8821C_1ANT_GNT_SET_MAX
 };
 
 enum bt_8821c_1ant_path_ctrl_owner {
 	BT_8821C_1ANT_PCO_BTSIDE		= 0x0,
-	BT_8821C_1ANT_PCO_WLSIDE	= 0x1,
+	BT_8821C_1ANT_PCO_WLSIDE		= 0x1,
 	BT_8821C_1ANT_PCO_MAX
 };
 
 enum bt_8821c_1ant_gnt_ctrl_type {
-	BT_8821C_1ANT_GNT_TYPE_CTRL_BY_PTA		= 0x0,
-	BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW		= 0x1,
+	BT_8821C_1ANT_GNT_TYPE_CTRL_BY_PTA	= 0x0,
+	BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW	= 0x1,
 	BT_8821C_1ANT_GNT_TYPE_MAX
 };
 
 enum bt_8821c_1ant_gnt_ctrl_block {
 	BT_8821C_1ANT_GNT_BLOCK_RFC_BB		= 0x0,
-	BT_8821C_1ANT_GNT_BLOCK_RFC			= 0x1,
-	BT_8821C_1ANT_GNT_BLOCK_BB			= 0x2,
+	BT_8821C_1ANT_GNT_BLOCK_RFC		= 0x1,
+	BT_8821C_1ANT_GNT_BLOCK_BB		= 0x2,
 	BT_8821C_1ANT_GNT_BLOCK_MAX
 };
 
 enum bt_8821c_1ant_lte_coex_table_type {
-	BT_8821C_1ANT_CTT_WL_VS_LTE			= 0x0,
-	BT_8821C_1ANT_CTT_BT_VS_LTE			= 0x1,
+	BT_8821C_1ANT_CTT_WL_VS_LTE		= 0x0,
+	BT_8821C_1ANT_CTT_BT_VS_LTE		= 0x1,
 	BT_8821C_1ANT_CTT_MAX
 };
 
 enum bt_8821c_1ant_lte_break_table_type {
-	BT_8821C_1ANT_LBTT_WL_BREAK_LTE			= 0x0,
-	BT_8821C_1ANT_LBTT_BT_BREAK_LTE				= 0x1,
-	BT_8821C_1ANT_LBTT_LTE_BREAK_WL			= 0x2,
-	BT_8821C_1ANT_LBTT_LTE_BREAK_BT				= 0x3,
+	BT_8821C_1ANT_LBTT_WL_BREAK_LTE		= 0x0,
+	BT_8821C_1ANT_LBTT_BT_BREAK_LTE		= 0x1,
+	BT_8821C_1ANT_LBTT_LTE_BREAK_WL		= 0x2,
+	BT_8821C_1ANT_LBTT_LTE_BREAK_BT		= 0x3,
 	BT_8821C_1ANT_LBTT_MAX
 };
 
 enum bt_info_src_8821c_1ant {
-	BT_INFO_SRC_8821C_1ANT_WIFI_FW			= 0x0,
-	BT_INFO_SRC_8821C_1ANT_BT_RSP				= 0x1,
-	BT_INFO_SRC_8821C_1ANT_BT_ACTIVE_SEND		= 0x2,
-	BT_INFO_SRC_8821C_1ANT_MAX
+	BT_8821C_1ANT_INFO_SRC_WIFI_FW		= 0x0,
+	BT_8821C_1ANT_INFO_SRC_BT_RSP		= 0x1,
+	BT_8821C_1ANT_INFO_SRC_BT_ACT		= 0x2,
+	BT_8821C_1ANT_INFO_SRC_MAX
 };
 
 enum bt_8821c_1ant_bt_status {
-	BT_8821C_1ANT_BT_STATUS_NON_CONNECTED_IDLE	= 0x0,
-	BT_8821C_1ANT_BT_STATUS_CONNECTED_IDLE		= 0x1,
-	BT_8821C_1ANT_BT_STATUS_INQ_PAGE				= 0x2,
-	BT_8821C_1ANT_BT_STATUS_ACL_BUSY				= 0x3,
-	BT_8821C_1ANT_BT_STATUS_SCO_BUSY				= 0x4,
-	BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY			= 0x5,
-	BT_8821C_1ANT_BT_STATUS_MAX
+	BT_8821C_1ANT_BSTATUS_NCON_IDLE		= 0x0,
+	BT_8821C_1ANT_BSTATUS_CON_IDLE		= 0x1,
+	BT_8821C_1ANT_BSTATUS_INQ_PAGE		= 0x2,
+	BT_8821C_1ANT_BSTATUS_ACL_BUSY		= 0x3,
+	BT_8821C_1ANT_BSTATUS_SCO_BUSY		= 0x4,
+	BT_8821C_1ANT_BSTATUS_ACL_SCO_BUSY	= 0x5,
+	BT_8821C_1ANT_BSTATUS_MAX
 };
 
 enum bt_8821c_1ant_wifi_status {
-	BT_8821C_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE				= 0x0,
-	BT_8821C_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN		= 0x1,
-	BT_8821C_1ANT_WIFI_STATUS_CONNECTED_SCAN					= 0x2,
-	BT_8821C_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT				= 0x3,
-	BT_8821C_1ANT_WIFI_STATUS_CONNECTED_IDLE					= 0x4,
-	BT_8821C_1ANT_WIFI_STATUS_CONNECTED_BUSY					= 0x5,
-	BT_8821C_1ANT_WIFI_STATUS_MAX
+	BT_8821C_1ANT_WSTATUS_NCON_IDLE		= 0x0,
+	BT_8821C_1ANT_WSTATUS_NCON_SCAN		= 0x1,
+	BT_8821C_1ANT_WSTATUS_CON_SCAN		= 0x2,
+	BT_8821C_1ANT_WSTATUS_CON_SPECPKT	= 0x3,
+	BT_8821C_1ANT_WSTATUS_CON_IDLE		= 0x4,
+	BT_8821C_1ANT_WSTATUS_CON_BUSY		= 0x5,
+	BT_8821C_1ANT_WSTATUS_MAX
 };
 
 enum bt_8821c_1ant_coex_algo {
-	BT_8821C_1ANT_COEX_ALGO_UNDEFINED			= 0x0,
-	BT_8821C_1ANT_COEX_ALGO_SCO				= 0x1,
-	BT_8821C_1ANT_COEX_ALGO_HID				= 0x2,
-	BT_8821C_1ANT_COEX_ALGO_A2DP				= 0x3,
-	BT_8821C_1ANT_COEX_ALGO_A2DP_PANHS		= 0x4,
-	BT_8821C_1ANT_COEX_ALGO_PANEDR			= 0x5,
-	BT_8821C_1ANT_COEX_ALGO_PANHS			= 0x6,
-	BT_8821C_1ANT_COEX_ALGO_PANEDR_A2DP		= 0x7,
-	BT_8821C_1ANT_COEX_ALGO_PANEDR_HID		= 0x8,
-	BT_8821C_1ANT_COEX_ALGO_HID_A2DP_PANEDR	= 0x9,
-	BT_8821C_1ANT_COEX_ALGO_HID_A2DP			= 0xa,
-	BT_8821C_1ANT_COEX_ALGO_MAX				= 0xb,
+	BT_8821C_1ANT_COEX_UNDEFINED		= 0x0,
+	BT_8821C_1ANT_COEX_SCO			= 0x1,
+	BT_8821C_1ANT_COEX_HID			= 0x2,
+	BT_8821C_1ANT_COEX_A2DP			= 0x3,
+	BT_8821C_1ANT_COEX_A2DP_PANHS		= 0x4,
+	BT_8821C_1ANT_COEX_PAN			= 0x5,
+	BT_8821C_1ANT_COEX_PANHS		= 0x6,
+	BT_8821C_1ANT_COEX_PAN_A2DP		= 0x7,
+	BT_8821C_1ANT_COEX_PAN_HID		= 0x8,
+	BT_8821C_1ANT_COEX_HID_A2DP_PAN		= 0x9,
+	BT_8821C_1ANT_COEX_HID_A2DP		= 0xa,
+	BT_8821C_1ANT_COEX_MAX			= 0xb,
 };
 
 enum bt_8821c_1ant_ext_ant_switch_type {
-	BT_8821C_1ANT_EXT_ANT_SWITCH_USE_DPDT		= 0x0,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_USE_SPDT		= 0x1,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_NONE			= 0x2,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_MAX
+	BT_8821C_1ANT_USE_DPDT		= 0x0,
+	BT_8821C_1ANT_USE_SPDT		= 0x1,
+	BT_8821C_1ANT_SWITCH_NONE	= 0x2,
+	BT_8821C_1ANT_SWITCH_MAX
 };
 
 
 enum bt_8821c_1ant_ext_ant_switch_ctrl_type {
-	BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW	= 0x0,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA		= 0x1,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV	= 0x2,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_MAC		= 0x3,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT		= 0x4,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_MAX
+	BT_8821C_1ANT_CTRL_BY_BBSW	= 0x0,
+	BT_8821C_1ANT_CTRL_BY_PTA	= 0x1,
+	BT_8821C_1ANT_CTRL_BY_ANTDIV	= 0x2,
+	BT_8821C_1ANT_CTRL_BY_MAC	= 0x3,
+	BT_8821C_1ANT_CTRL_BY_BT	= 0x4,
+	BT_8821C_1ANT_CTRL_BY_FW	= 0x5,
+	BT_8821C_1ANT_CTRL_MAX
 };
 
 enum bt_8821c_1ant_ext_ant_switch_pos_type {
-	BT_8821C_1ANT_EXT_ANT_SWITCH_TO_BT			= 0x0,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_TO_WLG			= 0x1,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_TO_WLA			= 0x2,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_TO_NOCARE		= 0x3,
-	BT_8821C_1ANT_EXT_ANT_SWITCH_TO_MAX
+	BT_8821C_1ANT_TO_BT		= 0x0,
+	BT_8821C_1ANT_TO_WLG		= 0x1,
+	BT_8821C_1ANT_TO_WLA		= 0x2,
+	BT_8821C_1ANT_TO_NOCARE		= 0x3,
+	BT_8821C_1ANT_TO_MAX
 };
 
-enum bt_8821c_1ant_ext_band_switch_pos_type {
-	BT_8821C_1ANT_EXT_BAND_SWITCH_TO_WLG			= 0x0,
-	BT_8821C_1ANT_EXT_BAND_SWITCH_TO_WLA			= 0x1,
-	BT_8821C_1ANT_EXT_BAND_SWITCH_TO_MAX
+enum bt_8821c_1ant_phase {
+	BT_8821C_1ANT_PHASE_INIT	= 0x0,
+	BT_8821C_1ANT_PHASE_WONLY	= 0x1,
+	BT_8821C_1ANT_PHASE_WOFF	= 0x2,
+	BT_8821C_1ANT_PHASE_2G		= 0x3,
+	BT_8821C_1ANT_PHASE_5G		= 0x4,
+	BT_8821C_1ANT_PHASE_BTMP	= 0x5,
+	BT_8821C_1ANT_PHASE_ANTDET	= 0x6,
+	BT_8821C_1ANT_PHASE_POWERON	= 0x7,
+	BT_8821C_1ANT_PHASE_MCC		= 0x8,
+	BT_8821C_1ANT_PHASE_MAX
 };
 
-enum bt_8821c_1ant_int_block {
-	BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG			= 0x0,
-	BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG		= 0x1,
-	BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG		= 0x2,
-	BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_MAX
+enum bt_8821c_1ant_scoreboard {
+	BT_8821C_1ANT_SCBD_ACTIVE	= BIT(0),
+	BT_8821C_1ANT_SCBD_ONOFF	= BIT(1),
+	BT_8821C_1ANT_SCBD_SCAN		= BIT(2),
+	BT_8821C_1ANT_SCBD_UNDERTEST	= BIT(3),
+	BT_8821C_1ANT_SCBD_WLBUSY	= BIT(6),
+	BT_8821C_1ANT_SCBD_BTCQDDR	= BIT(10)
 };
 
-enum bt_8821c_1ant_phase {
-	BT_8821C_1ANT_PHASE_COEX_INIT								= 0x0,
-	BT_8821C_1ANT_PHASE_WLANONLY_INIT							= 0x1,
-	BT_8821C_1ANT_PHASE_WLAN_OFF								= 0x2,
-	BT_8821C_1ANT_PHASE_2G_RUNTIME								= 0x3,
-	BT_8821C_1ANT_PHASE_5G_RUNTIME								= 0x4,
-	BT_8821C_1ANT_PHASE_BTMPMODE									= 0x5,
-	BT_8821C_1ANT_PHASE_ANTENNA_DET								= 0x6,
-	BT_8821C_1ANT_PHASE_COEX_POWERON							= 0x7,
-	BT_8821C_1ANT_PHASE_MAX
+enum bt_8821c_1ant_RUNREASON {
+	BT_8821C_1ANT_RSN_2GSCANSTART	= 0x0,
+	BT_8821C_1ANT_RSN_5GSCANSTART	= 0x1,
+	BT_8821C_1ANT_RSN_SCANFINISH	= 0x2,
+	BT_8821C_1ANT_RSN_2GSWITCHBAND	= 0x3,
+	BT_8821C_1ANT_RSN_5GSWITCHBAND	= 0x4,
+	BT_8821C_1ANT_RSN_2GCONSTART	= 0x5,
+	BT_8821C_1ANT_RSN_5GCONSTART	= 0x6,
+	BT_8821C_1ANT_RSN_2GCONFINISH	= 0x7,
+	BT_8821C_1ANT_RSN_5GCONFINISH	= 0x8,
+	BT_8821C_1ANT_RSN_2GMEDIA	= 0x9,
+	BT_8821C_1ANT_RSN_5GMEDIA	= 0xa,
+	BT_8821C_1ANT_RSN_MEDIADISCON	= 0xb,
+	BT_8821C_1ANT_RSN_2GSPECIALPKT	= 0xc,
+	BT_8821C_1ANT_RSN_5GSPECIALPKT	= 0xd,
+	BT_8821C_1ANT_RSN_BTINFO	= 0xe,
+	BT_8821C_1ANT_RSN_PERIODICAL	= 0xf,
+	BT_8821C_1ANT_RSN_PNP		= 0x10,
+	BT_8821C_1ANT_RSN_MAX
 };
 
-enum bt_8821c_1ant_Scoreboard {
-	BT_8821C_1ANT_SCOREBOARD_ACTIVE								= BIT(0),
-	BT_8821C_1ANT_SCOREBOARD_ONOFF								= BIT(1),
-	BT_8821C_1ANT_SCOREBOARD_SCAN								= BIT(2),
-	BT_8821C_1ANT_SCOREBOARD_UNDERTEST							= BIT(3),
-	BT_8821C_1ANT_SCOREBOARD_WLBUSY								= BIT(6)
+enum bt_8821c_1ant_WL_LINK_MODE {
+	BT_8821C_1ANT_WLINK_2G1PORT	= 0x0,
+	BT_8821C_1ANT_WLINK_2GMPORT	= 0x1,
+	BT_8821C_1ANT_WLINK_25GMPORT	= 0x2,
+	BT_8821C_1ANT_WLINK_5G		= 0x3,
+	BT_8821C_1ANT_WLINK_2GGO	= 0x4,
+	BT_8821C_1ANT_WLINK_BTMR	= 0x5,
+	BT_8821C_1ANT_WLINK_MAX
 };
 
 struct coex_dm_8821c_1ant {
 	/* hw setting */
-	u32		pre_ant_pos_type;
 	u32		cur_ant_pos_type;
+
 	/* fw mechanism */
 	boolean		cur_ignore_wlan_act;
-	boolean		pre_ignore_wlan_act;
-	u8		pre_ps_tdma;
+
 	u8		cur_ps_tdma;
 	u8		ps_tdma_para[5];
-	u8		ps_tdma_du_adj_type;
-	boolean		pre_ps_tdma_on;
 	boolean		cur_ps_tdma_on;
-	boolean		pre_bt_auto_report;
+
 	boolean		cur_bt_auto_report;
-	u8		pre_lps;
 	u8		cur_lps;
-	u8		pre_rpwm;
 	u8		cur_rpwm;
 
 	/* sw mechanism */
-	boolean	pre_low_penalty_ra;
 	boolean		cur_low_penalty_ra;
-	u32		pre_val0x6c0;
+
 	u32		cur_val0x6c0;
-	u32		pre_val0x6c4;
 	u32		cur_val0x6c4;
-	u32		pre_val0x6c8;
 	u32		cur_val0x6c8;
-	u8		pre_val0x6cc;
 	u8		cur_val0x6cc;
-	boolean		limited_dig;
-
-	u32		backup_arfr_cnt1;	/* Auto Rate Fallback Retry cnt */
-	u32		backup_arfr_cnt2;	/* Auto Rate Fallback Retry cnt */
-	u16		backup_retry_limit;
-	u8		backup_ampdu_max_time;
 
 	/* algorithm related */
-	u8		pre_algorithm;
 	u8		cur_algorithm;
 	u8		bt_status;
 	u8		wifi_chnl_info[3];
 
-	u32		pre_ra_mask;
-	u32		cur_ra_mask;
-	u8		pre_arfr_type;
-	u8		cur_arfr_type;
-	u8		pre_retry_limit_type;
-	u8		cur_retry_limit_type;
-	u8		pre_ampdu_time_type;
-	u8		cur_ampdu_time_type;
 	u32		arp_cnt;
 
-	u32		pre_ext_ant_switch_status;
 	u32		cur_ext_ant_switch_status;
-
-	u8		pre_ext_band_switch_status;
-	u8		cur_ext_band_switch_status;
-
-	u8		pre_int_block_status;
-	u8		cur_int_block_status;
-
-	u8		error_condition;
+	u32		setting_tdma;
 };
 
 struct coex_sta_8821c_1ant {
-	boolean					bt_disabled;
-	boolean					bt_link_exist;
-	boolean					sco_exist;
-	boolean					a2dp_exist;
-	boolean					hid_exist;
-	boolean					pan_exist;
-	u8					num_of_profile;
-
-	boolean					under_lps;
-	boolean					under_ips;
-	u32					specific_pkt_period_cnt;
-	u32					high_priority_tx;
-	u32					high_priority_rx;
-	u32					low_priority_tx;
-	u32					low_priority_rx;
-	boolean             is_hiPri_rx_overhead;
-	s8					bt_rssi;
-	u8					pre_bt_rssi_state;
-	u8					pre_wifi_rssi_state[4];
-	u8					bt_info_c2h[BT_INFO_SRC_8821C_1ANT_MAX][10];
-	u32					bt_info_c2h_cnt[BT_INFO_SRC_8821C_1ANT_MAX];
-	boolean					bt_whck_test;
-	boolean					c2h_bt_inquiry_page;
-	boolean				c2h_bt_remote_name_req;
-	boolean					c2h_bt_page;				/* Add for win8.1 page out issue */
-	boolean					wifi_is_high_pri_task;		/* Add for win8.1 page out issue */
-
-	u8					bt_info_ext;
-	u8					bt_info_ext2;
-	u32					pop_event_cnt;
-	u8					scan_ap_num;
-	u8					bt_retry_cnt;
-
-	u32					crc_ok_cck;
-	u32					crc_ok_11g;
-	u32					crc_ok_11n;
-	u32					crc_ok_11n_vht;
-
-	u32					crc_err_cck;
-	u32					crc_err_11g;
-	u32					crc_err_11n;
-	u32					crc_err_11n_vht;
-
-	boolean					cck_lock;
-	boolean					pre_ccklock;
-	boolean					cck_ever_lock;
-	u8					coex_table_type;
-
-	boolean					force_lps_ctrl;
-
-	boolean					concurrent_rx_mode_on;
-
-	u16					score_board;
-	u8					isolation_btween_wb;   /* 0~ 50 */
-
-	u8					a2dp_bit_pool;
-	u8					cut_version;
-	boolean				acl_busy;
-	boolean				bt_create_connection;
-
-	u32					bt_coex_supported_feature;
-	u32					bt_coex_supported_version;
-
-	u8					bt_ble_scan_type;
-	u32					bt_ble_scan_para[3];
-
-	boolean				run_time_state;
-	boolean				freeze_coexrun_by_btinfo;
-
-	boolean				is_A2DP_3M;
-	boolean				voice_over_HOGP;
-	u8                  bt_info;
-	boolean				is_autoslot;
-	u8					forbidden_slot;
-	u8					hid_busy_num;
-	u8					hid_pair_cnt;
-
-	u32					cnt_RemoteNameReq;
-	u32					cnt_setupLink;
-	u32					cnt_ReInit;
-	u32					cnt_IgnWlanAct;
-	u32					cnt_Page;
-	u32					cnt_RoleSwitch;
-
-	u16					bt_reg_vendor_ac;
-	u16					bt_reg_vendor_ae;
-
-	boolean				is_setupLink;
-	u8					wl_noisy_level;
-	u32                 gnt_error_cnt;
-
-	u8					bt_afh_map[10];
-	u8					bt_relink_downcount;
-	boolean				is_tdma_btautoslot;
-	boolean				is_tdma_btautoslot_hang;
-
-	u8					switch_band_notify_to;
-	boolean				is_rf_state_off;
-
-	boolean				is_hid_low_pri_tx_overhead;
-	boolean				is_bt_multi_link;
-	boolean				is_bt_a2dp_sink;
-	boolean				is_set_ps_state_fail;
-	u8					cnt_set_ps_state_fail;
+	boolean			bt_disabled;
+	boolean			bt_link_exist;
+	boolean			sco_exist;
+	boolean			a2dp_exist;
+	boolean			hid_exist;
+	boolean			pan_exist;
+	boolean			msft_mr_exist;
+	u8			num_of_profile;
+
+	boolean			under_lps;
+	boolean			under_ips;
+	u32			specific_pkt_period_cnt;
+	u32			high_priority_tx;
+	u32			high_priority_rx;
+	u32			low_priority_tx;
+	u32			low_priority_rx;
+	boolean			is_hi_pri_rx_overhead;
+	s8			bt_rssi;
+	u8			pre_bt_rssi_state;
+	u8			pre_wifi_rssi_state[4];
+	u8			bt_info_c2h[BT_8821C_1ANT_INFO_SRC_MAX][10];
+	u32			bt_info_c2h_cnt[BT_8821C_1ANT_INFO_SRC_MAX];
+	boolean			bt_whck_test;
+	boolean			c2h_bt_inquiry_page;
+	boolean			c2h_bt_remote_name_req;
+	boolean			c2h_bt_page;
+
+	boolean			wifi_high_pri_task1;
+	boolean			wifi_high_pri_task2;
+
+	u8			bt_info_ext;
+	u8			bt_info_ext2;
+	u32			pop_event_cnt;
+	u8			scan_ap_num;
+	u8			bt_retry_cnt;
+
+	u32			crc_ok_cck;
+	u32			crc_ok_11g;
+	u32			crc_ok_11n;
+	u32			crc_ok_11n_vht;
+
+	u32			crc_err_cck;
+	u32			crc_err_11g;
+	u32			crc_err_11n;
+	u32			crc_err_11n_vht;
+
+	boolean			cck_lock;
+	boolean			cck_lock_ever;
+	boolean			cck_lock_warn;
+
+	u8			coex_table_type;
+	boolean			force_lps_ctrl;
+	boolean			concurrent_rx_mode_on;
+	u16			score_board;
+	u8			isolation_btween_wb;   /* 0~ 50 */
+
+	u8			a2dp_bit_pool;
+	u8			cut_version;
+	boolean			acl_busy;
+	boolean			bt_create_connection;
+
+	u32			bt_coex_supported_feature;
+	u32			bt_coex_supported_version;
+
+	u8			bt_ble_scan_type;
+	u32			bt_ble_scan_para[3];
+
+	boolean			run_time_state;
+	boolean			freeze_coexrun_by_btinfo;
+
+	boolean			is_A2DP_3M;
+	boolean			voice_over_HOGP;
+	u8			bt_info;
+	boolean			is_autoslot;
+	u8			forbidden_slot;
+	u8			hid_busy_num;
+	u8			hid_pair_cnt;
+
+	u32			cnt_remote_name_req;
+	u32			cnt_setup_link;
+	u32			cnt_reinit;
+	u32			cnt_ign_wlan_act;
+	u32			cnt_page;
+	u32			cnt_role_switch;
+
+	u16			bt_reg_vendor_ac;
+	u16			bt_reg_vendor_ae;
+
+	boolean			is_setup_link;
+	u8			wl_noisy_level;
+	u32			gnt_error_cnt;
+
+	u8			bt_afh_map[10];
+	u8			bt_relink_downcount;
+	boolean			is_tdma_btautoslot;
+	boolean			is_tdma_btautoslot_hang;
+
+	u8			switch_band_notify_to;
+	boolean			is_rf_state_off;
+
+	boolean			is_hid_low_pri_tx_overhead;
+	boolean			is_bt_multi_link;
+	boolean			is_bt_a2dp_sink;
+	boolean			is_set_ps_state_fail;
+	u8			cnt_set_ps_state_fail;
+
+	u8			wl_fw_dbg_info[10];
+	u8			wl_rx_rate;
+	u8			wl_tx_rate;
+	u8			wl_rts_rx_rate;
+	u8			wl_center_channel;
+	u8			wl_tx_macid;
+	u8			wl_tx_retry_ratio;
+
+	u16			score_board_WB;
+	boolean			is_hid_rcu;
+	u16			legacy_forbidden_slot;
+	u16			le_forbidden_slot;
+	u8			bt_a2dp_vendor_id;
+	u32			bt_a2dp_device_name;
+	boolean			is_ble_scan_en;
+
+	boolean			is_bt_opp_exist;
+	boolean			gl_wifi_busy;
+	u8			connect_ap_period_cnt;
+
+	boolean			is_bt_reenable;
+	u8			cnt_bt_reenable;
+	boolean			is_wifi_linkscan_process;
+	u8			wl_coex_mode;
+	u8			wl_pnp_wakeup_downcnt;
+	u32			coex_run_cnt;
 };
 
 
 #define  BT_8821C_1ANT_EXT_BAND_SWITCH_USE_DPDT	0
 #define  BT_8821C_1ANT_EXT_BAND_SWITCH_USE_SPDT	1
 
-
 struct rfe_type_8821c_1ant {
-
-	u8			rfe_module_type;
-	boolean		ext_ant_switch_exist;
-	u8			ext_ant_switch_type;			/* 0:DPDT, 1:SPDT */
-	u8			ext_ant_switch_ctrl_polarity;		/*  iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */
-
-	boolean		ext_band_switch_exist;
-	u8			ext_band_switch_type;			/* 0:DPDT, 1:SPDT */
-	u8			ext_band_switch_ctrl_polarity;
-
-	boolean		ant_at_main_port;
-
-	boolean		wlg_Locate_at_btg;				/*  If TRUE:  WLG at BTG, If FALSE: WLG at WLAG */
-
-	boolean		ext_ant_switch_diversity;		/* If diversity on */
+	u8 rfe_module_type;
+	boolean ext_ant_switch_exist;
+	/* 0:DPDT, 1:SPDT */
+	u8 ext_ant_switch_type;
+	/*  iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */
+	u8 ext_ant_switch_ctrl_polarity;
+
+	boolean ext_band_switch_exist;
+	/* 0:DPDT, 1:SPDT */
+	u8 ext_band_switch_type;
+	u8 ext_band_switch_ctrl_polarity;
+	boolean ant_at_main_port;
+
+	/*  If TRUE:  WLG at BTG, If FALSE: WLG at WLAG */
+	boolean wlg_locate_at_btg;
+
+	/* If diversity on */
+	boolean ext_ant_switch_diversity;
 };
 
-#define  BT_8821C_1ANT_ANTDET_PSD_POINTS			256	/* MAX:1024 */
-#define  BT_8821C_1ANT_ANTDET_PSD_AVGNUM			1	/* MAX:3 */
-#define	BT_8821C_1ANT_ANTDET_BUF_LEN				16
-
-struct psdscan_sta_8821c_1ant {
-
-	u32			ant_det_bt_le_channel;  /* BT LE Channel ex:2412 */
-	u32			ant_det_bt_tx_time;
-	u32			ant_det_pre_psdscan_peak_val;
-	boolean			ant_det_is_ant_det_available;
-	u32			ant_det_psd_scan_peak_val;
-	boolean			ant_det_is_btreply_available;
-	u32			ant_det_psd_scan_peak_freq;
-
-	u8			ant_det_result;
-	u8			ant_det_peak_val[BT_8821C_1ANT_ANTDET_BUF_LEN];
-	u8			ant_det_peak_freq[BT_8821C_1ANT_ANTDET_BUF_LEN];
-	u32			ant_det_try_count;
-	u32			ant_det_fail_count;
-	u32			ant_det_inteval_count;
-	u32			ant_det_thres_offset;
-
-	u32			real_cent_freq;
-	s32			real_offset;
-	u32			real_span;
-
-	u32			psd_band_width;  /* unit: Hz */
-	u32			psd_point;		/* 128/256/512/1024 */
-	u32			psd_report[1024];  /* unit:dB (20logx), 0~255 */
-	u32			psd_report_max_hold[1024];  /* unit:dB (20logx), 0~255 */
-	u32			psd_start_point;
-	u32			psd_stop_point;
-	u32			psd_max_value_point;
-	u32			psd_max_value;
-	u32			psd_max_value2;
-	u32			psd_avg_value;   /* filter loop_max_value that below BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT, and average the rest*/
-	u32			psd_loop_max_value[BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT];  /*max value in each loop */
-	u32			psd_start_base;
-	u32			psd_avg_num;	/* 1/8/16/32 */
-	u32			psd_gen_count;
-	boolean			is_AntDet_running;
-	boolean			is_psd_show_max_only;
+struct wifi_link_info_8821c_1ant {
+	u8				num_of_active_port;
+	u32				port_connect_status;
+	boolean				is_all_under_5g;
+	boolean				is_mcc_25g;
+	boolean				is_p2p_connected;
 };
 
 /* *******************************************
  * The following is interface which will notify coex module.
  * ******************************************* */
-void ex_halbtc8821c1ant_power_on_setting(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c1ant_pre_load_firmware(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c1ant_init_hw_config(IN struct btc_coexist *btcoexist,
-				       IN boolean wifi_only);
-void ex_halbtc8821c1ant_init_coex_dm(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c1ant_ips_notify(IN struct btc_coexist *btcoexist,
-				   IN u8 type);
-void ex_halbtc8821c1ant_lps_notify(IN struct btc_coexist *btcoexist,
-				   IN u8 type);
-void ex_halbtc8821c1ant_scan_notify(IN struct btc_coexist *btcoexist,
-				    IN u8 type);
-void ex_halbtc8821c1ant_switchband_notify(IN struct btc_coexist *btcoexist,
-		IN u8 type);
-void ex_halbtc8821c1ant_connect_notify(IN struct btc_coexist *btcoexist,
-				       IN u8 type);
-void ex_halbtc8821c1ant_media_status_notify(IN struct btc_coexist *btcoexist,
-		IN u8 type);
-void ex_halbtc8821c1ant_specific_packet_notify(IN struct btc_coexist *btcoexist,
-		IN u8 type);
-void ex_halbtc8821c1ant_bt_info_notify(IN struct btc_coexist *btcoexist,
-				       IN u8 *tmp_buf, IN u8 length);
-void ex_halbtc8821c1ant_rf_status_notify(IN struct btc_coexist *btcoexist,
-		IN u8 type);
-void ex_halbtc8821c1ant_halt_notify(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c1ant_pnp_notify(IN struct btc_coexist *btcoexist,
-				   IN u8 pnp_state);
-void ex_halbtc8821c1ant_coex_dm_reset(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c1ant_periodical(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c1ant_display_coex_info(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c1ant_antenna_detection(IN struct btc_coexist *btcoexist,
-		IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds);
-void ex_halbtc8821c1ant_antenna_isolation(IN struct btc_coexist *btcoexist,
-		IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds);
-
-void ex_halbtc8821c1ant_psd_scan(IN struct btc_coexist *btcoexist,
-		 IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds);
-void ex_halbtc8821c1ant_display_ant_detection(IN struct btc_coexist *btcoexist);
+void ex_halbtc8821c1ant_power_on_setting(struct btc_coexist *btc);
+void ex_halbtc8821c1ant_pre_load_firmware(struct btc_coexist *btc);
+void ex_halbtc8821c1ant_init_hw_config(struct btc_coexist *btc,
+				       boolean wifi_only);
+void ex_halbtc8821c1ant_init_coex_dm(struct btc_coexist *btc);
+void ex_halbtc8821c1ant_ips_notify(struct btc_coexist *btc,
+				   u8 type);
+void ex_halbtc8821c1ant_lps_notify(struct btc_coexist *btc,
+				   u8 type);
+void ex_halbtc8821c1ant_scan_notify(struct btc_coexist *btc,
+				    u8 type);
+void ex_halbtc8821c1ant_switchband_notify(struct btc_coexist *btc,
+					  u8 type);
+void ex_halbtc8821c1ant_connect_notify(struct btc_coexist *btc,
+				       u8 type);
+void ex_halbtc8821c1ant_media_status_notify(struct btc_coexist *btc,
+					    u8 type);
+void ex_halbtc8821c1ant_specific_packet_notify(struct btc_coexist *btc,
+					       u8 type);
+void ex_halbtc8821c1ant_bt_info_notify(struct btc_coexist *btc,
+				       u8 *tmp_buf,  u8 length);
+void ex_halbtc8821c1ant_wl_fwdbginfo_notify(struct btc_coexist *btc,
+					    u8 *tmp_buf, u8 length);
+void ex_halbtc8821c1ant_rx_rate_change_notify(struct btc_coexist *btc,
+					      BOOLEAN is_data_frame,
+					      u8 btc_rate_id);
+void ex_halbtc8821c1ant_tx_rate_change_notify(struct btc_coexist *btc,
+					      u8 tx_rate,
+					      u8 tx_retry_ratio, u8 macid);
+void ex_halbtc8821c1ant_rf_status_notify(struct btc_coexist *btc,
+					 u8 type);
+void ex_halbtc8821c1ant_halt_notify(struct btc_coexist *btc);
+void ex_halbtc8821c1ant_pnp_notify(struct btc_coexist *btc,
+				   u8 pnp_state);
+void ex_halbtc8821c1ant_coex_dm_reset(struct btc_coexist *btc);
+void ex_halbtc8821c1ant_periodical(struct btc_coexist *btc);
+void ex_halbtc8821c1ant_display_simple_coex_info(struct btc_coexist *btc);
+void ex_halbtc8821c1ant_display_coex_info(struct btc_coexist *btc);
 
 #else
-#define	ex_halbtc8821c1ant_power_on_setting(btcoexist)
-#define	ex_halbtc8821c1ant_pre_load_firmware(btcoexist)
-#define	ex_halbtc8821c1ant_init_hw_config(btcoexist, wifi_only)
-#define	ex_halbtc8821c1ant_init_coex_dm(btcoexist)
-#define	ex_halbtc8821c1ant_ips_notify(btcoexist, type)
-#define	ex_halbtc8821c1ant_lps_notify(btcoexist, type)
-#define	ex_halbtc8821c1ant_scan_notify(btcoexist, type)
-#define   ex_halbtc8821c1ant_switchband_notify(btcoexist,type)
-#define	ex_halbtc8821c1ant_connect_notify(btcoexist, type)
-#define	ex_halbtc8821c1ant_media_status_notify(btcoexist, type)
-#define	ex_halbtc8821c1ant_specific_packet_notify(btcoexist, type)
-#define	ex_halbtc8821c1ant_bt_info_notify(btcoexist, tmp_buf, length)
-#define	ex_halbtc8821c1ant_rf_status_notify(btcoexist, type)
-#define	ex_halbtc8821c1ant_halt_notify(btcoexist)
-#define	ex_halbtc8821c1ant_pnp_notify(btcoexist, pnp_state)
-#define	ex_halbtc8821c1ant_coex_dm_reset(btcoexist)
-#define	ex_halbtc8821c1ant_periodical(btcoexist)
-#define	ex_halbtc8821c1ant_display_coex_info(btcoexist)
-#define	ex_halbtc8821c1ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds)
-#define	ex_halbtc8821c1ant_antenna_isolation(btcoexist, cent_freq, offset, span, seconds)
-#define	ex_halbtc8821c1ant_psd_scan(btcoexist, cent_freq, offset, span, seconds)
-#define	ex_halbtc8821c1ant_display_ant_detection(btcoexist)
+#define ex_halbtc8821c1ant_power_on_setting(btc)
+#define ex_halbtc8821c1ant_pre_load_firmware(btc)
+#define ex_halbtc8821c1ant_init_hw_config(btc, wifi_only)
+#define ex_halbtc8821c1ant_init_coex_dm(btc)
+#define ex_halbtc8821c1ant_ips_notify(btc, type)
+#define ex_halbtc8821c1ant_lps_notify(btc, type)
+#define ex_halbtc8821c1ant_scan_notify(btc, type)
+#define ex_halbtc8821c1ant_switchband_notify(btc, type)
+#define ex_halbtc8821c1ant_connect_notify(btc, type)
+#define ex_halbtc8821c1ant_media_status_notify(btc, type)
+#define ex_halbtc8821c1ant_specific_packet_notify(btc, type)
+#define ex_halbtc8821c1ant_bt_info_notify(btc, tmp_buf, length)
+#define ex_halbtc8821c1ant_wl_fwdbginfo_notify(btc, tmp_buf, length)
+#define ex_halbtc8821c1ant_rx_rate_change_notify(btc, is_data_frame,     \
+						 btc_rate_id)
+#define ex_halbtc8821c1ant_tx_rate_change_notify(btcoexist, tx_rate,     \
+						tx_retry_ratio, macid)
+#define ex_halbtc8821c1ant_rf_status_notify(btc, type)
+#define ex_halbtc8821c1ant_halt_notify(btc)
+#define ex_halbtc8821c1ant_pnp_notify(btc, pnp_state)
+#define ex_halbtc8821c1ant_coex_dm_reset(btc)
+#define ex_halbtc8821c1ant_periodical(btc)
+#define ex_halbtc8821c1ant_display_simple_coex_info(btc)
+#define ex_halbtc8821c1ant_display_coex_info(btc)
 #endif
 
 #endif

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 771 - 298
hal/btc/halbtc8821c2ant.c


+ 368 - 384
hal/btc/halbtc8821c2ant.h

@@ -1,3 +1,17 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 
 #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1)
 
@@ -6,497 +20,467 @@
 /* *******************************************
  * The following is for 8821C 2Ant BT Co-exist definition
  * ******************************************* */
-#define	BT_8821C_2ANT_COEX_DBG					0
-#define	BT_AUTO_REPORT_ONLY_8821C_2ANT				1
-
-
-#define	BT_INFO_8821C_2ANT_B_FTP						BIT(7)
-#define	BT_INFO_8821C_2ANT_B_A2DP					BIT(6)
-#define	BT_INFO_8821C_2ANT_B_HID						BIT(5)
-#define	BT_INFO_8821C_2ANT_B_SCO_BUSY				BIT(4)
-#define	BT_INFO_8821C_2ANT_B_ACL_BUSY				BIT(3)
-#define	BT_INFO_8821C_2ANT_B_INQ_PAGE				BIT(2)
-#define	BT_INFO_8821C_2ANT_B_SCO_ESCO				BIT(1)
-#define	BT_INFO_8821C_2ANT_B_CONNECTION				BIT(0)
-
-#define		BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT		2
-
-
-#define	BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES1				80  /* unit: % WiFi RSSI Threshold for   2-Ant free-run/2-Ant TDMA translation, default = 42 */
-#define	BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES1				80 /*  unit: % BT RSSI Threshold for      2-Ant free-run/2-Ant TDMA translation, default = 46 */
-#define	BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES2				80  /* unit: % WiFi RSSI Threshold for   1-Ant TDMA/1-Ant PS-TDMA translation, default = 42 */
-#define	BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES2				80 /*  unit: % BT RSSI Threshold for      1-Ant TDMA/1-Ant PS-TDMA translation, default = 46 */
-#define	BT_8821C_2ANT_DEFAULT_ISOLATION						15	 /*  unit: dB */
-#define   BT_8821C_2ANT_WIFI_MAX_TX_POWER						15	 /*  unit: dBm */
-#define   BT_8821C_2ANT_BT_MAX_TX_POWER							3	 /*  unit: dBm */
-#define   BT_8821C_2ANT_WIFI_SIR_THRES1							-15  /*  unit: dB */
-#define   BT_8821C_2ANT_WIFI_SIR_THRES2							-30  /*  unit: dB */
-#define   BT_8821C_2ANT_BT_SIR_THRES1							-15		 /*  unit: dB */
-#define   BT_8821C_2ANT_BT_SIR_THRES2							-30		 /*  unit: dB */
-
-
-/* for Antenna detection */
-#define	BT_8821C_2ANT_ANTDET_PSDTHRES_BACKGROUND						50
-#define	BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION				70
-#define	BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION			52
-#define	BT_8821C_2ANT_ANTDET_PSDTHRES_1ANT							40
-#define	BT_8821C_2ANT_ANTDET_RETRY_INTERVAL							10	/* retry timer if ant det is fail, unit: second */
-#define	BT_8821C_2ANT_ANTDET_SWEEPPOINT_DELAY							60000
-#define	BT_8821C_2ANT_ANTDET_ENABLE										0
-#define	BT_8821C_2ANT_ANTDET_BTTXTIME									100
-#define	BT_8821C_2ANT_ANTDET_BTTXCHANNEL								39
-#define	BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT						50
-
-
-#define	BT_8821C_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT		30000
+#define	BT_8821C_2ANT_COEX_DBG				0
+#define	BT_AUTO_REPORT_ONLY_8821C_2ANT			1
+
+#define	BT_INFO_8821C_2ANT_B_FTP			BIT(7)
+#define	BT_INFO_8821C_2ANT_B_A2DP			BIT(6)
+#define	BT_INFO_8821C_2ANT_B_HID			BIT(5)
+#define	BT_INFO_8821C_2ANT_B_SCO_BUSY			BIT(4)
+#define	BT_INFO_8821C_2ANT_B_ACL_BUSY			BIT(3)
+#define	BT_INFO_8821C_2ANT_B_INQ_PAGE			BIT(2)
+#define	BT_INFO_8821C_2ANT_B_SCO_ESCO			BIT(1)
+#define	BT_INFO_8821C_2ANT_B_CONNECTION			BIT(0)
+
+#define	BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT		2
+
+#define	BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES1	80
+#define	BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES1		80
+#define	BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES2	80
+#define	BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES2		80
+#define	BT_8821C_2ANT_DEFAULT_ISOLATION			15
+#define   BT_8821C_2ANT_WIFI_MAX_TX_POWER			15
+#define   BT_8821C_2ANT_BT_MAX_TX_POWER			3
+#define   BT_8821C_2ANT_WIFI_SIR_THRES1			-15
+#define   BT_8821C_2ANT_WIFI_SIR_THRES2			-30
+#define   BT_8821C_2ANT_BT_SIR_THRES1			-15
+#define   BT_8821C_2ANT_BT_SIR_THRES2			-30
 
 enum bt_8821c_2ant_signal_state {
-	BT_8821C_2ANT_SIG_STA_SET_TO_LOW		= 0x0,
-	BT_8821C_2ANT_SIG_STA_SET_BY_HW		= 0x0,
-	BT_8821C_2ANT_SIG_STA_SET_TO_HIGH		= 0x1,
-	BT_8821C_2ANT_SIG_STA_MAX
+	BT_8821C_2ANT_GNT_SET_TO_LOW	= 0x0,
+	BT_8821C_2ANT_GNT_SET_TO_HIGH	= 0x1,
+	BT_8821C_2ANT_GNT_SET_BY_HW	= 0x2,
+	BT_8821C_2ANT_GNT_SET_MAX
 };
 
 enum bt_8821c_2ant_path_ctrl_owner {
 	BT_8821C_2ANT_PCO_BTSIDE		= 0x0,
-	BT_8821C_2ANT_PCO_WLSIDE	= 0x1,
+	BT_8821C_2ANT_PCO_WLSIDE		= 0x1,
 	BT_8821C_2ANT_PCO_MAX
 };
 
 enum bt_8821c_2ant_gnt_ctrl_type {
-	BT_8821C_2ANT_GNT_TYPE_CTRL_BY_PTA		= 0x0,
-	BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW		= 0x1,
+	BT_8821C_2ANT_GNT_TYPE_CTRL_BY_PTA	= 0x0,
+	BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW	= 0x1,
 	BT_8821C_2ANT_GNT_TYPE_MAX
 };
 
 enum bt_8821c_2ant_gnt_ctrl_block {
 	BT_8821C_2ANT_GNT_BLOCK_RFC_BB		= 0x0,
-	BT_8821C_2ANT_GNT_BLOCK_RFC			= 0x1,
-	BT_8821C_2ANT_GNT_BLOCK_BB			= 0x2,
+	BT_8821C_2ANT_GNT_BLOCK_RFC		= 0x1,
+	BT_8821C_2ANT_GNT_BLOCK_BB		= 0x2,
 	BT_8821C_2ANT_GNT_BLOCK_MAX
 };
 
 enum bt_8821c_2ant_lte_coex_table_type {
-	BT_8821C_2ANT_CTT_WL_VS_LTE			= 0x0,
-	BT_8821C_2ANT_CTT_BT_VS_LTE			= 0x1,
+	BT_8821C_2ANT_CTT_WL_VS_LTE		= 0x0,
+	BT_8821C_2ANT_CTT_BT_VS_LTE		= 0x1,
 	BT_8821C_2ANT_CTT_MAX
 };
 
 enum bt_8821c_2ant_lte_break_table_type {
-	BT_8821C_2ANT_LBTT_WL_BREAK_LTE			= 0x0,
-	BT_8821C_2ANT_LBTT_BT_BREAK_LTE				= 0x1,
-	BT_8821C_2ANT_LBTT_LTE_BREAK_WL			= 0x2,
-	BT_8821C_2ANT_LBTT_LTE_BREAK_BT				= 0x3,
+	BT_8821C_2ANT_LBTT_WL_BREAK_LTE		= 0x0,
+	BT_8821C_2ANT_LBTT_BT_BREAK_LTE		= 0x1,
+	BT_8821C_2ANT_LBTT_LTE_BREAK_WL		= 0x2,
+	BT_8821C_2ANT_LBTT_LTE_BREAK_BT		= 0x3,
 	BT_8821C_2ANT_LBTT_MAX
 };
 
 enum bt_info_src_8821c_2ant {
-	BT_INFO_SRC_8821C_2ANT_WIFI_FW			= 0x0,
-	BT_INFO_SRC_8821C_2ANT_BT_RSP				= 0x1,
-	BT_INFO_SRC_8821C_2ANT_BT_ACTIVE_SEND		= 0x2,
-	BT_INFO_SRC_8821C_2ANT_MAX
+	BT_8821C_2ANT_INFO_SRC_WIFI_FW		= 0x0,
+	BT_8821C_2ANT_INFO_SRC_BT_RSP		= 0x1,
+	BT_8821C_2ANT_INFO_SRC_BT_ACT		= 0x2,
+	BT_8821C_2ANT_INFO_SRC_MAX
 };
 
 enum bt_8821c_2ant_bt_status {
-	BT_8821C_2ANT_BT_STATUS_NON_CONNECTED_IDLE	= 0x0,
-	BT_8821C_2ANT_BT_STATUS_CONNECTED_IDLE		= 0x1,
-	BT_8821C_2ANT_BT_STATUS_INQ_PAGE				= 0x2,
-	BT_8821C_2ANT_BT_STATUS_ACL_BUSY				= 0x3,
-	BT_8821C_2ANT_BT_STATUS_SCO_BUSY				= 0x4,
-	BT_8821C_2ANT_BT_STATUS_ACL_SCO_BUSY			= 0x5,
-	BT_8821C_2ANT_BT_STATUS_MAX
+	BT_8821C_2ANT_BSTATUS_NCON_IDLE		= 0x0,
+	BT_8821C_2ANT_BSTATUS_CON_IDLE		= 0x1,
+	BT_8821C_2ANT_BSTATUS_INQ_PAGE		= 0x2,
+	BT_8821C_2ANT_BSTATUS_ACL_BUSY		= 0x3,
+	BT_8821C_2ANT_BSTATUS_SCO_BUSY		= 0x4,
+	BT_8821C_2ANT_BSTATUS_ACL_SCO_BUSY	= 0x5,
+	BT_8821C_2ANT_BSTATUS_MAX
 };
 
 enum bt_8821c_2ant_coex_algo {
-	BT_8821C_2ANT_COEX_ALGO_UNDEFINED			= 0x0,
-	BT_8821C_2ANT_COEX_ALGO_SCO				= 0x1,
-	BT_8821C_2ANT_COEX_ALGO_HID				= 0x2,
-	BT_8821C_2ANT_COEX_ALGO_A2DP				= 0x3,
-	BT_8821C_2ANT_COEX_ALGO_A2DP_PANHS		= 0x4,
-	BT_8821C_2ANT_COEX_ALGO_PANEDR			= 0x5,
-	BT_8821C_2ANT_COEX_ALGO_PANHS			= 0x6,
-	BT_8821C_2ANT_COEX_ALGO_PANEDR_A2DP		= 0x7,
-	BT_8821C_2ANT_COEX_ALGO_PANEDR_HID		= 0x8,
-	BT_8821C_2ANT_COEX_ALGO_HID_A2DP_PANEDR	= 0x9,
-	BT_8821C_2ANT_COEX_ALGO_HID_A2DP			= 0xa,
-	BT_8821C_2ANT_COEX_ALGO_NOPROFILEBUSY		= 0xb,
-	BT_8821C_2ANT_COEX_ALGO_A2DPSINK		= 0xc,
-	BT_8821C_2ANT_COEX_ALGO_MAX
+	BT_8821C_2ANT_COEX_UNDEFINED		= 0x0,
+	BT_8821C_2ANT_COEX_SCO			= 0x1,
+	BT_8821C_2ANT_COEX_HID			= 0x2,
+	BT_8821C_2ANT_COEX_A2DP			= 0x3,
+	BT_8821C_2ANT_COEX_A2DP_PANHS		= 0x4,
+	BT_8821C_2ANT_COEX_PAN			= 0x5,
+	BT_8821C_2ANT_COEX_PANHS		= 0x6,
+	BT_8821C_2ANT_COEX_PAN_A2DP		= 0x7,
+	BT_8821C_2ANT_COEX_PAN_HID		= 0x8,
+	BT_8821C_2ANT_COEX_HID_A2DP_PAN		= 0x9,
+	BT_8821C_2ANT_COEX_HID_A2DP		= 0xa,
+	BT_8821C_2ANT_COEX_NOPROFILEBUSY	= 0xb,
+	BT_8821C_2ANT_COEX_A2DPSINK		= 0xc,
+	BT_8821C_2ANT_COEX_MAX
 };
 
 enum bt_8821c_2ant_ext_ant_switch_type {
-	BT_8821C_2ANT_EXT_ANT_SWITCH_USE_DPDT		= 0x0,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_USE_SPDT		= 0x1,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_NONE			= 0x2,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_MAX
+	BT_8821C_2ANT_USE_DPDT		= 0x0,
+	BT_8821C_2ANT_USE_SPDT		= 0x1,
+	BT_8821C_2ANT_SWITCH_NONE	= 0x2,
+	BT_8821C_2ANT_SWITCH_MAX
 };
 
 enum bt_8821c_2ant_ext_ant_switch_ctrl_type {
-	BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW	= 0x0,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_PTA		= 0x1,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV	= 0x2,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_MAC		= 0x3,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT		= 0x4,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_MAX
+	BT_8821C_2ANT_CTRL_BY_BBSW	= 0x0,
+	BT_8821C_2ANT_CTRL_BY_PTA	= 0x1,
+	BT_8821C_2ANT_CTRL_BY_ANTDIV	= 0x2,
+	BT_8821C_2ANT_CTRL_BY_MAC	= 0x3,
+	BT_8821C_2ANT_CTRL_BY_BT	= 0x4,
+	BT_8821C_2ANT_CTRL_BY_FW	= 0x5,
+	BT_8821C_2ANT_CTRL_MAX
 };
 
 enum bt_8821c_2ant_ext_ant_switch_pos_type {
-	BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_BT			= 0x0,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLG			= 0x1,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLA			= 0x2,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE		= 0x3,
-	BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_MAX
-};
-
-enum bt_8821c_2ant_ext_band_switch_pos_type {
-	BT_8821C_2ANT_EXT_BAND_SWITCH_TO_WLG			= 0x0,
-	BT_8821C_2ANT_EXT_BAND_SWITCH_TO_WLA			= 0x1,
-	BT_8821C_2ANT_EXT_BAND_SWITCH_TO_MAX
-};
-
-enum bt_8821c_2ant_int_block {
-	BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG			= 0x0,
-	BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG		= 0x1,
-	BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG		= 0x2,
-	BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_MAX
+	BT_8821C_2ANT_TO_BT		= 0x0,
+	BT_8821C_2ANT_TO_WLG		= 0x1,
+	BT_8821C_2ANT_TO_WLA		= 0x2,
+	BT_8821C_2ANT_TO_NOCARE		= 0x3,
+	BT_8821C_2ANT_TO_MAX
 };
 
 enum bt_8821c_2ant_phase {
-	BT_8821C_2ANT_PHASE_COEX_INIT								= 0x0,
-	BT_8821C_2ANT_PHASE_WLANONLY_INIT							= 0x1,
-	BT_8821C_2ANT_PHASE_WLAN_OFF								= 0x2,
-	BT_8821C_2ANT_PHASE_2G_RUNTIME								= 0x3,
-	BT_8821C_2ANT_PHASE_5G_RUNTIME								= 0x4,
-	BT_8821C_2ANT_PHASE_BTMPMODE								= 0x5,
-	BT_8821C_2ANT_PHASE_ANTENNA_DET								= 0x6,
-	BT_8821C_2ANT_PHASE_COEX_POWERON							= 0x7,
-	BT_8821C_2ANT_PHASE_2G_RUNTIME_CONCURRENT					= 0x8,
+	BT_8821C_2ANT_PHASE_INIT		= 0x0,
+	BT_8821C_2ANT_PHASE_WONLY		= 0x1,
+	BT_8821C_2ANT_PHASE_WOFF		= 0x2,
+	BT_8821C_2ANT_PHASE_2G			= 0x3,
+	BT_8821C_2ANT_PHASE_5G			= 0x4,
+	BT_8821C_2ANT_PHASE_BTMP		= 0x5,
+	BT_8821C_2ANT_PHASE_ANTDET		= 0x6,
+	BT_8821C_2ANT_PHASE_POWERON		= 0x7,
 	BT_8821C_2ANT_PHASE_MAX
 };
 
-enum bt_8821c_2ant_Scoreboard {
-	BT_8821C_2ANT_SCOREBOARD_ACTIVE								= BIT(0),
-	BT_8821C_2ANT_SCOREBOARD_ONOFF								= BIT(1),
-	BT_8821C_2ANT_SCOREBOARD_SCAN								= BIT(2),
-	BT_8821C_2ANT_SCOREBOARD_UNDERTEST							= BIT(3),
-	BT_8821C_2ANT_SCOREBOARD_WLBUSY								= BIT(6)
+enum bt_8821c_2ant_scoreboard {
+	BT_8821C_2ANT_SCBD_ACTIVE		= BIT(0),
+	BT_8821C_2ANT_SCBD_ONOFF		= BIT(1),
+	BT_8821C_2ANT_SCBD_SCAN			= BIT(2),
+	BT_8821C_2ANT_SCBD_UNDERTEST		= BIT(3),
+	BT_8821C_2ANT_SCBD_RXGAIN		= BIT(4),
+	BT_8821C_2ANT_SCBD_WLBUSY		= BIT(6),
+	BT_8821C_2ANT_SCBD_BTCQDDR		= BIT(10)
 };
 
+enum bt_8821c_2ant_RUNREASON {
+	BT_8821C_2ANT_RSN_2GSCANSTART		= 0x0,
+	BT_8821C_2ANT_RSN_5GSCANSTART		= 0x1,
+	BT_8821C_2ANT_RSN_SCANFINISH		= 0x2,
+	BT_8821C_2ANT_RSN_2GSWITCHBAND		= 0x3,
+	BT_8821C_2ANT_RSN_5GSWITCHBAND		= 0x4,
+	BT_8821C_2ANT_RSN_2GCONSTART		= 0x5,
+	BT_8821C_2ANT_RSN_5GCONSTART		= 0x6,
+	BT_8821C_2ANT_RSN_2GCONFINISH		= 0x7,
+	BT_8821C_2ANT_RSN_5GCONFINISH		= 0x8,
+	BT_8821C_2ANT_RSN_2GMEDIA		= 0x9,
+	BT_8821C_2ANT_RSN_5GMEDIA		= 0xa,
+	BT_8821C_2ANT_RSN_MEDIADISCON		= 0xb,
+	BT_8821C_2ANT_RSN_2GSPECIALPKT		= 0xc,
+	BT_8821C_2ANT_RSN_5GSPECIALPKT		= 0xd,
+	BT_8821C_2ANT_RSN_BTINFO		= 0xe,
+	BT_8821C_2ANT_RSN_PERIODICAL		= 0xf,
+	BT_8821C_2ANT_RSN_PNP			= 0x10,
+	BT_8821C_2ANT_RSN_MAX
+};
 
+enum bt_8821c_2ant_WL_LINK_MODE {
+	BT_8821C_2ANT_WLINK_2G1PORT		= 0x0,
+	BT_8821C_2ANT_WLINK_2GMPORT		= 0x1,
+	BT_8821C_2ANT_WLINK_25GMPORT		= 0x2,
+	BT_8821C_2ANT_WLINK_5G			= 0x3,
+	BT_8821C_2ANT_WLINK_2GGO		= 0x4,
+	BT_8821C_2ANT_WLINK_BTMR		= 0x5,
+	BT_8821C_2ANT_WLINK_MAX
+};
 
 struct coex_dm_8821c_2ant {
 	/* hw setting */
-	u32		pre_ant_pos_type;
 	u32		cur_ant_pos_type;
 	/* fw mechanism */
-	u8		pre_bt_dec_pwr_lvl;
-	u8		cur_bt_dec_pwr_lvl;
-	u8		pre_fw_dac_swing_lvl;
-	u8		cur_fw_dac_swing_lvl;
+
+	u8		cur_bt_pwr_lvl;
+	u8		cur_wl_pwr_lvl;
+
 	boolean		cur_ignore_wlan_act;
-	boolean		pre_ignore_wlan_act;
-	u8		pre_ps_tdma;
+
 	u8		cur_ps_tdma;
 	u8		ps_tdma_para[5];
-	u8		ps_tdma_du_adj_type;
 	boolean		reset_tdma_adjust;
-	boolean		pre_ps_tdma_on;
 	boolean		cur_ps_tdma_on;
-	boolean		pre_bt_auto_report;
 	boolean		cur_bt_auto_report;
 
 	/* sw mechanism */
-	boolean		pre_rf_rx_lpf_shrink;
-	boolean		cur_rf_rx_lpf_shrink;
-	u32		bt_rf_0x1e_backup;
-	boolean	pre_low_penalty_ra;
 	boolean		cur_low_penalty_ra;
-	boolean		pre_dac_swing_on;
-	u32		pre_dac_swing_lvl;
-	boolean		cur_dac_swing_on;
-	u32		cur_dac_swing_lvl;
-	boolean		pre_adc_back_off;
-	boolean		cur_adc_back_off;
-	boolean	pre_agc_table_en;
-	boolean		cur_agc_table_en;
-	u32		pre_val0x6c0;
+
 	u32		cur_val0x6c0;
-	u32		pre_val0x6c4;
 	u32		cur_val0x6c4;
-	u32		pre_val0x6c8;
 	u32		cur_val0x6c8;
-	u8		pre_val0x6cc;
 	u8		cur_val0x6cc;
-	boolean		limited_dig;
 
 	/* algorithm related */
-	u8		pre_algorithm;
 	u8		cur_algorithm;
 	u8		bt_status;
 	u8		wifi_chnl_info[3];
 
-	boolean		need_recover0x948;
-	u32		backup0x948;
-
-	u8		pre_lps;
 	u8		cur_lps;
-	u8		pre_rpwm;
 	u8		cur_rpwm;
 
 	boolean		is_switch_to_1dot5_ant;
-	u8		switch_thres_offset;
-	u32					arp_cnt;
+	u32		arp_cnt;
 
-	u32		pre_ext_ant_switch_status;
 	u32		cur_ext_ant_switch_status;
 
-	u8		pre_ext_band_switch_status;
-	u8		cur_ext_band_switch_status;
-
-	u8		pre_int_block_status;
-	u8		cur_int_block_status;
+	u8		cur_antdiv_type;
+	u32		setting_tdma;
 };
 
 struct coex_sta_8821c_2ant {
-	boolean					bt_disabled;
-	boolean					bt_link_exist;
-	boolean					sco_exist;
-	boolean					a2dp_exist;
-	boolean					hid_exist;
-	boolean					pan_exist;
-
-	boolean					under_lps;
-	boolean					under_ips;
-	u32					high_priority_tx;
-	u32					high_priority_rx;
-	u32					low_priority_tx;
-	u32					low_priority_rx;
-	boolean             is_hiPri_rx_overhead;
-	u8					bt_rssi;
-	u8					pre_bt_rssi_state;
-	u8					pre_wifi_rssi_state[4];
-	u8					bt_info_c2h[BT_INFO_SRC_8821C_2ANT_MAX][10];
-	u32					bt_info_c2h_cnt[BT_INFO_SRC_8821C_2ANT_MAX];
-	boolean				bt_whck_test;
-	boolean					c2h_bt_inquiry_page;
-	boolean					c2h_bt_remote_name_req;
-
-	u8					bt_info_ext;
-	u8					bt_info_ext2;
-	u32					pop_event_cnt;
-	u8					scan_ap_num;
-	u8					bt_retry_cnt;
-
-	u32					crc_ok_cck;
-	u32					crc_ok_11g;
-	u32					crc_ok_11n;
-	u32					crc_ok_11n_vht;
-
-	u32					crc_err_cck;
-	u32					crc_err_11g;
-	u32					crc_err_11n;
-	u32					crc_err_11n_vht;
-
-	u32					acc_crc_ratio;
-	u32					now_crc_ratio;
-
-	boolean					cck_lock;
-	boolean					pre_ccklock;
-	boolean					cck_ever_lock;
-
-	u8					coex_table_type;
-	boolean					force_lps_ctrl;
-
-	u8					dis_ver_info_cnt;
-
-	u8					a2dp_bit_pool;
-	u8					cut_version;
-
-	boolean					concurrent_rx_mode_on;
-
-	u16					score_board;
-	u8					isolation_btween_wb;   /* 0~ 50 */
-	u8					wifi_coex_thres;
-	u8					bt_coex_thres;
-	u8					wifi_coex_thres2;
-	u8					bt_coex_thres2;
-
-	u8					num_of_profile;
-	boolean				acl_busy;
-	boolean				bt_create_connection;
-	boolean				wifi_is_high_pri_task;
-	u32					specific_pkt_period_cnt;
-	u32					bt_coex_supported_feature;
-	u32					bt_coex_supported_version;
-
-	u8					bt_ble_scan_type;
-	u32					bt_ble_scan_para[3];
-
-	boolean				run_time_state;
-	boolean				freeze_coexrun_by_btinfo;
-
-	boolean				is_A2DP_3M;
-	boolean				voice_over_HOGP;
-	u8                  bt_info;
-	boolean				is_autoslot;
-	u8					forbidden_slot;
-	u8					hid_busy_num;
-	u8					hid_pair_cnt;
-
-	u32					cnt_RemoteNameReq;
-	u32					cnt_setupLink;
-	u32					cnt_ReInit;
-	u32					cnt_IgnWlanAct;
-	u32					cnt_Page;
-	u32					cnt_RoleSwitch;
-
-	u16					bt_reg_vendor_ac;
-	u16					bt_reg_vendor_ae;
-
-	boolean				is_setupLink;
-	u8				    wl_noisy_level;
-	u32                 gnt_error_cnt;
-
-	u8					bt_afh_map[10];
-	u8					bt_relink_downcount;
-	boolean				is_tdma_btautoslot;
-	boolean				is_tdma_btautoslot_hang;
-
-	boolean             is_eSCO_mode;
-	u8                  switch_band_notify_to;
-	boolean				is_rf_state_off;
-
-	boolean				is_hid_low_pri_tx_overhead;
-	boolean				is_bt_multi_link;
-	boolean				is_bt_a2dp_sink;
-	boolean				is_set_ps_state_fail;
-	u8					cnt_set_ps_state_fail;
+	boolean			bt_disabled;
+	boolean			bt_link_exist;
+	boolean			sco_exist;
+	boolean			a2dp_exist;
+	boolean			hid_exist;
+	boolean			pan_exist;
+	boolean			msft_mr_exist;
+
+	boolean			under_lps;
+	boolean			under_ips;
+	u32			high_priority_tx;
+	u32			high_priority_rx;
+	u32			low_priority_tx;
+	u32			low_priority_rx;
+	boolean			is_hi_pri_rx_overhead;
+	u8			bt_rssi;
+	u8			pre_bt_rssi_state;
+	u8			pre_wifi_rssi_state[4];
+	u8			bt_info_c2h[BT_8821C_2ANT_INFO_SRC_MAX][10];
+	u32			bt_info_c2h_cnt[BT_8821C_2ANT_INFO_SRC_MAX];
+	boolean			bt_whck_test;
+	boolean			c2h_bt_inquiry_page;
+	boolean			c2h_bt_remote_name_req;
+
+	u8			bt_info_ext;
+	u8			bt_info_ext2;
+	u32			pop_event_cnt;
+	u8			scan_ap_num;
+	u8			bt_retry_cnt;
+
+	u32			crc_ok_cck;
+	u32			crc_ok_11g;
+	u32			crc_ok_11n;
+	u32			crc_ok_11n_vht;
+	u32			crc_err_cck;
+	u32			crc_err_11g;
+	u32			crc_err_11n;
+	u32			crc_err_11n_vht;
+	u32			cnt_crcok_max_in_10s;
+
+	boolean			cck_lock;
+	boolean			cck_lock_ever;
+	boolean			cck_lock_warn;
+
+	u8			coex_table_type;
+	boolean			force_lps_ctrl;
+
+	u8			dis_ver_info_cnt;
+
+	u8			a2dp_bit_pool;
+	u8			cut_version;
+
+	boolean			concurrent_rx_mode_on;
+
+	u16			score_board;
+	u8			isolation_btween_wb;   /* 0~ 50 */
+	u8			wifi_coex_thres;
+	u8			bt_coex_thres;
+	u8			wifi_coex_thres2;
+	u8			bt_coex_thres2;
+
+	u8			num_of_profile;
+	boolean			acl_busy;
+	boolean			bt_create_connection;
+
+	boolean			wifi_high_pri_task1;
+	boolean			wifi_high_pri_task2;
+
+	u32			specific_pkt_period_cnt;
+	u32			bt_coex_supported_feature;
+	u32			bt_coex_supported_version;
+
+	u8			bt_ble_scan_type;
+	u32			bt_ble_scan_para[3];
+
+	boolean			run_time_state;
+	boolean			freeze_coexrun_by_btinfo;
+
+	boolean			is_A2DP_3M;
+	boolean			voice_over_HOGP;
+	u8			bt_info;
+	boolean			is_autoslot;
+	u8			forbidden_slot;
+	u8			hid_busy_num;
+	u8			hid_pair_cnt;
+
+	u32			cnt_remote_name_req;
+	u32			cnt_setup_link;
+	u32			cnt_reinit;
+	u32			cnt_ign_wlan_act;
+	u32			cnt_page;
+	u32			cnt_role_switch;
+
+	u16			bt_reg_vendor_ac;
+	u16			bt_reg_vendor_ae;
+
+	boolean			is_setup_link;
+	u8			wl_noisy_level;
+	u32			gnt_error_cnt;
+
+	u8			bt_afh_map[10];
+	u8			bt_relink_downcount;
+	boolean			is_tdma_btautoslot;
+	boolean			is_tdma_btautoslot_hang;
+
+	boolean			is_esco_mode;
+	u8			switch_band_notify_to;
+	boolean			is_rf_state_off;
+
+	boolean			is_hid_low_pri_tx_overhead;
+	boolean			is_bt_multi_link;
+	boolean			is_bt_a2dp_sink;
+	boolean			is_set_ps_state_fail;
+	u8			cnt_set_ps_state_fail;
+
+	u8			wl_fw_dbg_info[10];
+	u8			wl_rx_rate;
+	u8			wl_tx_rate;
+	u8			wl_rts_rx_rate;
+	u8			wl_center_channel;
+	u8			wl_tx_macid;
+	u8			wl_tx_retry_ratio;
+
+	u16			score_board_WB;
+	boolean			is_hid_rcu;
+	u16			legacy_forbidden_slot;
+	u16			le_forbidden_slot;
+	u8			bt_a2dp_vendor_id;
+	u32			bt_a2dp_device_name;
+	boolean			is_ble_scan_en;
+
+	boolean			is_bt_opp_exist;
+	boolean			gl_wifi_busy;
+	u8			connect_ap_period_cnt;
+
+	boolean			is_bt_reenable;
+	u8			cnt_bt_reenable;
+	boolean			is_wifi_linkscan_process;
+	u8			wl_coex_mode;
+	u8			wl_pnp_wakeup_downcnt;
+	u32			coex_run_cnt;
 };
 
-
 #define  BT_8821C_2ANT_EXT_BAND_SWITCH_USE_DPDT	0
 #define  BT_8821C_2ANT_EXT_BAND_SWITCH_USE_SPDT	1
 
-
 struct rfe_type_8821c_2ant {
-
-	u8			rfe_module_type;
+	u8		rfe_module_type;
 	boolean		ext_ant_switch_exist;
-	u8			ext_ant_switch_type;			/* 0:DPDT, 1:SPDT */
-	u8			ext_ant_switch_ctrl_polarity;		/*  iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */
+	/* 0:DPDT, 1:SPDT */
+	u8		ext_ant_switch_type;
+	/*  iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */
+	u8		ext_ant_switch_ctrl_polarity;
 
 	boolean		ext_band_switch_exist;
-	u8			ext_band_switch_type;			/* 0:DPDT, 1:SPDT */
-	u8			ext_band_switch_ctrl_polarity;
+	/* 0:DPDT, 1:SPDT */
+	u8		ext_band_switch_type;
+	u8		ext_band_switch_ctrl_polarity;
 
 	boolean		ant_at_main_port;
 
-	boolean		wlg_Locate_at_btg;				/*  If TRUE:  WLG at BTG, If FALSE: WLG at WLAG */
+	/*  If TRUE:  WLG at BTG, If FALSE: WLG at WLAG */
+	boolean		wlg_locate_at_btg;
 
-	boolean		ext_ant_switch_diversity;		/* If diversity on */
+	/* If diversity on */
+	boolean		ext_ant_switch_diversity;
 };
 
-#define BT_8821C_2ANT_ANTDET_PSD_POINTS			256	/* MAX:1024 */
-#define BT_8821C_2ANT_ANTDET_PSD_AVGNUM		1	/* MAX:3 */
-#define BT_8821C_2ANT_ANTDET_BUF_LEN			16
-
-struct psdscan_sta_8821c_2ant {
-
-	u32			ant_det_bt_le_channel;  /* BT LE Channel ex:2412 */
-	u32			ant_det_bt_tx_time;
-	u32			ant_det_pre_psdscan_peak_val;
-	boolean			ant_det_is_ant_det_available;
-	u32			ant_det_psd_scan_peak_val;
-	boolean			ant_det_is_btreply_available;
-	u32			ant_det_psd_scan_peak_freq;
-
-	u8			ant_det_result;
-	u8			ant_det_peak_val[BT_8821C_2ANT_ANTDET_BUF_LEN];
-	u8			ant_det_peak_freq[BT_8821C_2ANT_ANTDET_BUF_LEN];
-	u32			ant_det_try_count;
-	u32			ant_det_fail_count;
-	u32			ant_det_inteval_count;
-	u32			ant_det_thres_offset;
-
-	u32			real_cent_freq;
-	s32			real_offset;
-	u32			real_span;
-
-	u32			psd_band_width;  /* unit: Hz */
-	u32			psd_point;		/* 128/256/512/1024 */
-	u32			psd_report[1024];  /* unit:dB (20logx), 0~255 */
-	u32			psd_report_max_hold[1024];  /* unit:dB (20logx), 0~255 */
-	u32			psd_start_point;
-	u32			psd_stop_point;
-	u32			psd_max_value_point;
-	u32			psd_max_value;
-	u32			psd_max_value2;
-	u32			psd_avg_value;   /* filter loop_max_value that below BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT, and average the rest*/
-	u32			psd_loop_max_value[BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT];  /*max value in each loop */
-	u32			psd_start_base;
-	u32			psd_avg_num;	/* 1/8/16/32 */
-	u32			psd_gen_count;
-	boolean			is_AntDet_running;
-	boolean			is_psd_show_max_only;
+struct wifi_link_info_8821c_2ant {
+	u8				num_of_active_port;
+	u32				port_connect_status;
+	boolean				is_all_under_5g;
+	boolean				is_mcc_25g;
+	boolean				is_p2p_connected;
 };
 
-
 /* *******************************************
  * The following is interface which will notify coex module.
  * ******************************************* */
-void ex_halbtc8821c2ant_power_on_setting(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c2ant_pre_load_firmware(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c2ant_init_hw_config(IN struct btc_coexist *btcoexist,
-				       IN boolean wifi_only);
-void ex_halbtc8821c2ant_init_coex_dm(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c2ant_ips_notify(IN struct btc_coexist *btcoexist,
-				   IN u8 type);
-void ex_halbtc8821c2ant_lps_notify(IN struct btc_coexist *btcoexist,
-				   IN u8 type);
-void ex_halbtc8821c2ant_scan_notify(IN struct btc_coexist *btcoexist,
-				    IN u8 type);
-void ex_halbtc8821c2ant_switchband_notify(IN struct btc_coexist *btcoexist,
-		IN u8 type);
-void ex_halbtc8821c2ant_connect_notify(IN struct btc_coexist *btcoexist,
-				       IN u8 type);
-void ex_halbtc8821c2ant_media_status_notify(IN struct btc_coexist *btcoexist,
-		IN u8 type);
-void ex_halbtc8821c2ant_specific_packet_notify(IN struct btc_coexist *btcoexist,
-		IN u8 type);
-void ex_halbtc8821c2ant_bt_info_notify(IN struct btc_coexist *btcoexist,
-				       IN u8 *tmp_buf, IN u8 length);
-void ex_halbtc8821c2ant_rf_status_notify(IN struct btc_coexist *btcoexist,
-		IN u8 type);
-void ex_halbtc8821c2ant_halt_notify(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c2ant_pnp_notify(IN struct btc_coexist *btcoexist,
-				   IN u8 pnp_state);
-void ex_halbtc8821c2ant_periodical(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c2ant_display_coex_info(IN struct btc_coexist *btcoexist);
-void ex_halbtc8821c2ant_antenna_detection(IN struct btc_coexist *btcoexist,
-		IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds);
-void ex_halbtc8821c2ant_display_ant_detection(IN struct btc_coexist *btcoexist);
-
+void ex_halbtc8821c2ant_power_on_setting(struct btc_coexist *btc);
+void ex_halbtc8821c2ant_pre_load_firmware(struct btc_coexist *btc);
+void ex_halbtc8821c2ant_init_hw_config(struct btc_coexist *btc,
+				       boolean wifi_only);
+void ex_halbtc8821c2ant_init_coex_dm(struct btc_coexist *btc);
+void ex_halbtc8821c2ant_ips_notify(struct btc_coexist *btc,
+				   u8 type);
+void ex_halbtc8821c2ant_lps_notify(struct btc_coexist *btc,
+				   u8 type);
+void ex_halbtc8821c2ant_scan_notify(struct btc_coexist *btc,
+				    u8 type);
+void ex_halbtc8821c2ant_switchband_notify(struct btc_coexist *btc,
+					  u8 type);
+void ex_halbtc8821c2ant_connect_notify(struct btc_coexist *btc,
+				       u8 type);
+void ex_halbtc8821c2ant_media_status_notify(struct btc_coexist *btc,
+					    u8 type);
+void ex_halbtc8821c2ant_specific_packet_notify(struct btc_coexist *btc,
+					       u8 type);
+void ex_halbtc8821c2ant_bt_info_notify(struct btc_coexist *btc,
+				       u8 *tmp_buf,  u8 length);
+void ex_halbtc8821c2ant_wl_fwdbginfo_notify(struct btc_coexist *btc,
+					    u8 *tmp_buf, u8 length);
+void ex_halbtc8821c2ant_rx_rate_change_notify(struct btc_coexist *btc,
+					      BOOLEAN is_data_frame,
+					      u8 btc_rate_id);
+void ex_halbtc8821c2ant_tx_rate_change_notify(struct btc_coexist *btc,
+					      u8 tx_rate,
+					      u8 tx_retry_ratio, u8 macid);
+void ex_halbtc8821c2ant_rf_status_notify(struct btc_coexist *btc,
+					 u8 type);
+void ex_halbtc8821c2ant_halt_notify(struct btc_coexist *btc);
+void ex_halbtc8821c2ant_pnp_notify(struct btc_coexist *btc,
+				   u8 pnp_state);
+void ex_halbtc8821c2ant_periodical(struct btc_coexist *btc);
+void ex_halbtc8821c2ant_display_simple_coex_info(struct btc_coexist *btc);
+void ex_halbtc8821c2ant_display_coex_info(struct btc_coexist *btc);
 
 #else
-#define	ex_halbtc8821c2ant_power_on_setting(btcoexist)
-#define	ex_halbtc8821c2ant_pre_load_firmware(btcoexist)
-#define	ex_halbtc8821c2ant_init_hw_config(btcoexist, wifi_only)
-#define	ex_halbtc8821c2ant_init_coex_dm(btcoexist)
-#define	ex_halbtc8821c2ant_ips_notify(btcoexist, type)
-#define	ex_halbtc8821c2ant_lps_notify(btcoexist, type)
-#define	ex_halbtc8821c2ant_scan_notify(btcoexist, type)
-#define   ex_halbtc8821c2ant_switchband_notify(btcoexist,type)
-#define	ex_halbtc8821c2ant_connect_notify(btcoexist, type)
-#define	ex_halbtc8821c2ant_media_status_notify(btcoexist, type)
-#define	ex_halbtc8821c2ant_specific_packet_notify(btcoexist, type)
-#define	ex_halbtc8821c2ant_bt_info_notify(btcoexist, tmp_buf, length)
-#define	ex_halbtc8821c2ant_rf_status_notify(btcoexist, type)
-#define	ex_halbtc8821c2ant_halt_notify(btcoexist)
-#define	ex_halbtc8821c2ant_pnp_notify(btcoexist, pnp_state)
-#define	ex_halbtc8821c2ant_periodical(btcoexist)
-#define	ex_halbtc8821c2ant_display_coex_info(btcoexist)
-#define	ex_halbtc8821c2ant_display_ant_detection(btcoexist)
-#define	ex_halbtc8821c2ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds)
+#define ex_halbtc8821c2ant_power_on_setting(btc)
+#define ex_halbtc8821c2ant_pre_load_firmware(btc)
+#define ex_halbtc8821c2ant_init_hw_config(btc, wifi_only)
+#define ex_halbtc8821c2ant_init_coex_dm(btc)
+#define ex_halbtc8821c2ant_ips_notify(btc, type)
+#define ex_halbtc8821c2ant_lps_notify(btc, type)
+#define ex_halbtc8821c2ant_scan_notify(btc, type)
+#define ex_halbtc8821c2ant_switchband_notify(btc, type)
+#define ex_halbtc8821c2ant_connect_notify(btc, type)
+#define ex_halbtc8821c2ant_media_status_notify(btc, type)
+#define ex_halbtc8821c2ant_specific_packet_notify(btc, type)
+#define ex_halbtc8821c2ant_bt_info_notify(btc, tmp_buf, length)
+#define ex_halbtc8821c2ant_wl_fwdbginfo_notify(btc, tmp_buf, length)
+#define ex_halbtc8821c2ant_rx_rate_change_notify(btc, is_data_frame,     \
+						 btc_rate_id)
+#define ex_halbtc8821c2ant_tx_rate_change_notify(btcoexist, tx_rate,     \
+						tx_retry_ratio, macid)
+#define ex_halbtc8821c2ant_rf_status_notify(btc, type)
+#define ex_halbtc8821c2ant_halt_notify(btc)
+#define ex_halbtc8821c2ant_pnp_notify(btc, pnp_state)
+#define ex_halbtc8821c2ant_periodical(btc)
+#define ex_halbtc8821c2ant_display_simple_coex_info(btc)
+#define ex_halbtc8821c2ant_display_coex_info(btc)
 #endif
 
 #endif

+ 27 - 0
hal/btc/halbtc8821cwifionly.c

@@ -1,3 +1,17 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 #include "mp_precomp.h"
 
 static struct	rfe_type_8821c_wifi_only	gl_rfe_type_8821c_1ant;
@@ -164,6 +178,9 @@ ex_hal8821c_wifi_only_hw_config(
 	/*gnt_wl=1 , gnt_bt=0*/
 	halwifionly_phy_set_bb_reg(pwifionlycfg, 0x1704, 0xffffffff, 0x7700);
 	halwifionly_phy_set_bb_reg(pwifionlycfg, 0x1700, 0xffffffff, 0xc00f0038);
+
+	halwifionly_phy_set_bb_reg(pwifionlycfg, 0x6c0, 0xffffffff, 0xaaaaaaaa);
+	halwifionly_phy_set_bb_reg(pwifionlycfg, 0x6c4, 0xffffffff, 0xaaaaaaaa);
 }
 
 VOID
@@ -184,3 +201,13 @@ ex_hal8821c_wifi_only_switchbandnotify(
 	hal8821c_wifi_only_switch_antenna(pwifionlycfg, is_5g);
 }
 
+VOID
+ex_hal8821c_wifi_only_connectnotify(
+	IN struct wifi_only_cfg *pwifionlycfg,
+	IN u1Byte  is_5g
+	)
+{
+	hal8821c_wifi_only_switch_antenna(pwifionlycfg, is_5g);
+}
+
+

+ 19 - 0
hal/btc/halbtc8821cwifionly.h

@@ -1,3 +1,17 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 #ifndef __INC_HAL8821CWIFIONLYHWCFG_H
 #define __INC_HAL8821CWIFIONLYHWCFG_H
 
@@ -63,6 +77,11 @@ ex_hal8821c_wifi_only_scannotify(
 	IN u1Byte  is_5g
 	);
 VOID
+ex_hal8821c_wifi_only_connectnotify(
+	IN struct wifi_only_cfg *pwifionlycfg,
+	IN u1Byte  is_5g
+	);
+VOID
 ex_hal8821c_wifi_only_switchbandnotify(
 	IN struct wifi_only_cfg *pwifionlycfg,
 	IN u1Byte  is_5g

+ 264 - 2
hal/btc/halbtcoutsrc.h

@@ -1,6 +1,120 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 #ifndef	__HALBTC_OUT_SRC_H__
 #define __HALBTC_OUT_SRC_H__
 
+enum {
+	BTC_CCK_1,
+	BTC_CCK_2,
+	BTC_CCK_5_5,
+	BTC_CCK_11,
+	BTC_OFDM_6,
+	BTC_OFDM_9,
+	BTC_OFDM_12,
+	BTC_OFDM_18,
+	BTC_OFDM_24,
+	BTC_OFDM_36,
+	BTC_OFDM_48,
+	BTC_OFDM_54,
+	BTC_MCS_0,
+	BTC_MCS_1,
+	BTC_MCS_2,
+	BTC_MCS_3,
+	BTC_MCS_4,
+	BTC_MCS_5,
+	BTC_MCS_6,
+	BTC_MCS_7,
+	BTC_MCS_8,
+	BTC_MCS_9,
+	BTC_MCS_10,
+	BTC_MCS_11,
+	BTC_MCS_12,
+	BTC_MCS_13,
+	BTC_MCS_14,
+	BTC_MCS_15,
+	BTC_MCS_16,
+	BTC_MCS_17,
+	BTC_MCS_18,
+	BTC_MCS_19,
+	BTC_MCS_20,
+	BTC_MCS_21,
+	BTC_MCS_22,
+	BTC_MCS_23,
+	BTC_MCS_24,
+	BTC_MCS_25,
+	BTC_MCS_26,
+	BTC_MCS_27,
+	BTC_MCS_28,
+	BTC_MCS_29,
+	BTC_MCS_30,
+	BTC_MCS_31,
+	BTC_VHT_1SS_MCS_0,
+	BTC_VHT_1SS_MCS_1,
+	BTC_VHT_1SS_MCS_2,
+	BTC_VHT_1SS_MCS_3,
+	BTC_VHT_1SS_MCS_4,
+	BTC_VHT_1SS_MCS_5,
+	BTC_VHT_1SS_MCS_6,
+	BTC_VHT_1SS_MCS_7,
+	BTC_VHT_1SS_MCS_8,
+	BTC_VHT_1SS_MCS_9,
+	BTC_VHT_2SS_MCS_0,
+	BTC_VHT_2SS_MCS_1,
+	BTC_VHT_2SS_MCS_2,
+	BTC_VHT_2SS_MCS_3,
+	BTC_VHT_2SS_MCS_4,
+	BTC_VHT_2SS_MCS_5,
+	BTC_VHT_2SS_MCS_6,
+	BTC_VHT_2SS_MCS_7,
+	BTC_VHT_2SS_MCS_8,
+	BTC_VHT_2SS_MCS_9,
+	BTC_VHT_3SS_MCS_0,
+	BTC_VHT_3SS_MCS_1,
+	BTC_VHT_3SS_MCS_2,
+	BTC_VHT_3SS_MCS_3,
+	BTC_VHT_3SS_MCS_4,
+	BTC_VHT_3SS_MCS_5,
+	BTC_VHT_3SS_MCS_6,
+	BTC_VHT_3SS_MCS_7,
+	BTC_VHT_3SS_MCS_8,
+	BTC_VHT_3SS_MCS_9,
+	BTC_VHT_4SS_MCS_0,
+	BTC_VHT_4SS_MCS_1,
+	BTC_VHT_4SS_MCS_2,
+	BTC_VHT_4SS_MCS_3,
+	BTC_VHT_4SS_MCS_4,
+	BTC_VHT_4SS_MCS_5,
+	BTC_VHT_4SS_MCS_6,
+	BTC_VHT_4SS_MCS_7,
+	BTC_VHT_4SS_MCS_8,
+	BTC_VHT_4SS_MCS_9,
+	BTC_MCS_32,
+	BTC_UNKNOWN,
+	BTC_PKT_MGNT,
+	BTC_PKT_CTRL,
+	BTC_PKT_UNKNOWN,
+	BTC_PKT_NOT_FOR_ME,
+	BTC_RATE_MAX
+};
+
+enum {
+	BTC_MULTIPORT_SCC,
+	BTC_MULTIPORT_MCC_DUAL_CHANNEL,
+	BTC_MULTIPORT_MCC_DUAL_BAND,
+	BTC_MULTIPORT_MAX
+};
 
 #define		BTC_COEX_OFFLOAD			0
 #define		BTC_TMP_BUF_SHORT		20
@@ -19,6 +133,9 @@ do {\
 #define		NORMAL_EXEC					FALSE
 #define		FORCE_EXEC						TRUE
 
+#define		NM_EXCU						FALSE
+#define		FC_EXCU						TRUE
+
 #define		BTC_RF_OFF					0x0
 #define		BTC_RF_ON					0x1
 
@@ -100,6 +217,7 @@ typedef enum _BTC_CHIP_TYPE {
 /* following is for command line utility */
 #define	CL_SPRINTF	rsprintf
 #define	CL_PRINTF	DCMD_Printf
+#define CL_STRNCAT(dst, dst_size, src, src_size) rstrncat(dst, src, src_size)
 
 struct btc_board_info {
 	/* The following is some board information */
@@ -119,6 +237,8 @@ struct btc_board_info {
 	u8				ant_det_result;
 	boolean			ant_det_result_five_complete;
 	u32				antdetval;
+	u8				customerID;
+	u8				customer_id;
 };
 
 typedef enum _BTC_DBG_OPCODE {
@@ -156,6 +276,7 @@ typedef enum _BTC_WIFI_ROLE {
 typedef enum _BTC_WIRELESS_FREQ {
 	BTC_FREQ_2_4G					= 0x0,
 	BTC_FREQ_5G						= 0x1,
+	BTC_FREQ_25G					= 0x2,
 	BTC_FREQ_MAX
 } BTC_WIRELESS_FREQ, *PBTC_WIRELESS_FREQ;
 
@@ -178,6 +299,7 @@ typedef enum _BTC_WIFI_PNP {
 	BTC_WIFI_PNP_WAKE_UP					= 0x0,
 	BTC_WIFI_PNP_SLEEP						= 0x1,
 	BTC_WIFI_PNP_SLEEP_KEEP_ANT				= 0x2,
+	BTC_WIFI_PNP_WOWLAN					= 0x3,
 	BTC_WIFI_PNP_MAX
 } BTC_WIFI_PNP, *PBTC_WIFI_PNP;
 
@@ -237,6 +359,8 @@ typedef enum _BTC_GET_TYPE {
 	BTC_GET_BL_HS_CONNECTING,
 	BTC_GET_BL_WIFI_FW_READY,
 	BTC_GET_BL_WIFI_CONNECTED,
+	BTC_GET_BL_WIFI_DUAL_BAND_CONNECTED,
+	BTC_GET_BL_WIFI_LINK_INFO,
 	BTC_GET_BL_WIFI_BUSY,
 	BTC_GET_BL_WIFI_SCAN,
 	BTC_GET_BL_WIFI_LINK,
@@ -250,6 +374,7 @@ typedef enum _BTC_GET_TYPE {
 	BTC_GET_BL_WIFI_IS_IN_MP_MODE,
 	BTC_GET_BL_IS_ASUS_8723B,
 	BTC_GET_BL_RF4CE_CONNECTED,
+	BTC_GET_BL_WIFI_LW_PWR_STATE,
 
 	/* type s4Byte */
 	BTC_GET_S4_WIFI_RSSI,
@@ -264,6 +389,8 @@ typedef enum _BTC_GET_TYPE {
 	BTC_GET_U4_VENDOR,
 	BTC_GET_U4_SUPPORTED_VERSION,
 	BTC_GET_U4_SUPPORTED_FEATURE,
+	BTC_GET_U4_BT_DEVICE_INFO,
+	BTC_GET_U4_BT_FORBIDDEN_SLOT_VAL,
 	BTC_GET_U4_WIFI_IQK_TOTAL,
 	BTC_GET_U4_WIFI_IQK_OK,
 	BTC_GET_U4_WIFI_IQK_FAIL,
@@ -278,6 +405,9 @@ typedef enum _BTC_GET_TYPE {
 	BTC_GET_U1_ANT_TYPE,
 	BTC_GET_U1_IOT_PEER,
 
+	/* type u2Byte */
+	BTC_GET_U2_BEACON_PERIOD,
+
 	/*===== for 1Ant ======*/
 	BTC_GET_U1_LPS_MODE,
 
@@ -297,6 +427,7 @@ typedef enum _BTC_SET_TYPE {
 	BTC_SET_BL_INC_SCAN_DEV_NUM,
 	BTC_SET_BL_BT_TX_RX_MASK,
 	BTC_SET_BL_MIRACAST_PLUS_BT,
+	BTC_SET_BL_BT_LNA_CONSTRAIN_LEVEL,
 
 	/* type u1Byte */
 	BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON,
@@ -306,6 +437,9 @@ typedef enum _BTC_SET_TYPE {
 	BTC_SET_ACT_GET_BT_RSSI,
 	BTC_SET_ACT_AGGREGATE_CTRL,
 	BTC_SET_ACT_ANTPOSREGRISTRY_CTRL,
+
+	// for mimo ps mode setting
+	BTC_SET_MIMO_PS_MODE,
 	/*===== for 1Ant ======*/
 	/* type BOOLEAN */
 
@@ -317,6 +451,8 @@ typedef enum _BTC_SET_TYPE {
 	BTC_SET_ACT_LEAVE_LPS,
 	BTC_SET_ACT_ENTER_LPS,
 	BTC_SET_ACT_NORMAL_LPS,
+	BTC_SET_ACT_PRE_NORMAL_LPS,
+	BTC_SET_ACT_POST_NORMAL_LPS,
 	BTC_SET_ACT_DISABLE_LOW_POWER,
 	BTC_SET_ACT_UPDATE_RAMASK,
 	BTC_SET_ACT_SEND_MIMO_PS,
@@ -349,6 +485,7 @@ typedef enum _BTC_NOTIFY_TYPE_SCAN {
 	BTC_SCAN_FINISH							= 0x0,
 	BTC_SCAN_START							= 0x1,
 	BTC_SCAN_START_2G						= 0x2,
+	BTC_SCAN_START_5G						= 0x3,
 	BTC_SCAN_MAX
 } BTC_NOTIFY_TYPE_SCAN, *PBTC_NOTIFY_TYPE_SCAN;
 typedef enum _BTC_NOTIFY_TYPE_SWITCHBAND {
@@ -368,6 +505,7 @@ typedef enum _BTC_NOTIFY_TYPE_ASSOCIATE {
 typedef enum _BTC_NOTIFY_TYPE_MEDIA_STATUS {
 	BTC_MEDIA_DISCONNECT					= 0x0,
 	BTC_MEDIA_CONNECT						= 0x1,
+	BTC_MEDIA_CONNECT_5G					= 0x02,
 	BTC_MEDIA_MAX
 } BTC_NOTIFY_TYPE_MEDIA_STATUS, *PBTC_NOTIFY_TYPE_MEDIA_STATUS;
 typedef enum _BTC_NOTIFY_TYPE_SPECIFIC_PACKET {
@@ -396,6 +534,8 @@ typedef enum _BTC_BT_OFFON {
 	BTC_BT_ON				= 0x1,
 } BTC_BTOFFON, *PBTC_BT_OFFON;
 
+#define BTC_5G_BAND 0x80
+
 /*==================================================
 For following block is for coex offload
 ==================================================*/
@@ -505,6 +645,49 @@ typedef struct _BTC_OFFLOAD {
 extern BTC_OFFLOAD				gl_coex_offload;
 /*==================================================*/
 
+/* BTC_LINK_MODE same as WIFI_LINK_MODE */
+typedef enum _BTC_LINK_MODE{
+	BTC_LINK_NONE=0,
+	BTC_LINK_ONLY_GO,
+	BTC_LINK_ONLY_GC,
+	BTC_LINK_ONLY_STA,
+	BTC_LINK_ONLY_AP,
+	BTC_LINK_2G_MCC_GO_STA,
+	BTC_LINK_5G_MCC_GO_STA,
+	BTC_LINK_25G_MCC_GO_STA,
+	BTC_LINK_2G_MCC_GC_STA,
+	BTC_LINK_5G_MCC_GC_STA,
+	BTC_LINK_25G_MCC_GC_STA,
+	BTC_LINK_2G_SCC_GO_STA,
+	BTC_LINK_5G_SCC_GO_STA,
+	BTC_LINK_2G_SCC_GC_STA,
+	BTC_LINK_5G_SCC_GC_STA,
+	BTC_LINK_MAX=30
+}BTC_LINK_MODE, *PBTC_LINK_MODE;
+
+
+struct btc_wifi_link_info {
+	BTC_LINK_MODE link_mode; /* LinkMode */
+	u1Byte sta_center_channel; /* StaCenterChannel */
+	u1Byte p2p_center_channel; /* P2PCenterChannel	*/
+	BOOLEAN bany_client_join_go;
+	BOOLEAN benable_noa;
+	BOOLEAN bhotspot;
+};
+
+typedef enum _BTC_MULTI_PORT_TDMA_MODE {
+	BTC_MULTI_PORT_TDMA_MODE_NONE=0,
+	BTC_MULTI_PORT_TDMA_MODE_2G_SCC_GO,
+	BTC_MULTI_PORT_TDMA_MODE_2G_P2P_GO,
+	BTC_MULTI_PORT_TDMA_MODE_2G_HOTSPOT_GO
+} BTC_MULTI_PORT_TDMA_MODE, *PBTC_MULTI_PORT_TDMA_MODE;
+
+typedef struct btc_multi_port_tdma_info {
+	BTC_MULTI_PORT_TDMA_MODE btc_multi_port_tdma_mode;
+	u1Byte start_time_from_bcn;
+	u1Byte bt_time;
+} BTC_MULTI_PORT_TDMA_INFO, *PBTC_MULTI_PORT_TDMA_INFO;
+
 typedef u1Byte
 (*BFP_BTC_R1)(
 	IN	PVOID			pBtcContext,
@@ -567,7 +750,7 @@ typedef u4Byte
 typedef VOID
 (*BFP_BTC_SET_RF_REG)(
 	IN	PVOID			pBtcContext,
-	IN	u1Byte			eRFPath,
+	IN	enum rf_path		eRFPath,
 	IN	u4Byte			RegAddr,
 	IN	u4Byte			BitMask,
 	IN	u4Byte			Data
@@ -575,7 +758,7 @@ typedef VOID
 typedef u4Byte
 (*BFP_BTC_GET_RF_REG)(
 	IN	PVOID			pBtcContext,
-	IN	u1Byte			eRFPath,
+	IN	enum rf_path		eRFPath,
 	IN	u4Byte			RegAddr,
 	IN	u4Byte			BitMask
 	);
@@ -656,6 +839,14 @@ typedef u4Byte
 	IN	PVOID			pBtcContext
 	);
 
+typedef u4Byte
+(*BFP_BTC_SET_ATOMIC) 	(
+	IN	PVOID			pBtcContext,
+	IN	pu4Byte 		target,
+	IN	u4Byte			val
+	);
+
+
 typedef VOID
 (*BTC_PHYDM_MODIFY_RA_PCR_THRESHLOD)(
 	IN	PVOID		pDM_Odm,
@@ -669,6 +860,12 @@ typedef u4Byte
 	IN		u1Byte	info_type
 	);
 
+typedef VOID
+(*BTC_PHYDM_MODIFY_ANTDIV_HWSW)(
+	IN		PVOID	pDM_Odm,
+	IN		u1Byte	type
+	);
+
 typedef u1Byte
 (*BFP_BTC_GET_ANT_DET_VAL_FROM_BT)(
 
@@ -779,6 +976,9 @@ struct btc_statistics {
 	u32					cnt_coex_dm_switch;
 	u32					cnt_stack_operation_notify;
 	u32					cnt_dbg_ctrl;
+	u32					cnt_rate_id_notify;
+	u32					cnt_halt_notify;
+	u32					cnt_pnp_notify;
 };
 
 struct btc_coexist {
@@ -788,6 +988,7 @@ struct btc_coexist {
 	struct  btc_bt_info			bt_info;		/*some bt info referenced by non-bt module*/
 	struct  btc_stack_info		stack_info;
 	struct  btc_bt_link_info		bt_link_info;
+	struct btc_wifi_link_info	wifi_link_info;
 
 #ifdef CONFIG_RF4CE_COEXIST
 	struct  btc_rf4ce_info		rf4ce_info;
@@ -802,6 +1003,8 @@ struct btc_coexist {
 	pu1Byte					cli_buf;
 	struct btc_statistics		statistics;
 	u1Byte				pwrModeVal[10];
+	BOOLEAN dbg_mode;
+	BOOLEAN auto_report;
 
 	/* function pointers */
 	/* io related */
@@ -839,12 +1042,59 @@ struct btc_coexist {
 	BFP_BTC_GET_BT_COEX_SUPPORTED_FEATURE btc_get_bt_coex_supported_feature;
 	BFP_BTC_GET_BT_COEX_SUPPORTED_VERSION btc_get_bt_coex_supported_version;
 	BFP_BTC_GET_PHYDM_VERSION		btc_get_bt_phydm_version;
+	BFP_BTC_SET_ATOMIC			btc_set_atomic;
 	BTC_PHYDM_MODIFY_RA_PCR_THRESHLOD	btc_phydm_modify_RA_PCR_threshold;
 	BTC_PHYDM_CMNINFOQUERY				btc_phydm_query_PHY_counter;
+	BTC_PHYDM_MODIFY_ANTDIV_HWSW		btc_phydm_modify_antdiv_hwsw;
 	BFP_BTC_GET_ANT_DET_VAL_FROM_BT		btc_get_ant_det_val_from_bt;
 	BFP_BTC_GET_BLE_SCAN_TYPE_FROM_BT	btc_get_ble_scan_type_from_bt;
 	BFP_BTC_GET_BLE_SCAN_PARA_FROM_BT	btc_get_ble_scan_para_from_bt;
 	BFP_BTC_GET_BT_AFH_MAP_FROM_BT		btc_get_bt_afh_map_from_bt;
+
+	union {
+		#ifdef CONFIG_RTL8822B
+		struct coex_dm_8822b_1ant	coex_dm_8822b_1ant;
+		struct coex_dm_8822b_2ant	coex_dm_8822b_2ant;
+		#endif /* 8822B */
+		#ifdef CONFIG_RTL8821C
+		struct coex_dm_8821c_1ant	coex_dm_8821c_1ant;
+		struct coex_dm_8821c_2ant	coex_dm_8821c_2ant;
+		#endif /* 8821C */
+	};
+
+	union {
+		#ifdef CONFIG_RTL8822B
+		struct coex_sta_8822b_1ant	coex_sta_8822b_1ant;
+		struct coex_sta_8822b_2ant	coex_sta_8822b_2ant;
+		#endif /* 8822B */
+		#ifdef CONFIG_RTL8821C
+		struct coex_sta_8821c_1ant	coex_sta_8821c_1ant;
+		struct coex_sta_8821c_2ant	coex_sta_8821c_2ant;
+		#endif /* 8821C */
+	};
+
+	union {
+		#ifdef CONFIG_RTL8822B
+		struct rfe_type_8822b_1ant	rfe_type_8822b_1ant;
+		struct rfe_type_8822b_2ant	rfe_type_8822b_2ant;
+		#endif /* 8822B */
+		#ifdef CONFIG_RTL8821C
+		struct rfe_type_8821c_1ant	rfe_type_8821c_1ant;
+		struct rfe_type_8821c_2ant	rfe_type_8821c_2ant;
+		#endif /* 8821C */
+	};
+
+	union {
+		#ifdef CONFIG_RTL8822B
+		struct wifi_link_info_8822b_1ant	wifi_link_info_8822b_1ant;
+		struct wifi_link_info_8822b_2ant	wifi_link_info_8822b_2ant;
+		#endif /* 8822B */
+		#ifdef CONFIG_RTL8821C
+		struct wifi_link_info_8821c_1ant	wifi_link_info_8821c_1ant;
+		struct wifi_link_info_8821c_2ant	wifi_link_info_8821c_2ant;
+		#endif /* 8821C */
+	};
+
 };
 typedef struct btc_coexist *PBTC_COEXIST;
 
@@ -918,6 +1168,18 @@ EXhalbtcoutsrc_RfStatusNotify(
 	IN	u1Byte				type
 	);
 VOID
+EXhalbtcoutsrc_WlFwDbgInfoNotify(
+	IN	PBTC_COEXIST		pBtCoexist,
+	IN	pu1Byte			tmpBuf,
+	IN	u1Byte			length
+	);
+VOID
+EXhalbtcoutsrc_rx_rate_change_notify(
+	IN	PBTC_COEXIST	pBtCoexist,
+	IN 	BOOLEAN			is_data_frame,
+	IN	u1Byte			btc_rate_id
+	);
+VOID
 EXhalbtcoutsrc_StackOperationNotify(
 	IN	PBTC_COEXIST		pBtCoexist,
 	IN	u1Byte			type

+ 51 - 10
hal/btc/mp_precomp.h

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2013 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #ifndef __MP_PRECOMP_H__
 #define __MP_PRECOMP_H__
 
@@ -27,6 +22,7 @@
 
 #ifdef PLATFORM_LINUX
 #define rsprintf snprintf
+#define rstrncat(dst, src, src_size) strncat(dst, src, src_size)
 #elif defined(PLATFORM_WINDOWS)
 #define rsprintf sprintf_s
 #endif
@@ -64,27 +60,72 @@ extern u4Byte GLBtcDbgType[];
 #define HS_SUPPORT		0
 #endif
 
-#include "halbtcoutsrc.h"
+/* for wifi only mode */
+#include "hal_btcoex_wifionly.h"
+
+#ifdef CONFIG_BT_COEXIST
+
+struct wifi_only_cfg;
+struct btc_coexist;
+
+#ifdef CONFIG_RTL8192E
 #include "halbtc8192e1ant.h"
 #include "halbtc8192e2ant.h"
+#endif
+
+#ifdef CONFIG_RTL8723B
+#include "halbtc8723bwifionly.h"
 #include "halbtc8723b1ant.h"
 #include "halbtc8723b2ant.h"
+#endif
+
+#ifdef CONFIG_RTL8812A
 #include "halbtc8812a1ant.h"
 #include "halbtc8812a2ant.h"
+#endif
+
+#ifdef CONFIG_RTL8821A
 #include "halbtc8821a1ant.h"
 #include "halbtc8821a2ant.h"
+#endif
+
+#ifdef CONFIG_RTL8703B
 #include "halbtc8703b1ant.h"
+#endif
+
+#ifdef CONFIG_RTL8723D
 #include "halbtc8723d1ant.h"
 #include "halbtc8723d2ant.h"
+#endif
+
+#ifdef CONFIG_RTL8822B
+#include "halbtc8822bwifionly.h"
 #include "halbtc8822b1ant.h"
 #include "halbtc8822b2ant.h"
+#endif
+
+#ifdef CONFIG_RTL8821C
+#include "halbtc8821cwifionly.h"
 #include "halbtc8821c1ant.h"
 #include "halbtc8821c2ant.h"
+#endif
 
-/* for wifi only mode */
-#include "hal_btcoex_wifionly.h"
+#include "halbtcoutsrc.h"
+
+#else /* CONFIG_BT_COEXIST */
+
+#ifdef CONFIG_RTL8723B
 #include "halbtc8723bwifionly.h"
+#endif
+
+#ifdef CONFIG_RTL8822B
 #include "halbtc8822bwifionly.h"
+#endif
+
+#ifdef CONFIG_RTL8821C
 #include "halbtc8821cwifionly.h"
+#endif
+
+#endif /* CONFIG_BT_COEXIST */
 
 #endif /*  __MP_PRECOMP_H__ */

+ 45 - 5
hal/efuse/efuse_mask.h

@@ -1,5 +1,19 @@
-
-#if DEV_BUS_TYPE == RT_USB_INTERFACE
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_USB_HCI
 
 	#if defined(CONFIG_RTL8188E)
 		#include "rtl8188e/HalEfuseMask8188E_USB.h"
@@ -37,6 +51,10 @@
 		#include "rtl8188f/HalEfuseMask8188F_USB.h"
 	#endif
 
+	#if defined(CONFIG_RTL8188GTV)
+		#include "rtl8188gtv/HalEfuseMask8188GTV_USB.h"
+	#endif
+
 	#if defined(CONFIG_RTL8822B)
 		#include "rtl8822b/HalEfuseMask8822B_USB.h"
 	#endif
@@ -44,8 +62,17 @@
 	#if defined(CONFIG_RTL8821C)
 		#include "rtl8821c/HalEfuseMask8821C_USB.h"
 	#endif
+	
+	#if defined(CONFIG_RTL8710B)
+		#include "rtl8710b/HalEfuseMask8710B_USB.h"
+	#endif
+	
+	#if defined(CONFIG_RTL8192F)
+		#include "rtl8192f/HalEfuseMask8192F_USB.h"
+	#endif
+#endif /*CONFIG_USB_HCI*/
 
-#elif DEV_BUS_TYPE == RT_PCI_INTERFACE
+#ifdef CONFIG_PCI_HCI
 
 	#if defined(CONFIG_RTL8188E)
 		#include "rtl8188e/HalEfuseMask8188E_PCIE.h"
@@ -85,7 +112,11 @@
 		#include "rtl8821c/HalEfuseMask8821C_PCIE.h"
 	#endif
 
-#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE
+	#if defined(CONFIG_RTL8192F)
+		#include "rtl8192f/HalEfuseMask8192F_PCIE.h"
+	#endif
+#endif /*CONFIG_PCI_HCI*/
+#ifdef CONFIG_SDIO_HCI
 	#if defined(CONFIG_RTL8723B)
 		#include "rtl8723b/HalEfuseMask8723B_SDIO.h"
 	#endif
@@ -102,6 +133,10 @@
 		#include "rtl8188f/HalEfuseMask8188F_SDIO.h"
 	#endif
 
+	#if defined(CONFIG_RTL8188GTV)
+		#include "rtl8188gtv/HalEfuseMask8188GTV_SDIO.h"
+	#endif
+
 	#if defined(CONFIG_RTL8723D)
 		#include "rtl8723d/HalEfuseMask8723D_SDIO.h"
 	#endif
@@ -121,4 +156,9 @@
 	#if defined(CONFIG_RTL8822B)
 		#include "rtl8822b/HalEfuseMask8822B_SDIO.h"
 	#endif
-#endif
+
+	#if defined(CONFIG_RTL8192F)
+		#include "rtl8192f/HalEfuseMask8192F_SDIO.h"
+	#endif
+
+#endif /*CONFIG_SDIO_HCI*/

+ 13 - 18
hal/efuse/rtl8821c/HalEfuseMask8821C_PCIE.c

@@ -1,22 +1,17 @@
 /******************************************************************************
-*
-* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
-*
-* 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
-*
-*
-******************************************************************************/
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
 
 /* #include "Mp_Precomp.h" */
 /* #include "../odm_precomp.h" */

+ 13 - 18
hal/efuse/rtl8821c/HalEfuseMask8821C_PCIE.h

@@ -1,22 +1,17 @@
 /******************************************************************************
-*
-* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
-*
-* 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
-*
-*
-******************************************************************************/
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
 
 
 

+ 13 - 18
hal/efuse/rtl8821c/HalEfuseMask8821C_SDIO.c

@@ -1,22 +1,17 @@
 /******************************************************************************
-*
-* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
-*
-* 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
-*
-*
-******************************************************************************/
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
 
 /* #include "Mp_Precomp.h" */
 /* #include "../odm_precomp.h" */

+ 13 - 18
hal/efuse/rtl8821c/HalEfuseMask8821C_SDIO.h

@@ -1,22 +1,17 @@
 /******************************************************************************
-*
-* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
-*
-* 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
-*
-*
-******************************************************************************/
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
 
 
 

+ 13 - 18
hal/efuse/rtl8821c/HalEfuseMask8821C_USB.c

@@ -1,22 +1,17 @@
 /******************************************************************************
-*
-* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
-*
-* 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
-*
-*
-******************************************************************************/
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
 
 /* #include "Mp_Precomp.h" */
 /* #include "../odm_precomp.h" */

+ 13 - 18
hal/efuse/rtl8821c/HalEfuseMask8821C_USB.h

@@ -1,22 +1,17 @@
 /******************************************************************************
-*
-* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
-*
-* 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
-*
-*
-******************************************************************************/
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
 
 
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 503 - 83
hal/hal_btcoex.c


+ 73 - 5
hal/hal_btcoex_wifionly.c

@@ -1,6 +1,23 @@
-#include "btc/mp_precomp.h"
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2017 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.
+ *
+ *****************************************************************************/
 #include <hal_btcoex_wifionly.h>
 
+#if (CONFIG_BTCOEX_SUPPORT_WIFI_ONLY_CFG == 1)
+
+#include "btc/mp_precomp.h"
+
 struct  wifi_only_cfg GLBtCoexistWifiOnly;
 
 void halwifionly_write1byte(PVOID pwifionlyContext, u32 RegAddr, u8 Data)
@@ -71,7 +88,7 @@ void halwifionly_bitmaskwrite1byte(PVOID pwifionlyContext, u32 regAddr, u8 bitMa
 	rtw_write8(Adapter, regAddr, data);
 }
 
-void halwifionly_phy_set_rf_reg(PVOID pwifionlyContext, u8 eRFPath, u32 RegAddr, u32 BitMask, u32 Data)
+void halwifionly_phy_set_rf_reg(PVOID pwifionlyContext, enum rf_path eRFPath, u32 RegAddr, u32 BitMask, u32 Data)
 {
 	struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext;
 	PADAPTER		Adapter = pwifionlycfg->Adapter;
@@ -95,10 +112,16 @@ void hal_btcoex_wifionly_switchband_notify(PADAPTER padapter)
 	if (pHalData->current_band_type == BAND_ON_5G)
 		is_5g = _TRUE;
 
-	if (IS_HARDWARE_TYPE_8822B(padapter))
+	if (IS_HARDWARE_TYPE_8822B(padapter)) {
+#ifdef CONFIG_RTL8822B
 		ex_hal8822b_wifi_only_switchbandnotify(&GLBtCoexistWifiOnly, is_5g);
+#endif
+	}
+
+#ifdef CONFIG_RTL8821C
 	else if (IS_HARDWARE_TYPE_8821C(padapter))
 		ex_hal8821c_wifi_only_switchbandnotify(&GLBtCoexistWifiOnly, is_5g);
+#endif
 }
 
 void hal_btcoex_wifionly_scan_notify(PADAPTER padapter)
@@ -109,22 +132,57 @@ void hal_btcoex_wifionly_scan_notify(PADAPTER padapter)
 	if (pHalData->current_band_type == BAND_ON_5G)
 		is_5g = _TRUE;
 
-	if (IS_HARDWARE_TYPE_8822B(padapter))
+	if (IS_HARDWARE_TYPE_8822B(padapter)) {
+#ifdef CONFIG_RTL8822B
 		ex_hal8822b_wifi_only_scannotify(&GLBtCoexistWifiOnly, is_5g);
+#endif
+	}
+
+#ifdef CONFIG_RTL8821C
 	else if (IS_HARDWARE_TYPE_8821C(padapter))
 		ex_hal8821c_wifi_only_scannotify(&GLBtCoexistWifiOnly, is_5g);
+#endif
+}
+
+void hal_btcoex_wifionly_connect_notify(PADAPTER padapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+	u8 is_5g = _FALSE;
+
+	if (pHalData->current_band_type == BAND_ON_5G)
+		is_5g = _TRUE;
+
+	if (IS_HARDWARE_TYPE_8822B(padapter)) {
+#ifdef CONFIG_RTL8822B
+		ex_hal8822b_wifi_only_connectnotify(&GLBtCoexistWifiOnly, is_5g);
+#endif
+	}
+
+#ifdef CONFIG_RTL8821C
+	else if (IS_HARDWARE_TYPE_8821C(padapter))
+		ex_hal8821c_wifi_only_connectnotify(&GLBtCoexistWifiOnly, is_5g);
+#endif
 }
 
 void hal_btcoex_wifionly_hw_config(PADAPTER padapter)
 {
 	struct wifi_only_cfg *pwifionlycfg = &GLBtCoexistWifiOnly;
 
-	if (IS_HARDWARE_TYPE_8723B(padapter))
+	if (IS_HARDWARE_TYPE_8723B(padapter)) {
+#ifdef CONFIG_RTL8723B
 		ex_hal8723b_wifi_only_hw_config(pwifionlycfg);
+#endif
+	}
+
+#ifdef CONFIG_RTL8822B
 	else if (IS_HARDWARE_TYPE_8822B(padapter))
 		ex_hal8822b_wifi_only_hw_config(pwifionlycfg);
+#endif
+
+#ifdef CONFIG_RTL8821C
 	else if (IS_HARDWARE_TYPE_8821C(padapter))
 		ex_hal8821c_wifi_only_hw_config(pwifionlycfg);
+#endif
 }
 
 void hal_btcoex_wifionly_initlizevariables(PADAPTER padapter)
@@ -148,9 +206,19 @@ void hal_btcoex_wifionly_initlizevariables(PADAPTER padapter)
 #endif
 
 	pwifionly_haldata->customer_id = CUSTOMER_NORMAL;
+}
+
+void hal_btcoex_wifionly_AntInfoSetting(PADAPTER padapter)
+{
+	struct wifi_only_cfg		*pwifionlycfg = &GLBtCoexistWifiOnly;
+	struct wifi_only_haldata	*pwifionly_haldata = &pwifionlycfg->haldata_info;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
 	pwifionly_haldata->efuse_pg_antnum = pHalData->EEPROMBluetoothAntNum;
 	pwifionly_haldata->efuse_pg_antpath = pHalData->ant_path;
 	pwifionly_haldata->rfe_type = pHalData->rfe_type;
 	pwifionly_haldata->ant_div_cfg = pHalData->AntDivCfg;
 }
 
+#endif
+

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 761 - 106
hal/hal_com.c


+ 11 - 7
hal/hal_com_c2h.h

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #ifndef __COMMON_C2H_H__
 #define __COMMON_C2H_H__
 
@@ -75,6 +70,10 @@ typedef enum _C2H_EVT {
 	C2H_DEFEATURE_DBG = 0x22,
 	C2H_CUSTOMER_STR_RPT = 0x24,
 	C2H_CUSTOMER_STR_RPT_2 = 0x25,
+	C2H_WLAN_INFO = 0x27,
+#ifdef RTW_PER_CMD_SUPPORT_FW
+	C2H_PER_RATE_RPT = 0x2c,
+#endif
 	C2H_DEFEATURE_RSVD = 0xFD,
 	C2H_EXTEND = 0xff,
 } C2H_EVT;
@@ -116,4 +115,9 @@ int c2h_customer_str_rpt_hdl(_adapter *adapter, u8 *data, u8 len);
 int c2h_customer_str_rpt_2_hdl(_adapter *adapter, u8 *data, u8 len);
 #endif /* CONFIG_RTW_CUSTOMER_STR */
 
+#ifdef RTW_PER_CMD_SUPPORT_FW
+/* C2H_PER_RATE_RPT, 0x2c */
+int c2h_per_rate_rpt_hdl(_adapter *adapter, u8 *data, u8 len);
+#endif
+
 #endif /* __COMMON_C2H_H__ */

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 296 - 248
hal/hal_com_phycfg.c


+ 1127 - 55
hal/hal_dm.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2014 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2014 - 2017 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
@@ -11,20 +11,15 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 
 #include <drv_types.h>
 #include <hal_data.h>
 
 /* A mapping from HalData to ODM. */
-enum odm_board_type_e boardType(u8 InterfaceSel)
+enum odm_board_type boardType(u8 InterfaceSel)
 {
-	enum odm_board_type_e        board	= ODM_BOARD_DEFAULT;
+	enum odm_board_type        board	= ODM_BOARD_DEFAULT;
 
 #ifdef CONFIG_PCI_HCI
 	INTERFACE_SELECT_PCIE   pcie	= (INTERFACE_SELECT_PCIE)InterfaceSel;
@@ -70,22 +65,227 @@ enum odm_board_type_e boardType(u8 InterfaceSel)
 	return board;
 }
 
+void rtw_hal_update_iqk_fw_offload_cap(_adapter *adapter)
+{
+	PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
+	struct dm_struct *p_dm_odm = adapter_to_phydm(adapter);
+
+	if (hal->RegIQKFWOffload) {
+		rtw_sctx_init(&hal->iqk_sctx, 0);
+		phydm_fwoffload_ability_init(p_dm_odm, PHYDM_RF_IQK_OFFLOAD);
+	} else
+		phydm_fwoffload_ability_clear(p_dm_odm, PHYDM_RF_IQK_OFFLOAD);
+
+	RTW_INFO("IQK FW offload:%s\n", hal->RegIQKFWOffload ? "enable" : "disable");
+}
+
+#if ((RTL8822B_SUPPORT == 1) || (RTL8821C_SUPPORT == 1) || (RTL8814B_SUPPORT == 1))
+void rtw_phydm_iqk_trigger(_adapter *adapter)
+{
+	struct dm_struct *p_dm_odm = adapter_to_phydm(adapter);
+	u8 clear = _TRUE;
+	u8 segment = _FALSE;
+	u8 rfk_forbidden = _FALSE;
+
+	/*segment = _rtw_phydm_iqk_segment_chk(adapter);*/
+	halrf_cmn_info_set(p_dm_odm, HALRF_CMNINFO_RFK_FORBIDDEN, rfk_forbidden);
+	halrf_cmn_info_set(p_dm_odm, HALRF_CMNINFO_IQK_SEGMENT, segment);
+	halrf_segment_iqk_trigger(p_dm_odm, clear, segment);
+}
+#endif
+
+void rtw_phydm_iqk_trigger_dbg(_adapter *adapter, bool recovery, bool clear, bool segment)
+{
+	struct dm_struct *p_dm_odm = adapter_to_phydm(adapter);
+
+#if ((RTL8822B_SUPPORT == 1) || (RTL8821C_SUPPORT == 1) || (RTL8814B_SUPPORT == 1))
+		halrf_segment_iqk_trigger(p_dm_odm, clear, segment);
+#else
+		halrf_iqk_trigger(p_dm_odm, recovery);
+#endif
+}
+void rtw_phydm_lck_trigger(_adapter *adapter)
+{
+	struct dm_struct *p_dm_odm = adapter_to_phydm(adapter);
+
+	halrf_lck_trigger(p_dm_odm);
+}
+#ifdef CONFIG_DBG_RF_CAL
+void rtw_hal_iqk_test(_adapter *adapter, bool recovery, bool clear, bool segment)
+{
+	struct dm_struct *p_dm_odm = adapter_to_phydm(adapter);
+
+	rtw_ps_deny(adapter, PS_DENY_IOCTL);
+	LeaveAllPowerSaveModeDirect(adapter);
+
+	rtw_phydm_ability_backup(adapter);
+	rtw_phydm_func_disable_all(adapter);
+
+	halrf_cmn_info_set(p_dm_odm, HALRF_CMNINFO_ABILITY, HAL_RF_IQK);
+
+	rtw_phydm_iqk_trigger_dbg(adapter, recovery, clear, segment);
+	rtw_phydm_ability_restore(adapter);
+
+	rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL);
+}
+
+void rtw_hal_lck_test(_adapter *adapter)
+{
+	struct dm_struct *p_dm_odm = adapter_to_phydm(adapter);
+
+	rtw_ps_deny(adapter, PS_DENY_IOCTL);
+	LeaveAllPowerSaveModeDirect(adapter);
+
+	rtw_phydm_ability_backup(adapter);
+	rtw_phydm_func_disable_all(adapter);
+
+	halrf_cmn_info_set(p_dm_odm, HALRF_CMNINFO_ABILITY, HAL_RF_LCK);
+
+	rtw_phydm_lck_trigger(adapter);
+
+	rtw_phydm_ability_restore(adapter);
+	rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL);
+}
+#endif
+
+#ifdef CONFIG_FW_OFFLOAD_PARAM_INIT
+void rtw_hal_update_param_init_fw_offload_cap(_adapter *adapter)
+{
+	struct dm_struct *p_dm_odm = adapter_to_phydm(adapter);
+
+	if (adapter->registrypriv.fw_param_init)
+		phydm_fwoffload_ability_init(p_dm_odm, PHYDM_PHY_PARAM_OFFLOAD);
+	else
+		phydm_fwoffload_ability_clear(p_dm_odm, PHYDM_PHY_PARAM_OFFLOAD);
+
+	RTW_INFO("Init-Parameter FW offload:%s\n", adapter->registrypriv.fw_param_init ? "enable" : "disable");
+}
+#endif
+
+void record_ra_info(void *p_dm_void, u8 macid, struct cmn_sta_info *p_sta, u64 ra_mask)
+{
+	struct dm_struct *p_dm = (struct dm_struct *)p_dm_void;
+	_adapter *adapter = p_dm->adapter;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+
+	if (p_sta) {
+		rtw_macid_ctl_set_bw(macid_ctl, macid, p_sta->ra_info.ra_bw_mode);
+		rtw_macid_ctl_set_vht_en(macid_ctl, macid, p_sta->ra_info.is_vht_enable);
+		rtw_macid_ctl_set_rate_bmp0(macid_ctl, macid, ra_mask);
+		rtw_macid_ctl_set_rate_bmp1(macid_ctl, macid, ra_mask >> 32);
+
+		rtw_update_tx_rate_bmp(adapter_to_dvobj(adapter));
+	}
+}
+
+#ifdef CONFIG_SUPPORT_DYNAMIC_TXPWR
+void rtw_phydm_fill_desc_dpt(void *dm, u8 *desc, u8 dpt_lv)
+{
+	struct dm_struct *p_dm = (struct dm_struct *)dm;
+	_adapter *adapter = p_dm->adapter;
+
+	switch (rtw_get_chip_type(adapter)) {
+/*
+	#ifdef CONFIG_RTL8188F
+	case RTL8188F:
+		break;
+	#endif
+
+	#ifdef CONFIG_RTL8723B
+	case RTL8723B :
+		break;
+	#endif
+
+	#ifdef CONFIG_RTL8703B
+	case RTL8703B :
+		break;
+	#endif
+
+	#ifdef CONFIG_RTL8812A
+	case RTL8812 :
+		break;
+	#endif
+
+	#ifdef CONFIG_RTL8821A
+	case RTL8821:
+		break;
+	#endif
+
+	#ifdef CONFIG_RTL8814A
+	case RTL8814A :
+		break;
+	#endif
+
+	#ifdef CONFIG_RTL8192F
+	case RTL8192F :
+		break;
+	#endif
+*/
+/*
+	#ifdef CONFIG_RTL8192E
+	case RTL8192E :
+		SET_TX_DESC_TX_POWER_0_PSET_92E(desc, dpt_lv);
+		break;
+	#endif
+*/
+
+	#ifdef CONFIG_RTL8821C
+	case RTL8821C :
+		SET_TX_DESC_TXPWR_OFSET_8821C(desc, dpt_lv);
+	break;
+	#endif
+
+	default :
+		RTW_ERR("%s IC not support dynamic tx power\n", __func__);
+		break;
+	}
+}
+void rtw_phydm_set_dyntxpwr(_adapter *adapter, u8 *desc, u8 mac_id)
+{
+	struct dm_struct *dm = adapter_to_phydm(adapter);
+
+	odm_set_dyntxpwr(dm, desc, mac_id);
+}
+#endif
+
+#ifdef CONFIG_RTW_TX_2PATH_EN
+void rtw_phydm_tx_2path_en(_adapter *adapter)
+{
+	struct dm_struct *dm = adapter_to_phydm(adapter);
+
+	phydm_tx_2path(dm);
+}
+#endif
+
+void rtw_phydm_ops_func_init(struct dm_struct *p_phydm)
+{
+	struct ra_table *p_ra_t = &p_phydm->dm_ra_table;
+
+	p_ra_t->record_ra_info = record_ra_info;
+	#ifdef CONFIG_SUPPORT_DYNAMIC_TXPWR
+	p_phydm->fill_desc_dyntxpwr = rtw_phydm_fill_desc_dpt;
+	#endif
+}
+void rtw_phydm_priv_init(_adapter *adapter)
+{
+	PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
+	struct dm_struct *phydm = &(hal->odmpriv);
+
+	phydm->adapter = adapter;
+	odm_cmn_info_init(phydm, ODM_CMNINFO_PLATFORM, ODM_CE);
+}
+
 void Init_ODM_ComInfo(_adapter *adapter)
 {
 	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
 	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(adapter);
-	struct PHY_DM_STRUCT		*pDM_Odm = &(pHalData->odmpriv);
-	struct mlme_ext_priv	*pmlmeext = &adapter->mlmeextpriv;
-	struct mlme_priv	*pmlmepriv = &adapter->mlmepriv;
+	struct dm_struct	*pDM_Odm = &(pHalData->odmpriv);
 	struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter);
 	int i;
 
-	_rtw_memset(pDM_Odm, 0, sizeof(*pDM_Odm));
-
-	pDM_Odm->adapter = adapter;
-
-	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_PLATFORM, ODM_CE);
-
+	/*phydm_op_mode could be change for different scenarios: ex: SoftAP - PHYDM_BALANCE_MODE*/
+	pHalData->phydm_op_mode = PHYDM_PERFORMANCE_MODE;/*Service one device*/
 	rtw_odm_init_ic_type(adapter);
 
 	if (rtw_get_intf_type(adapter) == RTW_GSPI)
@@ -99,28 +299,10 @@ void Init_ODM_ComInfo(_adapter *adapter)
 
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_BWIFI_TEST, adapter->registrypriv.wifi_spec);
 
-
-	if (pHalData->rf_type == RF_1T1R)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R);
-	else if (pHalData->rf_type == RF_1T2R)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R);
-	else if (pHalData->rf_type == RF_2T2R)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R);
-	else if (pHalData->rf_type == RF_2T2R_GREEN)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R_GREEN);
-	else if (pHalData->rf_type == RF_2T3R)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T3R);
-	else if (pHalData->rf_type == RF_2T4R)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T4R);
-	else if (pHalData->rf_type == RF_3T3R)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_3T3R);
-	else if (pHalData->rf_type == RF_3T4R)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_3T4R);
-	else if (pHalData->rf_type == RF_4T4R)
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_4T4R);
-	else
-		odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_XTXR);
-
+#ifdef CONFIG_ADVANCE_OTA
+	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_ADVANCE_OTA, adapter->registrypriv.adv_ota);
+#endif
+	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, pHalData->rf_type);
 
 	{
 		/* 1 ======= BoardType: ODM_CMNINFO_BOARD_TYPE ======= */
@@ -149,12 +331,11 @@ void Init_ODM_ComInfo(_adapter *adapter)
 		/* 1 ============== End of BoardType ============== */
 	}
 
-	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_DOMAIN_CODE_2G, pHalData->Regulation2_4G);
-	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_DOMAIN_CODE_5G, pHalData->Regulation5G);
+	rtw_hal_set_odm_var(adapter, HAL_ODM_REGULATION, NULL, _TRUE);
 
 #ifdef CONFIG_DFS_MASTER
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_DFS_REGION_DOMAIN, adapter->registrypriv.dfs_region_domain);
-	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_DFS_MASTER_ENABLE, &(adapter_to_rfctl(adapter)->dfs_master_enabled));
+	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_DFS_MASTER_ENABLE, &(adapter_to_rfctl(adapter)->radar_detect_enabled));
 #endif
 
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_GPA, pHalData->TypeGPA);
@@ -163,6 +344,7 @@ void Init_ODM_ComInfo(_adapter *adapter)
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_ALNA, pHalData->TypeALNA);
 
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RFE_TYPE, pHalData->rfe_type);
+	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_X_CAP_SETTING, pHalData->crystal_cap);
 
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_EXT_TRSW, 0);
 
@@ -170,8 +352,6 @@ void Init_ODM_ComInfo(_adapter *adapter)
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_REGRFKFREEENABLE, adapter->registrypriv.RegPwrTrimEnable);
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RFKFREEENABLE, pHalData->RfKFreeEnable);
 
-	/*Antenna diversity relative parameters*/
-	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_ANT_DIV, &(pHalData->AntDivCfg));
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_ANTENNA_TYPE, pHalData->TRxAntDivType);
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_BE_FIX_TX_ANT, pHalData->b_fix_tx_ant);
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH, pHalData->with_extenal_ant_switch);
@@ -183,45 +363,72 @@ void Init_ODM_ComInfo(_adapter *adapter)
 	/*Add by YuChen for adaptivity init*/
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_ADAPTIVITY, &(adapter->registrypriv.adaptivity_en));
 	phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_CARRIER_SENSE_ENABLE, (adapter->registrypriv.adaptivity_mode != 0) ? TRUE : FALSE);
-	phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_DCBACKOFF, adapter->registrypriv.adaptivity_dc_backoff);
-	phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_DYNAMICLINKADAPTIVITY, (adapter->registrypriv.adaptivity_dml != 0) ? TRUE : FALSE);
 	phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_TH_L2H_INI, adapter->registrypriv.adaptivity_th_l2h_ini);
 	phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_TH_EDCCA_HL_DIFF, adapter->registrypriv.adaptivity_th_edcca_hl_diff);
 
+	/*halrf info init*/
+	halrf_cmn_info_init(pDM_Odm, HALRF_CMNINFO_EEPROM_THERMAL_VALUE, pHalData->eeprom_thermal_meter);
+	halrf_cmn_info_init(pDM_Odm, HALRF_CMNINFO_PWT_TYPE, 0);
+
+	if (rtw_odm_adaptivity_needed(adapter) == _TRUE)
+		rtw_odm_adaptivity_config_msg(RTW_DBGDUMP, adapter);
+
 #ifdef CONFIG_IQK_PA_OFF
 	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_IQKPAOFF, 1);
 #endif
-	odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_IQKFWOFFLOAD, pHalData->RegIQKFWOffload);
+	rtw_hal_update_iqk_fw_offload_cap(adapter);
+	#ifdef CONFIG_FW_OFFLOAD_PARAM_INIT
+	rtw_hal_update_param_init_fw_offload_cap(adapter);
+	#endif
 
 	/* Pointer reference */
+	/*Antenna diversity relative parameters*/
+	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_ANT_DIV, &(pHalData->AntDivCfg));
+	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_MP_MODE, &(adapter->registrypriv.mp_mode));
+
+	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BB_OPERATION_MODE, &(pHalData->phydm_op_mode));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_TX_UNI, &(dvobj->traffic_stat.tx_bytes));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_RX_UNI, &(dvobj->traffic_stat.rx_bytes));
-	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_WM_MODE, &(pmlmeext->cur_wireless_mode));
+
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BAND, &(pHalData->current_band_type));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_FORCED_RATE, &(pHalData->ForcedDataRate));
-	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_FORCED_IGI_LB, &(pHalData->u1ForcedIgiLb));
 
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_SEC_CHNL_OFFSET, &(pHalData->nCur40MhzPrimeSC));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_SEC_MODE, &(adapter->securitypriv.dot11PrivacyAlgrthm));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BW, &(pHalData->current_channel_bw));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_CHNL, &(pHalData->current_channel));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_NET_CLOSED, &(adapter->net_closed));
-	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_FORCED_IGI_LB, &(pHalData->u1ForcedIgiLb));
 
-	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_SCAN, &(pmlmepriv->bScanInProcess));
+	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_SCAN, &(pHalData->bScanInProcess));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_POWER_SAVING, &(pwrctl->bpower_saving));
 	/*Add by Yuchen for phydm beamforming*/
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_TX_TP, &(dvobj->traffic_stat.cur_tx_tp));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_RX_TP, &(dvobj->traffic_stat.cur_rx_tp));
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_ANT_TEST, &(pHalData->antenna_test));
+#ifdef CONFIG_RTL8723B
+	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_IS1ANTENNA, &pHalData->EEPROMBluetoothAntNum);
+	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_RFDEFAULTPATH, &pHalData->ant_path);
+#endif /*CONFIG_RTL8723B*/
 #ifdef CONFIG_USB_HCI
 	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_HUBUSBMODE, &(dvobj->usb_speed));
 #endif
+
+#ifdef CONFIG_DYNAMIC_SOML
+	odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_ADAPTIVE_SOML, &(adapter->registrypriv.dyn_soml_en));
+#endif
+
+	/*halrf info hook*/
+#ifdef CONFIG_MP_INCLUDED
+	halrf_cmn_info_hook(pDM_Odm, HALRF_CMNINFO_CON_TX, &(adapter->mppriv.mpt_ctx.is_start_cont_tx));
+	halrf_cmn_info_hook(pDM_Odm, HALRF_CMNINFO_SINGLE_TONE, &(adapter->mppriv.mpt_ctx.is_single_tone));
+	halrf_cmn_info_hook(pDM_Odm, HALRF_CMNINFO_CARRIER_SUPPRESSION, &(adapter->mppriv.mpt_ctx.is_carrier_suppression));
+	halrf_cmn_info_hook(pDM_Odm, HALRF_CMNINFO_MP_RATE_INDEX, &(adapter->mppriv.mpt_ctx.mpt_rate_index));
+#endif/*CONFIG_MP_INCLUDED*/
 	for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++)
 		odm_cmn_info_ptr_array_hook(pDM_Odm, ODM_CMNINFO_STA_STATUS, i, NULL);
 
 	phydm_init_debug_setting(pDM_Odm);
-
+	rtw_phydm_ops_func_init(pDM_Odm);
 	/* TODO */
 	/* odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BT_OPERATION, _FALSE); */
 	/* odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BT_DISABLE_EDCA, _FALSE); */
@@ -355,7 +562,7 @@ void rtw_hal_turbo_edca(_adapter *adapter)
 				EDCA_BE_DL = edca_setting_DL[iot_peer];
 			}
 
-			if ((ic_type == RTL8812) || (ic_type == RTL8821) || (ic_type == RTL8192E)) { /* add 8812AU/8812AE */
+			if ((ic_type == RTL8812) || (ic_type == RTL8821) || (ic_type == RTL8192E) || (ic_type == RTL8192F)) { /* add 8812AU/8812AE */
 				EDCA_BE_UL = 0x5ea42b;
 				EDCA_BE_DL = 0x5ea42b;
 
@@ -363,7 +570,8 @@ void rtw_hal_turbo_edca(_adapter *adapter)
 			}
 
 			if (interface_type == RTW_PCIE &&
-				(ic_type == RTL8822B)) {
+				((ic_type == RTL8822B)
+				|| (ic_type == RTL8814A))) {
 				EDCA_BE_UL = 0x6ea42b;
 				EDCA_BE_DL = 0x6ea42b;
 			}
@@ -373,6 +581,59 @@ void rtw_hal_turbo_edca(_adapter *adapter)
 			else
 				edca_param = EDCA_BE_UL;
 
+#ifdef CONFIG_EXTEND_LOWRATE_TXOP
+#define TXOP_CCK1M			0x01A6
+#define TXOP_CCK2M			0x00E6
+#define TXOP_CCK5M			0x006B
+#define TXOP_OFD6M			0x0066
+#define TXOP_MCS6M			0x0061
+{
+			struct sta_info *psta;
+			struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+			u8 mac_id, role, current_rate_id;
+			
+			/*	search all used & connect2AP macid	*/
+			for (mac_id = 0; mac_id < macid_ctl->num; mac_id++) {
+				if (rtw_macid_is_used(macid_ctl, mac_id))  {
+					role = GET_H2CCMD_MSRRPT_PARM_ROLE(&(macid_ctl->h2c_msr[mac_id]));
+					if (role != H2C_MSR_ROLE_AP)
+						continue;
+
+					psta = macid_ctl->sta[mac_id];
+					current_rate_id = rtw_get_current_tx_rate(adapter, psta);
+					/*  Check init tx_rate==1M and set 0x508[31:16]==0x019B(unit 32us) if it is 	*/
+					switch (current_rate_id) {
+						case DESC_RATE1M:
+							edca_param &= 0x0000FFFF;
+							edca_param |= (TXOP_CCK1M<<16);
+							break;
+						case DESC_RATE2M:
+							edca_param &= 0x0000FFFF;
+							edca_param |= (TXOP_CCK2M<<16);
+							break;
+						case DESC_RATE5_5M:
+							edca_param &= 0x0000FFFF;
+							edca_param |= (TXOP_CCK5M<<16);
+							break;
+						case DESC_RATE6M:
+							edca_param &= 0x0000FFFF;
+							edca_param |= (TXOP_OFD6M<<16);
+							break;
+						case DESC_RATEMCS0:
+							edca_param &= 0x0000FFFF;
+							edca_param |= (TXOP_MCS6M<<16);
+							break;
+						default:
+							break;
+					}
+				}
+			}
+}
+#endif
+
+#ifdef 	CONFIG_RTW_CUSTOMIZE_BEEDCA
+			edca_param = CONFIG_RTW_CUSTOMIZE_BEEDCA;
+#endif
 			rtw_hal_set_hwreg(adapter, HW_VAR_AC_PARAM_BE, (u8 *)(&edca_param));
 
 			RTW_DBG("Turbo EDCA =0x%x\n", edca_param);
@@ -395,4 +656,815 @@ void rtw_hal_turbo_edca(_adapter *adapter)
 
 }
 
+s8 rtw_phydm_get_min_rssi(_adapter *adapter)
+{
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+	s8 rssi_min = 0;
+
+	rssi_min = phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_RSSI_MIN);
+	return rssi_min;
+}
+
+u8 rtw_phydm_get_cur_igi(_adapter *adapter)
+{
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+	u8 cur_igi = 0;
+
+	cur_igi = phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CURR_IGI);
+	return cur_igi;
+}
+
+u32 rtw_phydm_get_phy_cnt(_adapter *adapter, enum phy_cnt cnt)
+{
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+
+	if (cnt == FA_OFDM)
+		return  phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_FA_OFDM);
+	else if (cnt == FA_CCK)
+		return  phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_FA_CCK);
+	else if (cnt == FA_TOTAL)
+		return  phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_FA_TOTAL);
+	else if (cnt == CCA_OFDM)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CCA_OFDM);
+	else if (cnt == CCA_CCK)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CCA_CCK);
+	else if (cnt == CCA_ALL)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CCA_ALL);
+	else if (cnt == CRC32_OK_VHT)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CRC32_OK_VHT);
+	else if (cnt == CRC32_OK_HT)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CRC32_OK_HT);
+	else if (cnt == CRC32_OK_LEGACY)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CRC32_OK_LEGACY);
+	else if (cnt == CRC32_OK_CCK)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CRC32_OK_CCK);
+	else if (cnt == CRC32_ERROR_VHT)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CRC32_ERROR_VHT);
+	else if (cnt == CRC32_ERROR_HT)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CRC32_ERROR_HT);
+	else if (cnt == CRC32_ERROR_LEGACY)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CRC32_ERROR_LEGACY);
+	else if (cnt == CRC32_ERROR_CCK)
+		return	phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CRC32_ERROR_CCK);
+	else
+		return 0;
+}
+
+u8 rtw_phydm_is_iqk_in_progress(_adapter *adapter)
+{
+	u8 rts = _FALSE;
+	struct dm_struct *podmpriv = adapter_to_phydm(adapter);
+
+	odm_acquire_spin_lock(podmpriv, RT_IQK_SPINLOCK);
+	if (podmpriv->rf_calibrate_info.is_iqk_in_progress == _TRUE) {
+		RTW_ERR("IQK InProgress\n");
+		rts = _TRUE;
+	}
+	odm_release_spin_lock(podmpriv, RT_IQK_SPINLOCK);
+
+	return rts;
+}
+
+void SetHalODMVar(
+	PADAPTER				Adapter,
+	HAL_ODM_VARIABLE		eVariable,
+	PVOID					pValue1,
+	BOOLEAN					bSet)
+{
+	struct dm_struct *podmpriv = adapter_to_phydm(Adapter);
+	/* _irqL irqL; */
+	switch (eVariable) {
+	case HAL_ODM_STA_INFO: {
+		struct sta_info *psta = (struct sta_info *)pValue1;
+
+		if (bSet) {
+			RTW_INFO("### Set STA_(%d) info ###\n", psta->cmn.mac_id);
+			odm_cmn_info_ptr_array_hook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->cmn.mac_id, psta);
+			psta->cmn.dm_ctrl = STA_DM_CTRL_ACTIVE;
+			phydm_cmn_sta_info_hook(podmpriv, psta->cmn.mac_id, &(psta->cmn));
+		} else {
+			RTW_INFO("### Clean STA_(%d) info ###\n", psta->cmn.mac_id);
+			/* _enter_critical_bh(&pHalData->odm_stainfo_lock, &irqL); */
+			psta->cmn.dm_ctrl = 0;
+			odm_cmn_info_ptr_array_hook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->cmn.mac_id, NULL);
+			phydm_cmn_sta_info_hook(podmpriv, psta->cmn.mac_id, NULL);
+
+			/* _exit_critical_bh(&pHalData->odm_stainfo_lock, &irqL); */
+		}
+	}
+		break;
+	case HAL_ODM_P2P_STATE:
+		odm_cmn_info_update(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet);
+		break;
+	case HAL_ODM_WIFI_DISPLAY_STATE:
+		odm_cmn_info_update(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet);
+		break;
+	case HAL_ODM_REGULATION:
+		/* used to auto enable/disable adaptivity by SD7 */
+		phydm_adaptivity_info_update(podmpriv, PHYDM_ADAPINFO_DOMAIN_CODE_2G, 0);
+		phydm_adaptivity_info_update(podmpriv, PHYDM_ADAPINFO_DOMAIN_CODE_5G, 0);
+		break;
+	case HAL_ODM_INITIAL_GAIN: {
+		u8 rx_gain = *((u8 *)(pValue1));
+		/*printk("rx_gain:%x\n",rx_gain);*/
+		if (rx_gain == 0xff) {/*restore rx gain*/
+			/*odm_write_dig(podmpriv,pDigTable->backup_ig_value);*/
+			odm_pause_dig(podmpriv, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_0, rx_gain);
+		} else {
+			/*pDigTable->backup_ig_value = pDigTable->cur_ig_value;*/
+			/*odm_write_dig(podmpriv,rx_gain);*/
+			odm_pause_dig(podmpriv, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_0, rx_gain);
+		}
+	}
+	break;
+	case HAL_ODM_RX_INFO_DUMP: {
+		u8 cur_igi = 0;
+		s8 rssi_min;
+		void *sel;
+
+		sel = pValue1;
+		cur_igi = rtw_phydm_get_cur_igi(Adapter);
+		rssi_min = rtw_phydm_get_min_rssi(Adapter);
+
+		_RTW_PRINT_SEL(sel, "============ Rx Info dump ===================\n");
+		_RTW_PRINT_SEL(sel, "is_linked = %d, rssi_min = %d(%%), current_igi = 0x%x\n", podmpriv->is_linked, rssi_min, cur_igi);
+		_RTW_PRINT_SEL(sel, "cnt_cck_fail = %d, cnt_ofdm_fail = %d, Total False Alarm = %d\n",
+			rtw_phydm_get_phy_cnt(Adapter, FA_CCK),
+			rtw_phydm_get_phy_cnt(Adapter, FA_OFDM),
+			rtw_phydm_get_phy_cnt(Adapter, FA_TOTAL));
+
+		if (podmpriv->is_linked) {
+			_RTW_PRINT_SEL(sel, "rx_rate = %s", HDATA_RATE(podmpriv->rx_rate));
+			if (IS_HARDWARE_TYPE_8814A(Adapter))
+				_RTW_PRINT_SEL(sel, " rssi_a = %d(%%), rssi_b = %d(%%), rssi_c = %d(%%), rssi_d = %d(%%)\n",
+					podmpriv->rssi_a, podmpriv->rssi_b, podmpriv->rssi_c, podmpriv->rssi_d);
+			else
+				_RTW_PRINT_SEL(sel, " rssi_a = %d(%%), rssi_b = %d(%%)\n", podmpriv->rssi_a, podmpriv->rssi_b);
+#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA
+			rtw_dump_raw_rssi_info(Adapter, sel);
+#endif
+		}
+	}
+		break;
+	case HAL_ODM_RX_Dframe_INFO: {
+		void *sel;
+
+		sel = pValue1;
+
+		/*_RTW_PRINT_SEL(sel , "HAL_ODM_RX_Dframe_INFO\n");*/
+#ifdef DBG_RX_DFRAME_RAW_DATA
+		rtw_dump_rx_dframe_info(Adapter, sel);
+#endif
+	}
+		break;
+
+#ifdef CONFIG_ANTENNA_DIVERSITY
+	case HAL_ODM_ANTDIV_SELECT: {
+		u8	antenna = (*(u8 *)pValue1);
+		HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(Adapter);
+		/*switch antenna*/
+		odm_update_rx_idle_ant(&pHalData->odmpriv, antenna);
+		/*RTW_INFO("==> HAL_ODM_ANTDIV_SELECT, Ant_(%s)\n", (antenna == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT");*/
+
+	}
+		break;
+#endif
+
+	default:
+		break;
+	}
+}
+
+void GetHalODMVar(
+	PADAPTER				Adapter,
+	HAL_ODM_VARIABLE		eVariable,
+	PVOID					pValue1,
+	PVOID					pValue2)
+{
+	struct dm_struct *podmpriv = adapter_to_phydm(Adapter);
+
+	switch (eVariable) {
+#ifdef CONFIG_ANTENNA_DIVERSITY
+	case HAL_ODM_ANTDIV_SELECT: {
+		struct phydm_fat_struct	*pDM_FatTable = &podmpriv->dm_fat_table;
+		*((u8 *)pValue1) = pDM_FatTable->rx_idle_ant;
+	}
+		break;
+#endif
+	case HAL_ODM_INITIAL_GAIN:
+		*((u8 *)pValue1) = rtw_phydm_get_cur_igi(Adapter);
+		break;
+	default:
+		break;
+	}
+}
+
+#ifdef RTW_HALMAC
+#include "../hal_halmac.h"
+#endif
+
+enum hal_status
+rtw_phydm_fw_iqk(
+	struct dm_struct	*p_dm_odm,
+	u8 clear,
+	u8 segment
+)
+{
+	#ifdef RTW_HALMAC
+	struct _ADAPTER *adapter = p_dm_odm->adapter;
+
+	if (rtw_halmac_iqk(adapter_to_dvobj(adapter), clear, segment) == 0)
+		return HAL_STATUS_SUCCESS;
+	#endif
+	return HAL_STATUS_FAILURE;
+}
+
+enum hal_status
+rtw_phydm_cfg_phy_para(
+	struct dm_struct	*p_dm_odm,
+	enum phydm_halmac_param config_type,
+	u32 offset,
+	u32 data,
+	u32 mask,
+	enum rf_path e_rf_path,
+	u32 delay_time)
+{
+	#ifdef RTW_HALMAC
+	struct _ADAPTER *adapter = p_dm_odm->adapter;
+	struct rtw_phy_parameter para;
+
+	switch (config_type) {
+	case PHYDM_HALMAC_CMD_MAC_W8:
+		para.cmd = 0; /* MAC register */
+		para.data.mac.offset = offset;
+		para.data.mac.value = data;
+		para.data.mac.msk = mask;
+		para.data.mac.msk_en = (mask) ? 1 : 0;
+		para.data.mac.size = 1;
+	break;
+	case PHYDM_HALMAC_CMD_MAC_W16:
+		para.cmd = 0; /* MAC register */
+		para.data.mac.offset = offset;
+		para.data.mac.value = data;
+		para.data.mac.msk = mask;
+		para.data.mac.msk_en = (mask) ? 1 : 0;
+		para.data.mac.size = 2;
+	break;
+	case PHYDM_HALMAC_CMD_MAC_W32:
+		para.cmd = 0; /* MAC register */
+		para.data.mac.offset = offset;
+		para.data.mac.value = data;
+		para.data.mac.msk = mask;
+		para.data.mac.msk_en = (mask) ? 1 : 0;
+		para.data.mac.size = 4;
+	break;
+	case PHYDM_HALMAC_CMD_BB_W8:
+		para.cmd = 1; /* BB register */
+		para.data.bb.offset = offset;
+		para.data.bb.value = data;
+		para.data.bb.msk = mask;
+		para.data.bb.msk_en = (mask) ? 1 : 0;
+		para.data.bb.size = 1;
+	break;
+	case PHYDM_HALMAC_CMD_BB_W16:
+		para.cmd = 1; /* BB register */
+		para.data.bb.offset = offset;
+		para.data.bb.value = data;
+		para.data.bb.msk = mask;
+		para.data.bb.msk_en = (mask) ? 1 : 0;
+		para.data.bb.size = 2;
+	break;
+	case PHYDM_HALMAC_CMD_BB_W32:
+		para.cmd = 1; /* BB register */
+		para.data.bb.offset = offset;
+		para.data.bb.value = data;
+		para.data.bb.msk = mask;
+		para.data.bb.msk_en = (mask) ? 1 : 0;
+		para.data.bb.size = 4;
+	break;
+	case PHYDM_HALMAC_CMD_RF_W:
+		para.cmd = 2; /* RF register */
+		para.data.rf.offset = offset;
+		para.data.rf.value = data;
+		para.data.rf.msk = mask;
+		para.data.rf.msk_en = (mask) ? 1 : 0;
+		if (e_rf_path == RF_PATH_A)
+			para.data.rf.path = 0;
+		else if (e_rf_path == RF_PATH_B)
+			para.data.rf.path = 1;
+		else if (e_rf_path == RF_PATH_C)
+			para.data.rf.path = 2;
+		else if (e_rf_path == RF_PATH_D)
+			para.data.rf.path = 3;
+		else
+			para.data.rf.path = 0;
+	break;
+	case PHYDM_HALMAC_CMD_DELAY_US:
+		para.cmd = 3; /* Delay */
+		para.data.delay.unit = 0; /* microsecond */
+		para.data.delay.value = delay_time;
+	break;
+	case PHYDM_HALMAC_CMD_DELAY_MS:
+		para.cmd = 3; /* Delay */
+		para.data.delay.unit = 1; /* millisecond */
+		para.data.delay.value = delay_time;
+	break;
+	case PHYDM_HALMAC_CMD_END:
+		para.cmd = 0xFF; /* End command */
+	break;
+	default:
+		return HAL_STATUS_FAILURE;
+	}
+
+	if (rtw_halmac_cfg_phy_para(adapter_to_dvobj(adapter), &para))
+		return HAL_STATUS_FAILURE;
+	#endif /*RTW_HALMAC*/
+	return HAL_STATUS_SUCCESS;
+}
+
+
+#ifdef CONFIG_LPS_LCLK_WD_TIMER
+void rtw_phydm_wd_lps_lclk_hdl(_adapter *adapter)
+{
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter);
+	struct dm_struct	*podmpriv = &(pHalData->odmpriv);
+	struct sta_priv *pstapriv = &adapter->stapriv;
+	struct sta_info *psta = NULL;
+	u8 rssi_min = 0;
+	u32	rssi_rpt = 0;
+	bool is_linked = _FALSE;
+
+	if (!rtw_is_hw_init_completed(adapter))
+		return;
+
+	if (rtw_mi_check_status(adapter, MI_ASSOC))
+		is_linked = _TRUE;
+
+	if (is_linked == _FALSE)
+		return;
+
+	psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+	if (psta == NULL)
+		return;
+
+	odm_cmn_info_update(&pHalData->odmpriv, ODM_CMNINFO_LINK, is_linked);
+
+	phydm_watchdog_lps_32k(&pHalData->odmpriv);
+}
+
+void rtw_phydm_watchdog_in_lps_lclk(_adapter *adapter)
+{
+	struct mlme_priv	*pmlmepriv = &adapter->mlmepriv;
+	struct sta_priv *pstapriv = &adapter->stapriv;
+	struct sta_info *psta = NULL;
+	u8 cur_igi = 0;
+	s8 min_rssi = 0;
+
+	if (!rtw_is_hw_init_completed(adapter))
+		return;
+
+	psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+	if (psta == NULL)
+		return;
+
+	cur_igi = rtw_phydm_get_cur_igi(adapter);
+	min_rssi = rtw_phydm_get_min_rssi(adapter);
+	if (min_rssi <= 0)
+		min_rssi = psta->cmn.rssi_stat.rssi;
+	/*RTW_INFO("%s "ADPT_FMT" cur_ig_value=%d, min_rssi = %d\n", __func__,  ADPT_ARG(adapter), cur_igi, min_rssi);*/
+
+	if (min_rssi <= 0)
+		return;
+
+	if ((cur_igi > min_rssi + 5) ||
+		(cur_igi < min_rssi - 5)) {
+#ifdef CONFIG_LPS
+		rtw_dm_in_lps_wk_cmd(adapter);
+#endif
+	}
+}
+#endif /*CONFIG_LPS_LCLK_WD_TIMER*/
+
+void dump_sta_traffic(void *sel, _adapter *adapter, struct sta_info *psta)
+{
+	struct ra_sta_info *ra_info;
+	u8 curr_sgi = _FALSE;
+	u32 tx_tp_mbips, rx_tp_mbips, bi_tp_mbips;
+
+	if (!psta)
+		return;
+	RTW_PRINT_SEL(sel, "\n");
+	RTW_PRINT_SEL(sel, "====== mac_id : %d [" MAC_FMT "] ======\n",
+		psta->cmn.mac_id, MAC_ARG(psta->cmn.mac_addr));
+
+	if (is_client_associated_to_ap(psta->padapter))
+		RTW_PRINT_SEL(sel, "BCN counts : %d (per-%d second), DTIM Period:%d\n",
+		rtw_get_bcn_cnt(psta->padapter) / 2, 1, adapter->mlmeextpriv.dtim);
+
+	ra_info = &psta->cmn.ra_info;
+	curr_sgi = rtw_get_current_tx_sgi(adapter, psta);
+	RTW_PRINT_SEL(sel, "tx_rate : %s(%s)  rx_rate : %s, rx_rate_bmc : %s, rssi : %d %%\n"
+		, HDATA_RATE(rtw_get_current_tx_rate(adapter, psta)), (curr_sgi) ? "S" : "L"
+		, HDATA_RATE((psta->curr_rx_rate & 0x7F)), HDATA_RATE((psta->curr_rx_rate_bmc & 0x7F)), psta->cmn.rssi_stat.rssi
+	);
+
+	if (0) {
+		RTW_PRINT_SEL(sel, "tx_bytes:%llu(%llu - %llu)\n"
+			, psta->sta_stats.tx_bytes - psta->sta_stats.last_tx_bytes
+			, psta->sta_stats.tx_bytes, psta->sta_stats.last_tx_bytes
+		);
+		RTW_PRINT_SEL(sel, "rx_uc_bytes:%llu(%llu - %llu)\n"
+			, sta_rx_uc_bytes(psta) - sta_last_rx_uc_bytes(psta)
+			, sta_rx_uc_bytes(psta), sta_last_rx_uc_bytes(psta)
+		);
+		RTW_PRINT_SEL(sel, "rx_mc_bytes:%llu(%llu - %llu)\n"
+			, psta->sta_stats.rx_mc_bytes - psta->sta_stats.last_rx_mc_bytes
+			, psta->sta_stats.rx_mc_bytes, psta->sta_stats.last_rx_mc_bytes
+		);
+		RTW_PRINT_SEL(sel, "rx_bc_bytes:%llu(%llu - %llu)\n"
+			, psta->sta_stats.rx_bc_bytes - psta->sta_stats.last_rx_bc_bytes
+			, psta->sta_stats.rx_bc_bytes, psta->sta_stats.last_rx_bc_bytes
+		);
+	}
+
+	_RTW_PRINT_SEL(sel, "RTW: [TP] ");
+	tx_tp_mbips = psta->sta_stats.tx_tp_kbits >> 10;
+	rx_tp_mbips = psta->sta_stats.rx_tp_kbits >> 10;
+	bi_tp_mbips = tx_tp_mbips + rx_tp_mbips;
+
+	if (tx_tp_mbips)
+		_RTW_PRINT_SEL(sel, "Tx : %d(Mbps) ", tx_tp_mbips);
+	else
+		_RTW_PRINT_SEL(sel, "Tx : %d(Kbps) ", psta->sta_stats.tx_tp_kbits);
+
+	if (rx_tp_mbips) 
+		_RTW_PRINT_SEL(sel, "Rx : %d(Mbps) ", rx_tp_mbips);
+	else
+		_RTW_PRINT_SEL(sel, "Rx : %d(Kbps) ", psta->sta_stats.rx_tp_kbits);
+
+	if (bi_tp_mbips)
+		_RTW_PRINT_SEL(sel, "Total : %d(Mbps)\n", bi_tp_mbips);
+	else
+		_RTW_PRINT_SEL(sel, "Total : %d(Kbps)\n", psta->sta_stats.tx_tp_kbits + psta->sta_stats.rx_tp_kbits);
+
+
+	_RTW_PRINT_SEL(sel, "RTW: [Smooth TP] ");
+	tx_tp_mbips = psta->sta_stats.smooth_tx_tp_kbits >> 10;
+	rx_tp_mbips = psta->sta_stats.smooth_rx_tp_kbits >> 10;
+	bi_tp_mbips = tx_tp_mbips + rx_tp_mbips;
+	if (tx_tp_mbips)
+		_RTW_PRINT_SEL(sel, "Tx : %d(Mbps) ", tx_tp_mbips);
+	else
+		_RTW_PRINT_SEL(sel, "Tx : %d(Kbps) ", psta->sta_stats.smooth_tx_tp_kbits);
+
+	if (rx_tp_mbips) 
+		_RTW_PRINT_SEL(sel, "Rx : %d(Mbps) ", rx_tp_mbips);
+	else
+		_RTW_PRINT_SEL(sel, "Rx : %d(Kbps) ", psta->sta_stats.smooth_rx_tp_kbits);
+
+	if (bi_tp_mbips)
+		_RTW_PRINT_SEL(sel, "Total : %d(Mbps)\n", bi_tp_mbips);
+	else
+		_RTW_PRINT_SEL(sel, "Total : %d(Kbps)\n", psta->sta_stats.smooth_tx_tp_kbits + psta->sta_stats.rx_tp_kbits);
+
+	#if 0
+	RTW_PRINT_SEL(sel, "Moving-AVG TP {Tx,Rx,Total} = { %d , %d , %d } Mbps\n\n",
+		(psta->cmn.tx_moving_average_tp << 3), (psta->cmn.rx_moving_average_tp << 3),
+		(psta->cmn.tx_moving_average_tp + psta->cmn.rx_moving_average_tp) << 3);
+	#endif
+}
+
+void dump_sta_info(void *sel, struct sta_info *psta)
+{
+	struct ra_sta_info *ra_info;
+	u8 curr_tx_sgi = _FALSE;
+	u8 curr_tx_rate = 0;
+
+	if (!psta)
+		return;
+
+	ra_info = &psta->cmn.ra_info;
+
+	RTW_PRINT_SEL(sel, "============ STA [" MAC_FMT "]  ===================\n",
+		MAC_ARG(psta->cmn.mac_addr));
+	RTW_PRINT_SEL(sel, "mac_id : %d\n", psta->cmn.mac_id);
+	RTW_PRINT_SEL(sel, "wireless_mode : 0x%02x\n", psta->wireless_mode);
+	RTW_PRINT_SEL(sel, "mimo_type : %d\n", psta->cmn.mimo_type);
+	RTW_PRINT_SEL(sel, "bw_mode : %s, ra_bw_mode : %s\n",
+			ch_width_str(psta->cmn.bw_mode), ch_width_str(ra_info->ra_bw_mode));
+	RTW_PRINT_SEL(sel, "rate_id : %d\n", ra_info->rate_id);
+	RTW_PRINT_SEL(sel, "rssi : %d (%%), rssi_level : %d\n", psta->cmn.rssi_stat.rssi, ra_info->rssi_level);
+	RTW_PRINT_SEL(sel, "is_support_sgi : %s, is_vht_enable : %s\n",
+			(ra_info->is_support_sgi) ? "Y" : "N", (ra_info->is_vht_enable) ? "Y" : "N");
+	RTW_PRINT_SEL(sel, "disable_ra : %s, disable_pt : %s\n",
+				(ra_info->disable_ra) ? "Y" : "N", (ra_info->disable_pt) ? "Y" : "N");
+	RTW_PRINT_SEL(sel, "is_noisy : %s\n", (ra_info->is_noisy) ? "Y" : "N");
+	RTW_PRINT_SEL(sel, "txrx_state : %d\n", ra_info->txrx_state);/*0: uplink, 1:downlink, 2:bi-direction*/
+
+	curr_tx_sgi = rtw_get_current_tx_sgi(psta->padapter, psta);
+	curr_tx_rate = rtw_get_current_tx_rate(psta->padapter, psta);
+	RTW_PRINT_SEL(sel, "curr_tx_rate : %s (%s)\n",
+			HDATA_RATE(curr_tx_rate), (curr_tx_sgi) ? "S" : "L");
+	RTW_PRINT_SEL(sel, "curr_tx_bw : %s\n", ch_width_str(ra_info->curr_tx_bw));
+	RTW_PRINT_SEL(sel, "curr_retry_ratio : %d\n", ra_info->curr_retry_ratio);
+	RTW_PRINT_SEL(sel, "ra_mask : 0x%016llx\n\n", ra_info->ramask);
+}
+
+void rtw_phydm_ra_registed(_adapter *adapter, struct sta_info *psta)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+
+	if (psta == NULL) {
+		RTW_ERR(FUNC_ADPT_FMT" sta is NULL\n", FUNC_ADPT_ARG(adapter));
+		rtw_warn_on(1);
+		return;
+	}
+
+	phydm_ra_registed(&hal_data->odmpriv, psta->cmn.mac_id, psta->cmn.rssi_stat.rssi);
+	dump_sta_info(RTW_DBGDUMP, psta);
+}
+
+static void init_phydm_info(_adapter *adapter)
+{
+	PHAL_DATA_TYPE	hal_data = GET_HAL_DATA(adapter);
+	struct dm_struct *phydm = &(hal_data->odmpriv);
+
+	odm_cmn_info_init(phydm, ODM_CMNINFO_FW_VER, hal_data->firmware_version);
+	odm_cmn_info_init(phydm, ODM_CMNINFO_FW_SUB_VER, hal_data->firmware_sub_version);
+}
+void rtw_phydm_init(_adapter *adapter)
+{
+	PHAL_DATA_TYPE	hal_data = GET_HAL_DATA(adapter);
+	struct dm_struct	*phydm = &(hal_data->odmpriv);
+
+	init_phydm_info(adapter);
+	odm_dm_init(phydm);
+}
+
+#ifdef CONFIG_LPS_PG
+/*
+static void _lps_pg_state_update(_adapter *adapter)
+{
+	u8	is_in_lpspg = _FALSE;
+	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter);
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(adapter);
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct sta_priv *pstapriv = &adapter->stapriv;
+	struct sta_info *psta = NULL;
+
+	if ((pwrpriv->lps_level == LPS_PG) && (pwrpriv->pwr_mode != PS_MODE_ACTIVE) && (pwrpriv->rpwm <= PS_STATE_S2))
+		is_in_lpspg = _TRUE;
+	psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+
+	if (psta)
+		psta->cmn.ra_info.disable_ra = (is_in_lpspg) ? _TRUE : _FALSE;
+}
+*/
+void rtw_phydm_lps_pg_hdl(_adapter *adapter, struct sta_info *sta, bool in_lpspg)
+{
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+	/*u8 rate_id;*/
+
+	if(sta == NULL) {
+		RTW_ERR("%s sta is null\n", __func__);
+		rtw_warn_on(1);
+		return;
+	}
+
+	if (in_lpspg) {
+		sta->cmn.ra_info.disable_ra = _TRUE;
+		sta->cmn.ra_info.disable_pt = _TRUE;
+		/*TODO : DRV fix tx rate*/
+		/*rate_id = phydm_get_rate_from_rssi_lv(phydm, sta->cmn.mac_id);*/
+	} else {
+		sta->cmn.ra_info.disable_ra = _FALSE;
+		sta->cmn.ra_info.disable_pt = _FALSE;
+	}
+
+	rtw_phydm_ra_registed(adapter, sta);
+}
+#endif
+
+/*#define DBG_PHYDM_STATE_CHK*/
+
+
+static u8 _rtw_phydm_rfk_condition_check(_adapter *adapter, u8 is_scaning, u8 ifs_linked)
+{
+	u8 rfk_allowed = _TRUE;
+
+	#ifdef CONFIG_SKIP_RFK_IN_DM
+	rfk_allowed = _FALSE;
+	if (0)
+		RTW_ERR("[RFK-CHK] RF-K not allowed due to CONFIG_SKIP_RFK_IN_DM\n");
+	return rfk_allowed;
+	#endif
+
+	if (ifs_linked) {
+		if (is_scaning) {
+			rfk_allowed = _FALSE;
+			RTW_ERR("[RFK-CHK] RF-K not allowed due to ifaces under site-survey\n");
+		}
+		else {
+			rfk_allowed = rtw_mi_stayin_union_ch_chk(adapter) ? _TRUE : _FALSE;
+			if (rfk_allowed == _FALSE)
+				RTW_ERR("[RFK-CHK] RF-K not allowed due to ld_iface not stayin union ch\n");
+		}
+	}
+
+	#ifdef CONFIG_MCC_MODE
+	/*not in MCC State*/
+	if (MCC_EN(adapter)) {
+		if (rtw_hal_check_mcc_status(adapter, MCC_STATUS_DOING_MCC)) {
+			rfk_allowed = _FALSE;
+			if (0)
+				RTW_ERR("[RFK-CHK] RF-K not allowed due to doing MCC\n");
+		}
+	}
+	#endif
+
+	#if defined(CONFIG_TDLS) && defined(CONFIG_TDLS_CH_SW)
+
+	#endif
+
+	return rfk_allowed;
+}
+#if ((RTL8822B_SUPPORT == 1) || (RTL8821C_SUPPORT == 1) || (RTL8814B_SUPPORT == 1))
+static u8 _rtw_phydm_iqk_segment_chk(_adapter *adapter, u8 ifs_linked)
+{
+	u8 iqk_sgt = _FALSE;
+
+#if 0
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	if (is_linked && (dvobj->traffic_stat.cur_tx_tp > 2 || dvobj->traffic_stat.cur_rx_tp > 2))
+		rst = _TRUE;
+#else
+	if (ifs_linked)
+		iqk_sgt = _TRUE;
+#endif
+	return iqk_sgt;
+}
+#endif
+
+/*check the tx low rate while unlinked to any AP;for pwr tracking */
+static u8 _rtw_phydm_pwr_tracking_rate_check(_adapter *adapter)
+{
+	int i;
+	_adapter *iface;
+	u8		if_tx_rate = 0xFF;
+	u8		tx_rate = 0xFF;
+	struct mlme_ext_priv	*pmlmeext = NULL;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		pmlmeext = &(iface->mlmeextpriv);
+		if ((iface) && rtw_is_adapter_up(iface)) {
+#ifdef CONFIG_P2P
+			if (!rtw_p2p_chk_role(&(iface)->wdinfo, P2P_ROLE_DISABLE))
+				if_tx_rate = IEEE80211_OFDM_RATE_6MB;
+			else
+#endif
+				if_tx_rate = pmlmeext->tx_rate;
+			if(if_tx_rate < tx_rate)
+				tx_rate = if_tx_rate;
+
+			RTW_DBG("%s i=%d tx_rate =0x%x\n", __func__, i, if_tx_rate);
+		}
+	}
+	RTW_DBG("%s tx_low_rate (unlinked to any AP)=0x%x\n", __func__, tx_rate);
+	return tx_rate;
+}
+
+#ifdef CONFIG_DYNAMIC_SOML
+void rtw_dyn_soml_byte_update(_adapter *adapter, u8 data_rate, u32 size)
+{
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+
+	phydm_soml_bytes_acq(phydm, data_rate, size);
+}
+
+void rtw_dyn_soml_para_set(_adapter *adapter, u8 train_num, u8 intvl,
+			u8 period, u8 delay)
+{
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+
+	phydm_adaptive_soml_para_set(phydm, train_num, intvl, period, delay);
+	RTW_INFO("%s.\n", __func__);
+}
+
+void rtw_dyn_soml_config(_adapter *adapter)
+{
+	RTW_INFO("%s.\n", __func__);
+
+	if (adapter->registrypriv.dyn_soml_en == 1) {
+		/* Must after phydm_adaptive_soml_init() */
+		rtw_hal_set_hwreg(adapter , HW_VAR_SET_SOML_PARAM , NULL);
+		RTW_INFO("dyn_soml_en = 1\n");
+	} else {
+		if (adapter->registrypriv.dyn_soml_en == 2) {
+			rtw_dyn_soml_para_set(adapter, 
+				adapter->registrypriv.dyn_soml_train_num, 
+				adapter->registrypriv.dyn_soml_interval, 
+				adapter->registrypriv.dyn_soml_period,
+				adapter->registrypriv.dyn_soml_delay);
+			RTW_INFO("dyn_soml_en = 2\n");
+			RTW_INFO("dyn_soml_en, param = %d, %d, %d, %d\n",
+				adapter->registrypriv.dyn_soml_train_num,
+				adapter->registrypriv.dyn_soml_interval, 
+				adapter->registrypriv.dyn_soml_period,
+				adapter->registrypriv.dyn_soml_delay);
+		} else if (adapter->registrypriv.dyn_soml_en == 0) {
+			RTW_INFO("dyn_soml_en = 0\n");
+		} else
+			RTW_ERR("%s, wrong setting: dyn_soml_en = %d\n", __func__,
+				adapter->registrypriv.dyn_soml_en);
+	}
+}
+#endif
+
+
+void rtw_phydm_read_efuse(_adapter *adapter)
+{
+	PHAL_DATA_TYPE hal_data = GET_HAL_DATA(adapter);
+	struct dm_struct *phydm = &(hal_data->odmpriv);
+
+	/*PHYDM API - thermal trim*/
+	phydm_get_thermal_trim_offset(phydm);
+	/*PHYDM API - power trim*/
+	phydm_get_power_trim_offset(phydm);
+}
+
+void rtw_phydm_watchdog(_adapter *adapter)
+{
+	u8	bLinked = _FALSE;
+	u8	bsta_state = _FALSE;
+	u8	bBtDisabled = _TRUE;
+	u8	rfk_forbidden = _FALSE;
+	#if ((RTL8822B_SUPPORT == 1) || (RTL8821C_SUPPORT == 1) || (RTL8814B_SUPPORT == 1))
+	u8	segment_iqk = _FALSE;
+	#endif
+	u8	tx_unlinked_low_rate = 0xFF;
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(adapter);
+	struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter);
+
+	if (!rtw_is_hw_init_completed(adapter)) {
+		RTW_DBG("%s skip due to hw_init_completed == FALSE\n", __func__);
+		return;
+	}
+	if (rtw_mi_check_fwstate(adapter, _FW_UNDER_SURVEY))
+		pHalData->bScanInProcess = _TRUE;
+	else
+		pHalData->bScanInProcess = _FALSE;
+
+	if (rtw_mi_check_status(adapter, MI_ASSOC)) {
+		bLinked = _TRUE;
+		if (rtw_mi_check_status(adapter, MI_STA_LINKED))
+		bsta_state = _TRUE;
+	}
+
+	odm_cmn_info_update(&pHalData->odmpriv, ODM_CMNINFO_LINK, bLinked);
+	odm_cmn_info_update(&pHalData->odmpriv, ODM_CMNINFO_STATION_STATE, bsta_state);
+
+	#ifdef CONFIG_BT_COEXIST
+	bBtDisabled = rtw_btcoex_IsBtDisabled(adapter);
+	#endif /* CONFIG_BT_COEXIST */
+	odm_cmn_info_update(&pHalData->odmpriv, ODM_CMNINFO_BT_ENABLED,
+							(bBtDisabled == _TRUE) ? _FALSE : _TRUE);
+
+	rfk_forbidden = (_rtw_phydm_rfk_condition_check(adapter, pHalData->bScanInProcess, bLinked) == _TRUE) ? _FALSE : _TRUE;
+	halrf_cmn_info_set(&pHalData->odmpriv, HALRF_CMNINFO_RFK_FORBIDDEN, rfk_forbidden);
+
+	#if ((RTL8822B_SUPPORT == 1) || (RTL8821C_SUPPORT == 1) || (RTL8814B_SUPPORT == 1))
+	segment_iqk = _rtw_phydm_iqk_segment_chk(adapter, bLinked);
+	halrf_cmn_info_set(&pHalData->odmpriv, HALRF_CMNINFO_IQK_SEGMENT, segment_iqk);
+	#endif
+	#ifdef DBG_PHYDM_STATE_CHK
+	RTW_INFO("%s rfk_forbidden = %s, segment_iqk = %s\n",
+			__func__, (rfk_forbidden) ? "Y" : "N", (segment_iqk) ? "Y" : "N");
+	#endif
+
+	if (bLinked == _FALSE) {
+		tx_unlinked_low_rate = _rtw_phydm_pwr_tracking_rate_check(adapter);
+		halrf_cmn_info_set(&pHalData->odmpriv, HALRF_CMNINFO_RATE_INDEX, tx_unlinked_low_rate);
+	}
+
+	/*if (!rtw_mi_stayin_union_band_chk(adapter)) {
+		#ifdef DBG_PHYDM_STATE_CHK
+		RTW_ERR("Not stay in union band, skip phydm\n");
+		#endif
+		goto _exit;
+	}*/
+	if (pwrctl->bpower_saving)
+		phydm_watchdog_lps(&pHalData->odmpriv);
+	else
+		phydm_watchdog(&pHalData->odmpriv);
+
+	#ifdef CONFIG_RTW_ACS
+	rtw_acs_update_current_info(adapter);
+	#endif
+
+_exit:
+	return;
+}
 

+ 81 - 7
hal/hal_dm.h

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,16 +11,90 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #ifndef __HAL_DM_H__
 #define __HAL_DM_H__
 
+#define adapter_to_phydm(adapter) (&(GET_HAL_DATA(adapter)->odmpriv))
+#define dvobj_to_phydm(dvobj) adapter_to_phydm(dvobj_get_primary_adapter(dvobj))
+
+void rtw_phydm_priv_init(_adapter *adapter);
 void Init_ODM_ComInfo(_adapter *adapter);
+void rtw_phydm_init(_adapter *adapter);
+
 void rtw_hal_turbo_edca(_adapter *adapter);
+u8 rtw_phydm_is_iqk_in_progress(_adapter *adapter);
+
+void GetHalODMVar(
+	PADAPTER				Adapter,
+	HAL_ODM_VARIABLE		eVariable,
+	PVOID					pValue1,
+	PVOID					pValue2);
+void SetHalODMVar(
+	PADAPTER				Adapter,
+	HAL_ODM_VARIABLE		eVariable,
+	PVOID					pValue1,
+	BOOLEAN					bSet);
+
+void rtw_phydm_ra_registed(_adapter *adapter, struct sta_info *psta);
+
+#ifdef CONFIG_DYNAMIC_SOML
+void rtw_dyn_soml_byte_update(_adapter *adapter, u8 data_rate, u32 size);
+void rtw_dyn_soml_para_set(_adapter *adapter, u8 train_num, u8 intvl,
+			u8 period, u8 delay);
+void rtw_dyn_soml_config(_adapter *adapter);
+#endif
+void rtw_phydm_watchdog(_adapter *adapter);
+
+void rtw_hal_update_iqk_fw_offload_cap(_adapter *adapter);
+void dump_sta_info(void *sel, struct sta_info *psta);
+void dump_sta_traffic(void *sel, _adapter *adapter, struct sta_info *psta);
+
+#ifdef CONFIG_DBG_RF_CAL
+void rtw_hal_iqk_test(_adapter *adapter, bool recovery, bool clear, bool segment);
+void rtw_hal_lck_test(_adapter *adapter);
+#endif
+
+s8 rtw_phydm_get_min_rssi(_adapter *adapter);
+u8 rtw_phydm_get_cur_igi(_adapter *adapter);
+
+
+#ifdef CONFIG_LPS_LCLK_WD_TIMER
+extern void phydm_rssi_monitor_check(void *p_dm_void);
+
+void rtw_phydm_wd_lps_lclk_hdl(_adapter *adapter);
+void rtw_phydm_watchdog_in_lps_lclk(_adapter *adapter);
+#endif
+
+enum phy_cnt {
+	FA_OFDM,
+	FA_CCK,
+	FA_TOTAL,
+	CCA_OFDM,
+	CCA_CCK,
+	CCA_ALL,
+	CRC32_OK_VHT,
+	CRC32_OK_HT,
+	CRC32_OK_LEGACY,
+	CRC32_OK_CCK,
+	CRC32_ERROR_VHT,
+	CRC32_ERROR_HT,
+	CRC32_ERROR_LEGACY,
+	CRC32_ERROR_CCK,
+};
+u32 rtw_phydm_get_phy_cnt(_adapter *adapter, enum phy_cnt cnt);
+#if ((RTL8822B_SUPPORT == 1) || (RTL8821C_SUPPORT == 1) || (RTL8814B_SUPPORT == 1))
+void rtw_phydm_iqk_trigger(_adapter *adapter);
+#endif
+void rtw_phydm_read_efuse(_adapter *adapter);
 
+#ifdef CONFIG_SUPPORT_DYNAMIC_TXPWR
+void rtw_phydm_set_dyntxpwr(_adapter *adapter, u8 *desc, u8 mac_id);
+#endif
+#ifdef CONFIG_RTW_TX_2PATH_EN
+void rtw_phydm_tx_2path_en(_adapter *adapter);
+#endif
+#ifdef CONFIG_LPS_PG
+void rtw_phydm_lps_pg_hdl(_adapter *adapter, struct sta_info *sta, bool in_lpspg);
+#endif
 #endif /* __HAL_DM_H__ */

+ 554 - 0
hal/hal_dm_acs.c

@@ -0,0 +1,554 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2014 - 2017 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.
+ *
+ *****************************************************************************/
+#include <drv_types.h>
+#include <hal_data.h>
+
+
+#if defined(CONFIG_RTW_ACS) || defined(CONFIG_BACKGROUND_NOISE_MONITOR)
+static void _rtw_bss_nums_count(_adapter *adapter, u8 *pbss_nums)
+{
+	struct mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+	_queue *queue = &(pmlmepriv->scanned_queue);
+	struct wlan_network *pnetwork = NULL;
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+
+	_list	*plist, *phead;
+	_irqL irqL;
+	int chan_idx = -1;
+
+	if (pbss_nums == NULL) {
+		RTW_ERR("%s pbss_nums is null pointer\n", __func__);
+		return;
+	}
+	_rtw_memset(pbss_nums, 0, MAX_CHANNEL_NUM);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		if (!pnetwork)
+			break;
+		chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), pnetwork->network.Configuration.DSConfig);
+		if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) {
+			RTW_ERR("%s can't get chan_idx(CH:%d)\n",
+				__func__, pnetwork->network.Configuration.DSConfig);
+			chan_idx = 0;
+		}
+		/*if (pnetwork->network.Reserved[0] != BSS_TYPE_PROB_REQ)*/
+
+		pbss_nums[chan_idx]++;
+
+		plist = get_next(plist);
+	}
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+}
+
+u8 rtw_get_ch_num_by_idx(_adapter *adapter, u8 idx)
+{
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	RT_CHANNEL_INFO *pch_set = rfctl->channel_set;
+	u8 max_chan_nums = rfctl->max_chan_nums;
+
+	if (idx >= max_chan_nums)
+		return 0;
+	return pch_set[idx].ChannelNum;
+}
+#endif /*defined(CONFIG_RTW_ACS) || defined(CONFIG_BACKGROUND_NOISE_MONITOR)*/
+
+
+#ifdef CONFIG_RTW_ACS
+void rtw_acs_version_dump(void *sel, _adapter *adapter)
+{
+	_RTW_PRINT_SEL(sel, "RTK_ACS VER_%d\n", RTK_ACS_VERSION);
+}
+u8 rtw_phydm_clm_ratio(_adapter *adapter)
+{
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+
+	return phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_CLM_RATIO);
+}
+u8 rtw_phydm_nhm_ratio(_adapter *adapter)
+{
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+
+	return phydm_cmn_info_query(phydm, (enum phydm_info_query) PHYDM_INFO_NHM_RATIO);
+}
+void rtw_acs_reset(_adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct auto_chan_sel *pacs = &hal_data->acs;
+
+	_rtw_memset(pacs, 0, sizeof(struct auto_chan_sel));
+	#ifdef CONFIG_RTW_ACS_DBG
+	rtw_acs_adv_reset(adapter);
+	#endif /*CONFIG_RTW_ACS_DBG*/
+}
+
+#ifdef CONFIG_RTW_ACS_DBG
+u8 rtw_is_acs_igi_valid(_adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct auto_chan_sel *pacs = &hal_data->acs;
+
+	if ((pacs->igi) && ((pacs->igi >= 0x1E) || (pacs->igi < 0x60)))
+		return _TRUE;
+
+	return _FALSE;
+}
+void rtw_acs_adv_setting(_adapter *adapter, RT_SCAN_TYPE scan_type, u16 scan_time, u8 igi, u8 bw)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct auto_chan_sel *pacs = &hal_data->acs;
+	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+	pacs->scan_type = scan_type;
+	pacs->scan_time = scan_time;
+	pacs->igi = igi;
+	pacs->bw = bw;
+	RTW_INFO("[ACS] ADV setting - scan_type:%c, ch_ms:%d(ms), igi:0x%02x, bw:%d\n",
+		pacs->scan_type ? 'A' : 'P', pacs->scan_time, pacs->igi, pacs->bw);
+}
+void rtw_acs_adv_reset(_adapter *adapter)
+{
+	rtw_acs_adv_setting(adapter, SCAN_ACTIVE, 0, 0, 0);
+}
+#endif /*CONFIG_RTW_ACS_DBG*/
+
+void rtw_acs_trigger(_adapter *adapter, u16 scan_time_ms, u8 scan_chan, enum NHM_PID pid)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+#if (RTK_ACS_VERSION == 3)
+	struct clm_para_info clm_para;
+	struct nhm_para_info nhm_para;
+	struct env_trig_rpt trig_rpt;
+
+	scan_time_ms -= 10;
+
+	init_acs_clm(clm_para, scan_time_ms);
+
+	if (pid == NHM_PID_IEEE_11K_HIGH)
+		init_11K_high_nhm(nhm_para, scan_time_ms);
+	else if (pid == NHM_PID_IEEE_11K_LOW)
+		init_11K_low_nhm(nhm_para, scan_time_ms);
+	else
+		init_acs_nhm(nhm_para, scan_time_ms);
+
+	hal_data->acs.trig_rst = phydm_env_mntr_trigger(phydm, &nhm_para, &clm_para, &trig_rpt);
+	if (hal_data->acs.trig_rst == (NHM_SUCCESS | CLM_SUCCESS)) {
+		hal_data->acs.trig_rpt.clm_rpt_stamp = trig_rpt.clm_rpt_stamp;
+		hal_data->acs.trig_rpt.nhm_rpt_stamp = trig_rpt.nhm_rpt_stamp;
+		/*RTW_INFO("[ACS] trigger success (rst = 0x%02x, clm_stamp:%d, nhm_stamp:%d)\n",
+			hal_data->acs.trig_rst, hal_data->acs.trig_rpt.clm_rpt_stamp, hal_data->acs.trig_rpt.nhm_rpt_stamp);*/
+	} else
+		RTW_ERR("[ACS] trigger failed (rst = 0x%02x)\n", hal_data->acs.trig_rst);
+#else
+	phydm_ccx_monitor_trigger(phydm, scan_time_ms);
+#endif
+
+	hal_data->acs.trigger_ch = scan_chan;
+	hal_data->acs.triggered = _TRUE;
+
+	#ifdef CONFIG_RTW_ACS_DBG
+	RTW_INFO("[ACS] Trigger CH:%d, Times:%d\n", hal_data->acs.trigger_ch, scan_time_ms);
+	#endif
+}
+void rtw_acs_get_rst(_adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct dm_struct *phydm = adapter_to_phydm(adapter);
+	int chan_idx = -1;
+	u8 cur_chan = hal_data->acs.trigger_ch;
+
+	if (cur_chan == 0)
+		return;
+
+	if (!hal_data->acs.triggered)
+		return;
+
+	chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), cur_chan);
+	if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) {
+		RTW_ERR("[ACS] %s can't get chan_idx(CH:%d)\n", __func__, cur_chan);
+		return;
+	}
+#if (RTK_ACS_VERSION == 3)
+	if (!(hal_data->acs.trig_rst == (NHM_SUCCESS | CLM_SUCCESS))) {
+		RTW_ERR("[ACS] get_rst return, due to acs trigger failed\n");
+		return;
+	}
+
+	{
+		struct env_mntr_rpt rpt = {0};
+		u8 rst;
+
+		rst = phydm_env_mntr_result(phydm, &rpt);
+		if ((rst == (NHM_SUCCESS | CLM_SUCCESS)) &&
+			(rpt.clm_rpt_stamp == hal_data->acs.trig_rpt.clm_rpt_stamp) &&
+			(rpt.nhm_rpt_stamp == hal_data->acs.trig_rpt.nhm_rpt_stamp)){
+			hal_data->acs.clm_ratio[chan_idx] = rpt.clm_ratio;
+			hal_data->acs.nhm_ratio[chan_idx] = rpt.nhm_ratio;
+			_rtw_memcpy(&hal_data->acs.nhm[chan_idx][0], rpt.nhm_result, NHM_RPT_NUM);
+
+			/*RTW_INFO("[ACS] get_rst success (rst = 0x%02x, clm_stamp:%d:%d, nhm_stamp:%d:%d)\n",
+			rst,
+			hal_data->acs.trig_rpt.clm_rpt_stamp, rpt.clm_rpt_stamp,
+			hal_data->acs.trig_rpt.nhm_rpt_stamp, rpt.nhm_rpt_stamp);*/
+		} else {
+			RTW_ERR("[ACS] get_rst failed (rst = 0x%02x, clm_stamp:%d:%d, nhm_stamp:%d:%d)\n",
+			rst,
+			hal_data->acs.trig_rpt.clm_rpt_stamp, rpt.clm_rpt_stamp,
+			hal_data->acs.trig_rpt.nhm_rpt_stamp, rpt.nhm_rpt_stamp);
+		}
+	}
+
+#else
+	phydm_ccx_monitor_result(phydm);
+
+	hal_data->acs.clm_ratio[chan_idx] = rtw_phydm_clm_ratio(adapter);
+	hal_data->acs.nhm_ratio[chan_idx] = rtw_phydm_nhm_ratio(adapter);
+#endif
+	hal_data->acs.triggered = _FALSE;
+	#ifdef CONFIG_RTW_ACS_DBG
+	RTW_INFO("[ACS] Result CH:%d, CLM:%d NHM:%d\n",
+		cur_chan, hal_data->acs.clm_ratio[chan_idx], hal_data->acs.nhm_ratio[chan_idx]);
+	#endif
+}
+
+void _rtw_phydm_acs_select_best_chan(_adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	u8 ch_idx;
+	u8 ch_idx_24g = 0xFF, ch_idx_5g = 0xFF;
+	u8 min_itf_24g = 0xFF,  min_itf_5g = 0xFF;
+	u8 *pbss_nums = hal_data->acs.bss_nums;
+	u8 *pclm_ratio = hal_data->acs.clm_ratio;
+	u8 *pnhm_ratio = hal_data->acs.nhm_ratio;
+	u8 *pinterference_time = hal_data->acs.interference_time;
+	u8 max_chan_nums = rfctl->max_chan_nums;
+
+	for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) {
+		if (pbss_nums[ch_idx])
+			pinterference_time[ch_idx] = (pclm_ratio[ch_idx] / 2) + pnhm_ratio[ch_idx];
+		else
+			pinterference_time[ch_idx] = pclm_ratio[ch_idx] + pnhm_ratio[ch_idx];
+
+		if (rtw_get_ch_num_by_idx(adapter, ch_idx) < 14) {
+			if (pinterference_time[ch_idx] < min_itf_24g) {
+				min_itf_24g = pinterference_time[ch_idx];
+				ch_idx_24g = ch_idx;
+			}
+		} else {
+			if (pinterference_time[ch_idx] < min_itf_5g) {
+				min_itf_5g = pinterference_time[ch_idx];
+				ch_idx_5g = ch_idx;
+			}
+		}
+	}
+	if (ch_idx_24g != 0xFF)
+		hal_data->acs.best_chan_24g = rtw_get_ch_num_by_idx(adapter, ch_idx_24g);
+
+	if (ch_idx_5g != 0xFF)
+		hal_data->acs.best_chan_5g = rtw_get_ch_num_by_idx(adapter, ch_idx_5g);
+
+	hal_data->acs.trigger_ch = 0;
+}
+
+void rtw_acs_info_dump(void *sel, _adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	u8 max_chan_nums = rfctl->max_chan_nums;
+	u8 ch_idx, ch_num;
+
+	_RTW_PRINT_SEL(sel, "========== ACS (VER-%d) ==========\n", RTK_ACS_VERSION);
+	_RTW_PRINT_SEL(sel, "Best 24G Channel:%d\n", hal_data->acs.best_chan_24g);
+	_RTW_PRINT_SEL(sel, "Best 5G Channel:%d\n\n", hal_data->acs.best_chan_5g);
+
+	#ifdef CONFIG_RTW_ACS_DBG
+	_RTW_PRINT_SEL(sel, "Advanced setting - scan_type:%c, ch_ms:%d(ms), igi:0x%02x, bw:%d\n",
+		hal_data->acs.scan_type ? 'A' : 'P', hal_data->acs.scan_time, hal_data->acs.igi, hal_data->acs.bw);
+
+	_RTW_PRINT_SEL(sel, "BW  20MHz\n");
+	_RTW_PRINT_SEL(sel, "%5s  %3s  %3s  %3s(%%)  %3s(%%)  %3s\n",
+						"Index", "CH", "BSS", "CLM", "NHM", "ITF");
+
+	for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) {
+		ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx);
+		_RTW_PRINT_SEL(sel, "%5d  %3d  %3d  %6d  %6d  %3d\n",
+						ch_idx, ch_num, hal_data->acs.bss_nums[ch_idx],
+						hal_data->acs.clm_ratio[ch_idx],
+						hal_data->acs.nhm_ratio[ch_idx],
+						hal_data->acs.interference_time[ch_idx]);
+	}
+	#endif
+}
+void rtw_acs_select_best_chan(_adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+
+	_rtw_bss_nums_count(adapter, hal_data->acs.bss_nums);
+	_rtw_phydm_acs_select_best_chan(adapter);
+	rtw_acs_info_dump(RTW_DBGDUMP, adapter);
+}
+
+void rtw_acs_start(_adapter *adapter)
+{
+	rtw_acs_reset(adapter);
+	if (GET_ACS_STATE(adapter) != ACS_ENABLE)
+		SET_ACS_STATE(adapter, ACS_ENABLE);
+}
+void rtw_acs_stop(_adapter *adapter)
+{
+	SET_ACS_STATE(adapter, ACS_DISABLE);
+}
+
+
+u8 rtw_acs_get_clm_ratio_by_ch_num(_adapter *adapter, u8 chan)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	int chan_idx = -1;
+
+	chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan);
+	if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) {
+		RTW_ERR("[ACS] Get CLM fail, can't get chan_idx(CH:%d)\n", chan);
+		return 0;
+	}
+
+	return hal_data->acs.clm_ratio[chan_idx];
+}
+u8 rtw_acs_get_clm_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+
+	if (ch_idx >= MAX_CHANNEL_NUM) {
+		RTW_ERR("%s [ACS] ch_idx(%d) is invalid\n", __func__, ch_idx);
+		return 0;
+	}
+
+	return hal_data->acs.clm_ratio[ch_idx];
+}
+u8 rtw_acs_get_nhm_ratio_by_ch_num(_adapter *adapter, u8 chan)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	int chan_idx = -1;
+
+	chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan);
+	if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) {
+		RTW_ERR("[ACS] Get NHM fail, can't get chan_idx(CH:%d)\n", chan);
+		return 0;
+	}
+
+	return hal_data->acs.nhm_ratio[chan_idx];
+}
+u8 rtw_acs_get_num_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+
+	if (ch_idx >= MAX_CHANNEL_NUM) {
+		RTW_ERR("%s [ACS] ch_idx(%d) is invalid\n", __func__, ch_idx);
+		return 0;
+	}
+
+	return hal_data->acs.nhm_ratio[ch_idx];
+}
+void rtw_acs_chan_info_dump(void *sel, _adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	u8 max_chan_nums = rfctl->max_chan_nums;
+	u8 ch_idx, ch_num;
+	u8 utilization;
+
+	_RTW_PRINT_SEL(sel, "BW  20MHz\n");
+	_RTW_PRINT_SEL(sel, "%5s  %3s  %7s(%%)  %12s(%%)  %11s(%%)  %9s(%%)  %8s(%%)\n",
+						"Index", "CH", "Quality", "Availability", "Utilization",
+						"WIFI Util", "Interference Util");
+
+	for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) {
+		ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx);
+		utilization = hal_data->acs.clm_ratio[ch_idx] + hal_data->acs.nhm_ratio[ch_idx];
+		_RTW_PRINT_SEL(sel, "%5d  %3d  %7d   %12d   %12d   %12d   %12d\n",
+						ch_idx, ch_num,
+						(100-hal_data->acs.interference_time[ch_idx]),
+						(100-utilization),
+						utilization,
+						hal_data->acs.clm_ratio[ch_idx],
+						hal_data->acs.nhm_ratio[ch_idx]);
+	}
+}
+void rtw_acs_current_info_dump(void *sel, _adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	u8 ch, cen_ch, bw, offset;
+
+	_RTW_PRINT_SEL(sel, "========== ACS (VER-%d) ==========\n", RTK_ACS_VERSION);
+
+	ch = rtw_get_oper_ch(adapter);
+	bw = rtw_get_oper_bw(adapter);
+	offset = rtw_get_oper_choffset(adapter);
+
+	_RTW_PRINT_SEL(sel, "Current Channel:%d\n", ch);
+	if ((bw == CHANNEL_WIDTH_80) ||(bw == CHANNEL_WIDTH_40)) {
+		cen_ch = rtw_get_center_ch(ch, bw, offset);
+		_RTW_PRINT_SEL(sel, "Center Channel:%d\n", cen_ch);
+	}
+
+	_RTW_PRINT_SEL(sel, "Current BW %s\n", ch_width_str(bw));
+	if (0)
+		_RTW_PRINT_SEL(sel, "Current IGI 0x%02x\n", rtw_phydm_get_cur_igi(adapter));
+	_RTW_PRINT_SEL(sel, "CLM:%d, NHM:%d\n\n",
+		hal_data->acs.cur_ch_clm_ratio, hal_data->acs.cur_ch_nhm_ratio);
+}
+
+void rtw_acs_update_current_info(_adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+
+	hal_data->acs.cur_ch_clm_ratio = rtw_phydm_clm_ratio(adapter);
+	hal_data->acs.cur_ch_nhm_ratio = rtw_phydm_nhm_ratio(adapter);
+
+	#ifdef CONFIG_RTW_ACS_DBG
+	rtw_acs_current_info_dump(RTW_DBGDUMP, adapter);
+	#endif
+}
+#endif /*CONFIG_RTW_ACS*/
+
+#ifdef CONFIG_BACKGROUND_NOISE_MONITOR
+void rtw_noise_monitor_version_dump(void *sel, _adapter *adapter)
+{
+	_RTW_PRINT_SEL(sel, "RTK_NOISE_MONITOR VER_%d\n", RTK_NOISE_MONITOR_VERSION);
+}
+void rtw_nm_enable(_adapter *adapter)
+{
+	SET_NM_STATE(adapter, NM_ENABLE);
+}
+void rtw_nm_disable(_adapter *adapter)
+{
+	SET_NM_STATE(adapter, NM_DISABLE);
+}
+void rtw_noise_info_dump(void *sel, _adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	u8 max_chan_nums = rfctl->max_chan_nums;
+	u8 ch_idx, ch_num;
+
+	_RTW_PRINT_SEL(sel, "========== NM (VER-%d) ==========\n", RTK_NOISE_MONITOR_VERSION);
+
+	_RTW_PRINT_SEL(sel, "%5s  %3s  %3s  %10s", "Index", "CH", "BSS", "Noise(dBm)\n");
+
+	_rtw_bss_nums_count(adapter, hal_data->nm.bss_nums);
+
+	for (ch_idx = 0; ch_idx < max_chan_nums; ch_idx++) {
+		ch_num = rtw_get_ch_num_by_idx(adapter, ch_idx);
+		_RTW_PRINT_SEL(sel, "%5d  %3d  %3d  %10d\n",
+						ch_idx, ch_num, hal_data->nm.bss_nums[ch_idx],
+						hal_data->nm.noise[ch_idx]);
+	}
+}
+
+void rtw_noise_measure(_adapter *adapter, u8 chan, u8 is_pause_dig, u8 igi_value, u32 max_time)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct dm_struct *phydm = &hal_data->odmpriv;
+	int chan_idx = -1;
+	s16 noise = 0;
+
+	#ifdef DBG_NOISE_MONITOR
+	RTW_INFO("[NM] chan(%d)-PauseDIG:%s,  IGIValue:0x%02x, max_time:%d (ms)\n",
+		chan, (is_pause_dig) ? "Y" : "N", igi_value, max_time);
+	#endif
+
+	chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan);
+	if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) {
+		RTW_ERR("[NM] Get noise fail, can't get chan_idx(CH:%d)\n", chan);
+		return;
+	}
+	noise = odm_inband_noise_monitor(phydm, is_pause_dig, igi_value, max_time); /*dBm*/
+
+	hal_data->nm.noise[chan_idx] = noise;
+
+	#ifdef DBG_NOISE_MONITOR
+	RTW_INFO("[NM] %s chan_%d, noise = %d (dBm)\n", __func__, chan, hal_data->nm.noise[chan_idx]);
+
+	RTW_INFO("[NM] noise_a = %d, noise_b = %d  noise_all:%d\n",
+			 phydm->noise_level.noise[RF_PATH_A],
+			 phydm->noise_level.noise[RF_PATH_B],
+			 phydm->noise_level.noise_all);
+	#endif /*DBG_NOISE_MONITOR*/
+}
+
+s16 rtw_noise_query_by_chan_num(_adapter *adapter, u8 chan)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	s16 noise = 0;
+	int chan_idx = -1;
+
+	chan_idx = rtw_chset_search_ch(adapter_to_chset(adapter), chan);
+	if ((chan_idx == -1) || (chan_idx >= MAX_CHANNEL_NUM)) {
+		RTW_ERR("[NM] Get noise fail, can't get chan_idx(CH:%d)\n", chan);
+		return noise;
+	}
+	noise = hal_data->nm.noise[chan_idx];
+
+	#ifdef DBG_NOISE_MONITOR
+	RTW_INFO("[NM] %s chan_%d, noise = %d (dBm)\n", __func__, chan, noise);
+	#endif/*DBG_NOISE_MONITOR*/
+	return noise;
+}
+s16 rtw_noise_query_by_chan_idx(_adapter *adapter, u8 ch_idx)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	s16 noise = 0;
+
+	if (ch_idx >= MAX_CHANNEL_NUM) {
+		RTW_ERR("[NM] %s ch_idx(%d) is invalid\n", __func__, ch_idx);
+		return noise;
+	}
+	noise = hal_data->nm.noise[ch_idx];
+
+	#ifdef DBG_NOISE_MONITOR
+	RTW_INFO("[NM] %s ch_idx %d, noise = %d (dBm)\n", __func__, ch_idx, noise);
+	#endif/*DBG_NOISE_MONITOR*/
+	return noise;
+}
+
+s16 rtw_noise_measure_curchan(_adapter *padapter)
+{
+	s16 noise = 0;
+	u8 igi_value = 0x1E;
+	u32 max_time = 100;/* ms */
+	u8 is_pause_dig = _TRUE;
+	u8 cur_chan = rtw_get_oper_ch(padapter);
+
+	if (rtw_linked_check(padapter) == _FALSE)
+		return noise;
+
+	rtw_ps_deny(padapter, PS_DENY_IOCTL);
+	LeaveAllPowerSaveModeDirect(padapter);
+	rtw_noise_measure(padapter, cur_chan, is_pause_dig, igi_value, max_time);
+	noise = rtw_noise_query_by_chan_num(padapter, cur_chan);
+	rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL);
+
+	return noise;
+}
+#endif /*CONFIG_BACKGROUND_NOISE_MONITOR*/
+

+ 167 - 0
hal/hal_dm_acs.h

@@ -0,0 +1,167 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 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.
+ *
+ *****************************************************************************/
+#ifndef __HAL_DM_ACS_H__
+#define __HAL_DM_ACS_H__
+#ifdef CONFIG_RTW_ACS
+#define RTK_ACS_VERSION	3
+
+#if (RTK_ACS_VERSION == 3)
+enum NHM_PID {
+	NHM_PID_ACS,
+	NHM_PID_IEEE_11K_HIGH,
+	NHM_PID_IEEE_11K_LOW,
+};
+
+#define init_clm_param(clm, app, lv, time) \
+	do {\
+		clm.clm_app = app;\
+		clm.clm_lv = lv;\
+		clm.mntr_time = time;\
+	} while (0)
+
+#define init_nhm_param(nhm, txon, cca, cnt_opt, app, lv, time) \
+	do {\
+		nhm.incld_txon = txon;\
+		nhm.incld_cca = cca;\
+		nhm.div_opt = cnt_opt;\
+		nhm.nhm_app = app;\
+		nhm.nhm_lv = lv;\
+		nhm.mntr_time = time;\
+	} while (0)
+
+	
+#define init_acs_clm(clm, time) \
+	init_clm_param(clm, CLM_ACS, CLM_LV_2, time)
+
+#define init_acs_nhm(nhm, time) \
+	init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, NHM_ACS, NHM_LV_2, time)
+
+#define init_11K_high_nhm(nhm, time) \
+	init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, IEEE_11K_HIGH, NHM_LV_2, time)
+	
+#define init_11K_low_nhm(nhm, time) \
+		init_nhm_param(nhm, NHM_EXCLUDE_TXON, NHM_EXCLUDE_CCA, NHM_CNT_ALL, IEEE_11K_LOW, NHM_LV_2, time)
+
+
+#endif /*(RTK_ACS_VERSION == 3)*/
+void rtw_acs_version_dump(void *sel, _adapter *adapter);
+extern void phydm_ccx_monitor_trigger(void *p_dm_void, u16 monitor_time);
+extern void phydm_ccx_monitor_result(void *p_dm_void);
+
+#define GET_ACS_STATE(padapter)					(ATOMIC_READ(&GET_HAL_DATA(padapter)->acs.state))
+#define SET_ACS_STATE(padapter, set_state)			(ATOMIC_SET(&GET_HAL_DATA(padapter)->acs.state, set_state))
+#define IS_ACS_ENABLE(padapter)					((GET_ACS_STATE(padapter) == ACS_ENABLE) ? _TRUE : _FALSE)
+
+enum ACS_STATE {
+	ACS_DISABLE,
+	ACS_ENABLE,
+};
+
+#define ACS_BW_20M	BIT(0)
+#define ACS_BW_40M	BIT(1)
+#define ACS_BW_80M	BIT(2)
+#define ACS_BW_160M	BIT(3)
+
+struct auto_chan_sel {
+	ATOMIC_T state;
+	u8 trigger_ch;
+	bool triggered;
+	u8 clm_ratio[MAX_CHANNEL_NUM];
+	u8 nhm_ratio[MAX_CHANNEL_NUM];
+	#if (RTK_ACS_VERSION == 3)
+	u8 nhm[MAX_CHANNEL_NUM][NHM_RPT_NUM];
+	#endif
+	u8 bss_nums[MAX_CHANNEL_NUM];
+	u8 interference_time[MAX_CHANNEL_NUM];
+	u8 cur_ch_clm_ratio;
+	u8 cur_ch_nhm_ratio;
+	u8 best_chan_5g;
+	u8 best_chan_24g;
+
+	#if (RTK_ACS_VERSION == 3)
+	u8 trig_rst;
+	struct env_trig_rpt	trig_rpt;
+	#endif
+
+	#ifdef CONFIG_RTW_ACS_DBG
+	RT_SCAN_TYPE scan_type;
+	u16 scan_time;
+	u8 igi;
+	u8 bw;
+	#endif
+};
+
+#define rtw_acs_get_best_chan_24g(adapter)		(GET_HAL_DATA(adapter)->acs.best_chan_24g)
+#define rtw_acs_get_best_chan_5g(adapter)		(GET_HAL_DATA(adapter)->acs.best_chan_5g)
+
+#ifdef CONFIG_RTW_ACS_DBG
+#define rtw_is_acs_passiv_scan(adapter)	(((GET_HAL_DATA(adapter)->acs.scan_type) == SCAN_PASSIVE) ? _TRUE : _FALSE)
+
+#define rtw_acs_get_adv_st(adapter)	(GET_HAL_DATA(adapter)->acs.scan_time)
+#define rtw_is_acs_st_valid(adapter)	((GET_HAL_DATA(adapter)->acs.scan_time) ? _TRUE : _FALSE)
+
+#define rtw_acs_get_adv_igi(adapter)	(GET_HAL_DATA(adapter)->acs.igi)
+u8 rtw_is_acs_igi_valid(_adapter *adapter);
+
+#define rtw_acs_get_adv_bw(adapter)	(GET_HAL_DATA(adapter)->acs.bw)
+
+void rtw_acs_adv_setting(_adapter *adapter, RT_SCAN_TYPE scan_type, u16 scan_time, u8 igi, u8 bw);
+void rtw_acs_adv_reset(_adapter *adapter);
+#endif
+
+u8 rtw_acs_get_clm_ratio_by_ch_num(_adapter *adapter, u8 chan);
+u8 rtw_acs_get_clm_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx);
+u8 rtw_acs_get_nhm_ratio_by_ch_num(_adapter *adapter, u8 chan);
+u8 rtw_acs_get_num_ratio_by_ch_idx(_adapter *adapter, u8 ch_idx);
+
+void rtw_acs_reset(_adapter *adapter);
+void rtw_acs_trigger(_adapter *adapter, u16 scan_time_ms, u8 scan_chan, enum NHM_PID pid);
+void rtw_acs_get_rst(_adapter *adapter);
+void rtw_acs_select_best_chan(_adapter *adapter);
+void rtw_acs_info_dump(void *sel, _adapter *adapter);
+void rtw_acs_update_current_info(_adapter *adapter);
+void rtw_acs_chan_info_dump(void *sel, _adapter *adapter);
+void rtw_acs_current_info_dump(void *sel, _adapter *adapter);
+
+void rtw_acs_start(_adapter *adapter);
+void rtw_acs_stop(_adapter *adapter);
+
+#endif /*CONFIG_RTW_ACS*/
+
+#ifdef CONFIG_BACKGROUND_NOISE_MONITOR
+#define RTK_NOISE_MONITOR_VERSION	3
+#define GET_NM_STATE(padapter)					(ATOMIC_READ(&GET_HAL_DATA(padapter)->nm.state))
+#define SET_NM_STATE(padapter, set_state)			(ATOMIC_SET(&GET_HAL_DATA(padapter)->nm.state, set_state))
+#define IS_NM_ENABLE(padapter)					((GET_NM_STATE(padapter) == NM_ENABLE) ? _TRUE : _FALSE)
+
+enum NM_STATE {
+	NM_DISABLE,
+	NM_ENABLE,
+};
+
+struct noise_monitor {
+	ATOMIC_T state;
+	s16 noise[MAX_CHANNEL_NUM];
+	u8 bss_nums[MAX_CHANNEL_NUM];
+};
+void rtw_nm_enable(_adapter *adapter);
+void rtw_nm_disable(_adapter *adapter);
+void rtw_noise_measure(_adapter *adapter, u8 chan, u8 is_pause_dig, u8 igi_value, u32 max_time);
+s16 rtw_noise_query_by_chan_num(_adapter *adapter, u8 chan);
+s16 rtw_noise_query_by_chan_idx(_adapter *adapter, u8 ch_idx);
+s16 rtw_noise_measure_curchan(_adapter *padapter);
+void rtw_noise_info_dump(void *sel, _adapter *adapter);
+#endif
+#endif /* __HAL_DM_ACS_H__ */

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1694 - 226
hal/hal_halmac.c


+ 142 - 25
hal/hal_halmac.h

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2015 - 2018 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
@@ -11,25 +11,20 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #ifndef _HAL_HALMAC_H_
 #define _HAL_HALMAC_H_
 
 #include <drv_types.h>		/* adapter_to_dvobj(), struct intf_hdl and etc. */
 #include <hal_data.h>		/* struct hal_spec_t */
-#include "halmac/halmac_api.h"	/* PHALMAC_ADAPTER and etc. */
+#include "halmac/halmac_api.h"	/* struct halmac_adapter* and etc. */
 
 /* HALMAC Definition for Driver */
-#define RTW_HALMAC_H2C_MAX_SIZE		HALMAC_H2C_CMD_ORIGINAL_SIZE_88XX
+#define RTW_HALMAC_H2C_MAX_SIZE		8
 #define RTW_HALMAC_BA_SSN_RPT_SIZE	4
 
 #define dvobj_set_halmac(d, mac)	((d)->halmac = (mac))
-#define dvobj_to_halmac(d)		((PHALMAC_ADAPTER)((d)->halmac))
+#define dvobj_to_halmac(d)		((struct halmac_adapter *)((d)->halmac))
 #define adapter_to_halmac(p)		dvobj_to_halmac(adapter_to_dvobj(p))
 
 /* for H2C cmd */
@@ -42,7 +37,67 @@ typedef enum _RTW_HALMAC_MODE {
 	RTW_HALMAC_MODE_WIFI_TEST,
 } RTW_HALMAC_MODE;
 
-extern HALMAC_PLATFORM_API rtw_halmac_platform_api;
+union rtw_phy_para_data {
+	struct _mac {
+		u32	value;	/* value to be set in bit mask(msk) */
+		u32	msk;	/* bit mask */
+		u16	offset; /* address */
+		u8	msk_en;	/* 0/1 for msk invalid/valid */
+		u8	size;	/* Unit is bytes, and value should be 1/2/4 */
+	} mac;
+	struct _bb {
+		u32	value;
+		u32	msk;
+		u16	offset;
+		u8	msk_en;
+		u8	size;
+	} bb;
+	struct _rf {
+		u32	value;
+		u32	msk;
+		u8	offset;
+		u8	msk_en;
+		/*
+		 * 0: path A
+		 * 1: path B
+		 * 2: path C
+		 * 3: path D
+		 */
+		u8	path;
+	} rf;
+	struct _delay {
+		/*
+		 * 0: microsecond (us)
+		 * 1: millisecond (ms)
+		 */
+		u8	unit;
+		u16	value;
+	} delay;
+};
+
+struct rtw_phy_parameter {
+	/*
+	 * 0: MAC register
+	 * 1: BB register
+	 * 2: RF register
+	 * 3: Delay
+	 * 0xFF: Latest(End) command
+	 */
+	u8 cmd;
+	union rtw_phy_para_data data;
+};
+
+struct rtw_halmac_bcn_ctrl {
+	u8 rx_bssid_fit:1;	/* 0:HW handle beacon, 1:ignore */
+	u8 txbcn_rpt:1;		/* Enable TXBCN report in ad hoc and AP mode */
+	u8 tsf_update:1;	/* Update TSF when beacon or probe response */
+	u8 enable_bcn:1;	/* Enable beacon related functions */
+	u8 rxbcn_rpt:1;		/* Enable RXBCNOK report */
+	u8 p2p_ctwin:1;		/* Enable P2P CTN WINDOWS function */
+	u8 p2p_bcn_area:1;	/* Enable P2P BCN area on function */
+};
+
+extern struct halmac_platform_api rtw_halmac_platform_api;
 
 /* HALMAC API for Driver(HAL) */
 u8 rtw_halmac_read8(struct intf_hdl *, u32 addr);
@@ -53,14 +108,53 @@ void rtw_halmac_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem)
 u8 rtw_halmac_iread8(struct intf_hdl *pintfhdl, u32 addr);
 u16 rtw_halmac_iread16(struct intf_hdl *pintfhdl, u32 addr);
 u32 rtw_halmac_iread32(struct intf_hdl *pintfhdl, u32 addr);
-#endif
+#endif /* CONFIG_SDIO_INDIRECT_ACCESS */
 int rtw_halmac_write8(struct intf_hdl *, u32 addr, u8 value);
 int rtw_halmac_write16(struct intf_hdl *, u32 addr, u16 value);
 int rtw_halmac_write32(struct intf_hdl *, u32 addr, u32 value);
 
-void rtw_dump_halmac_info(void *sel);
-int rtw_halmac_init_adapter(struct dvobj_priv *, PHALMAC_PLATFORM_API);
+/* Software Information */
+void rtw_halmac_get_version(char *str, u32 len);
+
+/* Software Initialization */
+int rtw_halmac_init_adapter(struct dvobj_priv *d, struct halmac_platform_api *pf_api);
 int rtw_halmac_deinit_adapter(struct dvobj_priv *);
+
+/* Get operations */
+int rtw_halmac_get_hw_value(struct dvobj_priv *d, enum halmac_hw_id hw_id, void *pvalue);
+int rtw_halmac_get_tx_fifo_size(struct dvobj_priv *d, u32 *size);
+int rtw_halmac_get_rx_fifo_size(struct dvobj_priv *d, u32 *size);
+int rtw_halmac_get_rsvd_drv_pg_bndy(struct dvobj_priv *d, u16 *bndy);
+int rtw_halmac_get_page_size(struct dvobj_priv *d, u32 *size);
+int rtw_halmac_get_tx_agg_align_size(struct dvobj_priv *d, u16 *size);
+int rtw_halmac_get_rx_agg_align_size(struct dvobj_priv *d, u8 *size);
+int rtw_halmac_get_rx_drv_info_sz(struct dvobj_priv *, u8 *sz);
+int rtw_halmac_get_tx_desc_size(struct dvobj_priv *d, u32 *size);
+int rtw_halmac_get_rx_desc_size(struct dvobj_priv *d, u32 *size);
+int rtw_halmac_get_ori_h2c_size(struct dvobj_priv *d, u32 *size);
+int rtw_halmac_get_oqt_size(struct dvobj_priv *d, u8 *size);
+int rtw_halmac_get_ac_queue_number(struct dvobj_priv *d, u8 *num);
+int rtw_halmac_get_mac_address(struct dvobj_priv *d, enum _hw_port hwport, u8 *addr);
+int rtw_halmac_get_network_type(struct dvobj_priv *d, enum _hw_port hwport, u8 *type);
+int rtw_halmac_get_bcn_ctrl(struct dvobj_priv *d, enum _hw_port hwport, struct rtw_halmac_bcn_ctrl *bcn_ctrl);
+/*int rtw_halmac_get_wow_reason(struct dvobj_priv *, u8 *reason);*/
+
+/* Set operations */
+int rtw_halmac_config_rx_info(struct dvobj_priv *d, enum halmac_drv_info info);
+int rtw_halmac_set_max_dl_fw_size(struct dvobj_priv *d, u32 size);
+int rtw_halmac_set_mac_address(struct dvobj_priv *d, enum _hw_port hwport, u8 *addr);
+int rtw_halmac_set_bssid(struct dvobj_priv *d, enum _hw_port hwport, u8 *addr);
+int rtw_halmac_set_tx_address(struct dvobj_priv *d, enum _hw_port hwport, u8 *addr);
+int rtw_halmac_set_network_type(struct dvobj_priv *d, enum _hw_port hwport, u8 type);
+int rtw_halmac_reset_tsf(struct dvobj_priv *d, enum _hw_port hwport);
+int rtw_halmac_set_bcn_interval(struct dvobj_priv *d, enum _hw_port hwport, u32 space);
+int rtw_halmac_set_bcn_ctrl(struct dvobj_priv *d, enum _hw_port hwport, struct rtw_halmac_bcn_ctrl *bcn_ctrl);
+int rtw_halmac_set_aid(struct dvobj_priv *d, enum _hw_port hwport, u16 aid);
+int rtw_halmac_set_bandwidth(struct dvobj_priv *d, u8 channel, u8 pri_ch_idx, u8 bw);
+int rtw_halmac_set_edca(struct dvobj_priv *d, u8 queue, u8 aifs, u8 cw, u16 txop);
+int rtw_halmac_set_rts_full_bw(struct dvobj_priv *d, u8 enable);
+
+/* Functions */
 int rtw_halmac_poweron(struct dvobj_priv *);
 int rtw_halmac_poweroff(struct dvobj_priv *);
 int rtw_halmac_init_hal(struct dvobj_priv *);
@@ -68,6 +162,7 @@ int rtw_halmac_init_hal_fw(struct dvobj_priv *, u8 *fw, u32 fwsize);
 int rtw_halmac_init_hal_fw_file(struct dvobj_priv *, u8 *fwpath);
 int rtw_halmac_deinit_hal(struct dvobj_priv *);
 int rtw_halmac_self_verify(struct dvobj_priv *);
+int rtw_halmac_txfifo_wait_empty(struct dvobj_priv *d, u32 timeout);
 int rtw_halmac_dlfw(struct dvobj_priv *, u8 *fw, u32 fwsize);
 int rtw_halmac_dlfw_from_file(struct dvobj_priv *, u8 *fwpath);
 int rtw_halmac_dlfw_mem(struct dvobj_priv *d, u8 *fw, u32 fwsize, enum fw_mem mem);
@@ -75,14 +170,15 @@ int rtw_halmac_dlfw_mem_from_file(struct dvobj_priv *d, u8 *fwpath, enum fw_mem
 int rtw_halmac_phy_power_switch(struct dvobj_priv *, u8 enable);
 int rtw_halmac_send_h2c(struct dvobj_priv *, u8 *h2c);
 int rtw_halmac_c2h_handle(struct dvobj_priv *, u8 *c2h, u32 size);
-int rtw_halmac_get_available_efuse_size(struct dvobj_priv *d, u32 *size);
 
+/* eFuse */
+int rtw_halmac_get_available_efuse_size(struct dvobj_priv *d, u32 *size);
 int rtw_halmac_get_physical_efuse_size(struct dvobj_priv *, u32 *size);
 int rtw_halmac_read_physical_efuse_map(struct dvobj_priv *, u8 *map, u32 size);
 int rtw_halmac_read_physical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data);
 int rtw_halmac_write_physical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data);
 int rtw_halmac_get_logical_efuse_size(struct dvobj_priv *, u32 *size);
-int rtw_halmac_read_logical_efuse_map(struct dvobj_priv *, u8 *map, u32 size);
+int rtw_halmac_read_logical_efuse_map(struct dvobj_priv *, u8 *map, u32 size, u8 *maskmap, u32 masksize);
 int rtw_halmac_write_logical_efuse_map(struct dvobj_priv *, u8 *map, u32 size, u8 *maskmap, u32 masksize);
 int rtw_halmac_read_logical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data);
 int rtw_halmac_write_logical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data);
@@ -90,20 +186,17 @@ int rtw_halmac_write_logical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8
 int rtw_halmac_write_bt_physical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data);
 int rtw_halmac_read_bt_physical_efuse_map(struct dvobj_priv *, u8 *map, u32 size);
 
-int rtw_halmac_config_rx_info(struct dvobj_priv *, HALMAC_DRV_INFO);
-int rtw_halmac_set_mac_address(struct dvobj_priv *, enum _hw_port, u8 *addr);
-int rtw_halmac_set_bssid(struct dvobj_priv *, enum _hw_port hwport, u8 *addr);
-
-int rtw_halmac_set_bandwidth(struct dvobj_priv *, u8 channel, u8 pri_ch_idx, u8 bw);
 int rtw_halmac_dump_fifo(struct dvobj_priv *d, u8 fifo_sel, u32 addr, u32 size, u8 *buffer);
 int rtw_halmac_rx_agg_switch(struct dvobj_priv *, u8 enable);
-int rtw_halmac_get_hw_value(struct dvobj_priv *, HALMAC_HW_ID hw_id, VOID *pvalue);
-int rtw_halmac_get_wow_reason(struct dvobj_priv *, u8 *reason);
-int rtw_halmac_get_drv_info_sz(struct dvobj_priv *, u8 *sz);
-int rtw_halmac_get_rsvd_drv_pg_bndy(struct dvobj_priv *dvobj, u16 *drv_pg);
+
+/* Specific function APIs*/
 int rtw_halmac_download_rsvd_page(struct dvobj_priv *dvobj, u8 pg_offset, u8 *pbuf, u32 size);
 int rtw_halmac_fill_hal_spec(struct dvobj_priv *, struct hal_spec_t *);
 int rtw_halmac_p2pps(struct dvobj_priv *dvobj, PHAL_P2P_PS_PARA pp2p_ps_para);
+int rtw_halmac_iqk(struct dvobj_priv *d, u8 clear, u8 segment);
+int rtw_halmac_cfg_phy_para(struct dvobj_priv *d, struct rtw_phy_parameter *para);
+int rtw_halmac_led_cfg(struct dvobj_priv *d, u8 enable, u8 mode);
+void rtw_halmac_led_switch(struct dvobj_priv *d, u8 on);
 
 #ifdef CONFIG_SDIO_HCI
 int rtw_halmac_query_tx_page_num(struct dvobj_priv *);
@@ -115,10 +208,34 @@ u32 rtw_halmac_sdio_get_rx_addr(struct dvobj_priv *, u8 *seq);
 
 #ifdef CONFIG_USB_HCI
 u8 rtw_halmac_usb_get_bulkout_id(struct dvobj_priv *, u8 *buf, u32 size);
+int rtw_halmac_usb_get_txagg_desc_num(struct dvobj_priv *d, u8 *num);
 u8 rtw_halmac_switch_usb_mode(struct dvobj_priv *d, enum RTW_USB_SPEED usb_mode);
 #endif /* CONFIG_USB_HCI */
 
 #ifdef CONFIG_SUPPORT_TRX_SHARED
 void dump_trx_share_mode(void *sel, _adapter *adapter);
 #endif
+
+#ifdef CONFIG_BEAMFORMING
+#ifdef RTW_BEAMFORMING_VERSION_2
+int rtw_halmac_bf_add_mu_bfer(struct dvobj_priv *d, u16 paid, u16 csi_para,
+		u16 my_aid, enum halmac_csi_seg_len sel, u8 *addr);
+int rtw_halmac_bf_del_mu_bfer(struct dvobj_priv *d);
+
+int rtw_halmac_bf_cfg_sounding(struct dvobj_priv *d, enum halmac_snd_role role,
+		enum halmac_data_rate rate);
+int rtw_halmac_bf_del_sounding(struct dvobj_priv *d, enum halmac_snd_role role);
+
+int rtw_halmac_bf_cfg_csi_rate(struct dvobj_priv *d, u8 rssi, u8 current_rate,
+		u8 fixrate_en, u8 *new_rate);
+
+int rtw_halmac_bf_cfg_mu_mimo(struct dvobj_priv *d, enum halmac_snd_role role,
+		u8 *sounding_sts, u16 grouping_bitmap, u8 mu_tx_en,
+		u32 *given_gid_tab, u32 *given_user_pos);
+#define rtw_halmac_bf_cfg_mu_bfee(d, gid_tab, user_pos) \
+	rtw_halmac_bf_cfg_mu_mimo(d, HAL_BFEE, NULL, 0, 0, gid_tab, user_pos)
+
+#endif /* RTW_BEAMFORMING_VERSION_2 */
+#endif /* CONFIG_BEAMFORMING */
+
 #endif /* _HAL_HALMAC_H_ */

+ 2 - 7
hal/hal_hci/hal_pci.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _HAL_PCI_C_
 
 #include <drv_types.h>

+ 422 - 198
hal/hal_intf.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,12 +11,7 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 
 #define _HAL_INTF_C_
 
@@ -33,9 +28,12 @@ const u32 _chip_type_to_odm_ic_type[] = {
 	ODM_RTL8814A,
 	ODM_RTL8703B,
 	ODM_RTL8188F,
+	ODM_RTL8188F,
 	ODM_RTL8822B,
 	ODM_RTL8723D,
 	ODM_RTL8821C,
+	ODM_RTL8710B,
+	ODM_RTL8192F,
 	0,
 };
 
@@ -56,7 +54,7 @@ u8 rtw_hal_read_chip_info(_adapter *padapter)
 {
 	u8 rtn = _SUCCESS;
 	u8 hci_type = rtw_get_intf_type(padapter);
-	u32 start = rtw_get_current_time();
+	systime start = rtw_get_current_time();
 
 	/*  before access eFuse, make sure card enable has been called */
 	if ((hci_type == RTW_SDIO || hci_type == RTW_GSPI)
@@ -80,12 +78,56 @@ void rtw_hal_read_chip_version(_adapter *padapter)
 	rtw_odm_init_ic_type(padapter);
 }
 
+static void rtw_init_wireless_mode(_adapter *padapter)
+{
+	u8 proto_wireless_mode = 0;
+	struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
+	if(hal_spec->proto_cap & PROTO_CAP_11B)
+		proto_wireless_mode |= WIRELESS_11B;
+	
+	if(hal_spec->proto_cap & PROTO_CAP_11G)
+		proto_wireless_mode |= WIRELESS_11G;
+#ifdef CONFIG_80211AC_VHT
+	if(hal_spec->band_cap & BAND_CAP_5G)
+		proto_wireless_mode |= WIRELESS_11A;
+#endif
+
+#ifdef CONFIG_80211N_HT
+	if(hal_spec->proto_cap & PROTO_CAP_11N) {
+
+		if(hal_spec->band_cap & BAND_CAP_2G)
+			proto_wireless_mode |= WIRELESS_11_24N;
+		if(hal_spec->band_cap & BAND_CAP_5G)
+			proto_wireless_mode |= WIRELESS_11_5N;
+	}
+#endif
+
+#ifdef CONFIG_80211AC_VHT
+	if(hal_spec->proto_cap & PROTO_CAP_11AC) 
+		proto_wireless_mode |= WIRELESS_11AC;
+#endif
+	padapter->registrypriv.wireless_mode &= proto_wireless_mode;
+}
+
 void rtw_hal_def_value_init(_adapter *padapter)
 {
 	if (is_primary_adapter(padapter)) {
+		/*init fw_psmode_iface_id*/
+		adapter_to_pwrctl(padapter)->fw_psmode_iface_id = 0xff;
+		/*wireless_mode*/
+		rtw_init_wireless_mode(padapter);
 		padapter->hal_func.init_default_value(padapter);
 
 		rtw_init_hal_com_default_value(padapter);
+		
+		#ifdef CONFIG_FW_MULTI_PORT_SUPPORT
+		adapter_to_dvobj(padapter)->dft.port_id = 0xFF;
+		adapter_to_dvobj(padapter)->dft.mac_id = 0xFF;
+		#endif
+		#ifdef CONFIG_HW_P0_TSF_SYNC
+		adapter_to_dvobj(padapter)->p0_tsf.sync_port = MAX_HW_PORT;
+		adapter_to_dvobj(padapter)->p0_tsf.offset = 0;
+		#endif
 
 		{
 			struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
@@ -97,6 +139,7 @@ void rtw_hal_def_value_init(_adapter *padapter)
 			dvobj->cam_ctl.sec_cap = hal_spec->sec_cap;
 			dvobj->cam_ctl.num = rtw_min(hal_spec->sec_cam_ent_num, SEC_CAM_ENT_NUM_SW_LIMIT);
 		}
+		GET_HAL_DATA(padapter)->rx_tsf_addr_filter_config = 0;
 	}
 }
 
@@ -109,6 +152,7 @@ u8 rtw_hal_data_init(_adapter *padapter)
 			RTW_INFO("cant not alloc memory for HAL DATA\n");
 			return _FAIL;
 		}
+		rtw_phydm_priv_init(padapter);
 	}
 	return _SUCCESS;
 }
@@ -154,26 +198,49 @@ void rtw_hal_dm_deinit(_adapter *padapter)
 		_rtw_spinlock_free(&pHalData->IQKSpinLock);
 	}
 }
-void	rtw_hal_sw_led_init(_adapter *padapter)
+
+#ifdef CONFIG_RTW_SW_LED
+void rtw_hal_sw_led_init(_adapter *padapter)
 {
-	if (padapter->hal_func.InitSwLeds)
+	struct led_priv *ledpriv = adapter_to_led(padapter);
+
+	if (ledpriv->bRegUseLed == _FALSE)
+		return;
+
+	if (!is_primary_adapter(padapter))
+		return;
+
+	if (padapter->hal_func.InitSwLeds) {
 		padapter->hal_func.InitSwLeds(padapter);
+		rtw_led_set_ctl_en_mask_primary(padapter);
+		rtw_led_set_iface_en(padapter, 1);
+	}
 }
 
 void rtw_hal_sw_led_deinit(_adapter *padapter)
 {
+	struct led_priv *ledpriv = adapter_to_led(padapter);
+
+	if (ledpriv->bRegUseLed == _FALSE)
+		return;
+
+	if (!is_primary_adapter(padapter))
+		return;
+
 	if (padapter->hal_func.DeInitSwLeds)
 		padapter->hal_func.DeInitSwLeds(padapter);
 }
+#endif
 
 u32 rtw_hal_power_on(_adapter *padapter)
 {
 	u32 ret = 0;
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter);
 
 	ret = padapter->hal_func.hal_power_on(padapter);
 
 #ifdef CONFIG_BT_COEXIST
-	if (ret == _SUCCESS)
+	if ((ret == _SUCCESS) && (pHalData->EEPROMBluetoothCoexist == _TRUE))
 		rtw_btcoex_PowerOnSetting(padapter);
 #endif
 
@@ -205,27 +272,85 @@ void rtw_hal_init_opmode(_adapter *padapter)
 		networkType = Ndis802_11IBSS;
 	else if (fw_state & WIFI_STATION_STATE)
 		networkType = Ndis802_11Infrastructure;
+#ifdef CONFIG_AP_MODE
 	else if (fw_state & WIFI_AP_STATE)
 		networkType = Ndis802_11APMode;
+#endif
+#ifdef CONFIG_RTW_MESH
+	else if (fw_state & WIFI_MESH_STATE)
+		networkType = Ndis802_11_mesh;
+#endif
 	else
 		return;
 
-	rtw_setopmode_cmd(padapter, networkType, _FALSE);
+	rtw_setopmode_cmd(padapter, networkType, RTW_CMDF_DIRECTLY);
+}
+
+#ifdef CONFIG_NEW_NETDEV_HDL
+uint rtw_hal_iface_init(_adapter *adapter)
+{
+	uint status = _SUCCESS;
+
+	rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR, adapter_mac_addr(adapter));
+	#ifdef RTW_HALMAC
+	rtw_hal_hw_port_enable(adapter);
+	#endif
+	rtw_sec_restore_wep_key(adapter);
+	rtw_hal_init_opmode(adapter);
+	rtw_hal_start_thread(adapter);
+	return status;
 }
+uint rtw_hal_init(_adapter *padapter)
+{
+	uint status = _SUCCESS;
+
+	status = padapter->hal_func.hal_init(padapter);
 
+	if (status == _SUCCESS) {
+		rtw_set_hw_init_completed(padapter, _TRUE);
+		if (padapter->registrypriv.notch_filter == 1)
+			rtw_hal_notch_filter(padapter, 1);
+		rtw_led_control(padapter, LED_CTL_POWER_ON);
+		init_hw_mlme_ext(padapter);
+		#ifdef CONFIG_RF_POWER_TRIM
+		rtw_bb_rf_gain_offset(padapter);
+		#endif /*CONFIG_RF_POWER_TRIM*/
+		GET_PRIMARY_ADAPTER(padapter)->bup = _TRUE; /*temporary*/
+		#ifdef CONFIG_MI_WITH_MBSSID_CAM
+		rtw_mi_set_mbid_cam(padapter);
+		#endif
+		#ifdef CONFIG_SUPPORT_MULTI_BCN
+		rtw_ap_multi_bcn_cfg(padapter);
+		#endif
+		#if (RTL8822B_SUPPORT == 1) || (RTL8192F_SUPPORT == 1)
+		#ifdef CONFIG_DYNAMIC_SOML
+		rtw_dyn_soml_config(padapter);
+		#endif
+		#endif
+#ifdef CONFIG_RTW_TX_2PATH_EN
+		rtw_phydm_tx_2path_en(padapter);
+#endif
+	} else {
+		rtw_set_hw_init_completed(padapter, _FALSE);
+		RTW_ERR("%s: hal_init fail\n", __func__);
+	}
+	return status;
+}
+#else
 uint	 rtw_hal_init(_adapter *padapter)
 {
 	uint	status = _SUCCESS;
 	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
-	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
 	int i;
 
 	status = padapter->hal_func.hal_init(padapter);
 
 	if (status == _SUCCESS) {
-		pHalData->hw_init_completed = _TRUE;
-		rtw_restore_mac_addr(padapter);
-
+		rtw_set_hw_init_completed(padapter, _TRUE);
+		rtw_mi_set_mac_addr(padapter);/*set mac addr of all ifaces*/
+		#ifdef RTW_HALMAC
+		rtw_restore_hw_port_cfg(padapter);
+		#endif
 		if (padapter->registrypriv.notch_filter == 1)
 			rtw_hal_notch_filter(padapter, 1);
 
@@ -238,32 +363,45 @@ uint	 rtw_hal_init(_adapter *padapter)
 
 		rtw_hal_init_opmode(padapter);
 
-#ifdef CONFIG_RF_POWER_TRIM
+		#ifdef CONFIG_RF_POWER_TRIM
 		rtw_bb_rf_gain_offset(padapter);
-#endif /*CONFIG_RF_POWER_TRIM*/
+		#endif /*CONFIG_RF_POWER_TRIM*/
 
+		#ifdef CONFIG_SUPPORT_MULTI_BCN
+		rtw_ap_multi_bcn_cfg(padapter);
+		#endif
+
+#if (RTL8822B_SUPPORT == 1) || (RTL8192F_SUPPORT == 1)
+#ifdef CONFIG_DYNAMIC_SOML
+		rtw_dyn_soml_config(padapter);
+#endif
+#endif
+
+#ifdef CONFIG_RTW_TX_2PATH_EN
+		rtw_phydm_tx_2path_en(padapter);
+#endif
 	} else {
-		pHalData->hw_init_completed = _FALSE;
-		RTW_INFO("rtw_hal_init: hal_init fail\n");
+		rtw_set_hw_init_completed(padapter, _FALSE);
+		RTW_ERR("%s: fail\n", __func__);
 	}
 
 
 	return status;
 
 }
+#endif
 
 uint rtw_hal_deinit(_adapter *padapter)
 {
 	uint	status = _SUCCESS;
 	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
-	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
 	int i;
 
 	status = padapter->hal_func.hal_deinit(padapter);
 
 	if (status == _SUCCESS) {
 		rtw_led_control(padapter, LED_CTL_POWER_OFF);
-		pHalData->hw_init_completed = _FALSE;
+		rtw_set_hw_init_completed(padapter, _FALSE);
 	} else
 		RTW_INFO("\n rtw_hal_deinit: hal_init fail\n");
 
@@ -271,9 +409,9 @@ uint rtw_hal_deinit(_adapter *padapter)
 	return status;
 }
 
-void rtw_hal_set_hwreg(_adapter *padapter, u8 variable, u8 *val)
+u8 rtw_hal_set_hwreg(_adapter *padapter, u8 variable, u8 *val)
 {
-	padapter->hal_func.set_hw_reg_handler(padapter, variable, val);
+	return padapter->hal_func.set_hw_reg_handler(padapter, variable, val);
 }
 
 void rtw_hal_get_hwreg(_adapter *padapter, u8 variable, u8 *val)
@@ -335,7 +473,7 @@ s32 rtw_hal_fw_dl(_adapter *padapter, u8 wowlan)
 #ifdef RTW_HALMAC
 s32 rtw_hal_fw_mem_dl(_adapter *padapter, enum fw_mem mem)
 {
-	u32 dlfw_start_time = rtw_get_current_time();
+	systime dlfw_start_time = rtw_get_current_time();
 	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
 	struct debug_priv *pdbgpriv = &dvobj->drv_dbg;
 	s32 rst = _FALSE;
@@ -460,38 +598,18 @@ s32	rtw_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe)
 s32	rtw_hal_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe)
 {
 	s32 ret = _FAIL;
-	u8	*pframe, subtype;
-	struct rtw_ieee80211_hdr	*pwlanhdr;
-	struct sta_info	*psta;
-	struct sta_priv		*pstapriv = &padapter->stapriv;
 
 	update_mgntframe_attrib_addr(padapter, pmgntframe);
-	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
-	subtype = get_frame_sub_type(pframe); /* bit(7)~bit(2) */
-
-	/* pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; */
-	/* _rtw_memcpy(pmgntframe->attrib.ra, pwlanhdr->addr1, ETH_ALEN); */
-
-#ifdef CONFIG_IEEE80211W
-	if (padapter->securitypriv.binstallBIPkey == _TRUE && (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC ||
-			subtype == WIFI_ACTION)) {
-		if (IS_MCAST(pmgntframe->attrib.ra) && pmgntframe->attrib.key_type != IEEE80211W_NO_KEY) {
-			pmgntframe->attrib.encrypt = _BIP_;
-			/* pmgntframe->attrib.bswenc = _TRUE; */
-		} else if (pmgntframe->attrib.key_type != IEEE80211W_NO_KEY) {
-			psta = rtw_get_stainfo(pstapriv, pmgntframe->attrib.ra);
-			if (psta && psta->bpairwise_key_installed == _TRUE) {
-				pmgntframe->attrib.encrypt = _AES_;
-				pmgntframe->attrib.bswenc = _TRUE;
-			} else {
-				RTW_INFO("%s, %d, bpairwise_key_installed is FALSE\n", __func__, __LINE__);
-				goto no_mgmt_coalesce;
-			}
-		}
-		RTW_INFO("encrypt=%d, bswenc=%d\n", pmgntframe->attrib.encrypt, pmgntframe->attrib.bswenc);
+
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_RTW_MESH)
+	if ((!MLME_IS_MESH(padapter) && SEC_IS_BIP_KEY_INSTALLED(&padapter->securitypriv) == _TRUE)
+		#ifdef CONFIG_RTW_MESH
+		|| (MLME_IS_MESH(padapter) && padapter->mesh_info.mesh_auth_id)
+		#endif
+	)
 		rtw_mgmt_xmitframe_coalesce(padapter, pmgntframe->pkt, pmgntframe);
-	}
-#endif /* CONFIG_IEEE80211W */
+#endif
+
 no_mgmt_coalesce:
 	ret = padapter->hal_func.mgnt_xmit(padapter, pmgntframe);
 	return ret;
@@ -515,97 +633,44 @@ void	rtw_hal_free_recv_priv(_adapter *padapter)
 	padapter->hal_func.free_recv_priv(padapter);
 }
 
-void rtw_update_ramask(_adapter *padapter, struct sta_info *psta, u32 mac_id, u8 rssi_level, u8 is_update_bw)
+void rtw_sta_ra_registed(_adapter *padapter, struct sta_info *psta)
 {
-	struct macid_cfg h2c_macid_cfg;
-	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
-	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
-	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
-	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-	HAL_DATA_TYPE	*hal_data = GET_HAL_DATA(padapter);
-	u8 disable_cck_rate = FALSE, MimoPs_enable = FALSE;
-	u32 ratr_bitmap_msb = 0, ratr_bitmap_lsb = 0;
-	u64	mask = 0, rate_bitmap = 0;
-	u8 bw, short_gi;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter);
 
 	if (psta == NULL) {
-		RTW_ERR(FUNC_ADPT_FMT" macid:%u, sta is NULL\n", FUNC_ADPT_ARG(padapter), mac_id);
+		RTW_ERR(FUNC_ADPT_FMT" sta is NULL\n", FUNC_ADPT_ARG(padapter));
 		rtw_warn_on(1);
 		return;
 	}
-	_rtw_memset(&h2c_macid_cfg, 0, sizeof(struct macid_cfg));
-
-	bw =  rtw_get_tx_bw_mode(padapter, psta);
-	short_gi = query_ra_short_GI(psta, bw);
-
-	ratr_bitmap_msb = (u32)(psta->ra_mask >> 32);
-	ratr_bitmap_lsb = (u32)(psta->ra_mask);
-
-	phydm_update_hal_ra_mask(&hal_data->odmpriv, psta->wireless_mode, hal_data->rf_type, bw, MimoPs_enable, disable_cck_rate, &ratr_bitmap_msb, &ratr_bitmap_lsb, rssi_level);
-	mask = (((u64)ratr_bitmap_msb) << 32) | ((u64)ratr_bitmap_lsb);
 
-
-#ifdef CONFIG_BT_COEXIST
-	if (hal_data->EEPROMBluetoothCoexist == 1) {
-		rate_bitmap = rtw_btcoex_GetRaMask(padapter);
-		mask &= ~rate_bitmap;
-	}
-#endif /* CONFIG_BT_COEXIST */
-
-#ifdef CONFIG_CMCC_TEST
-#ifdef CONFIG_BT_COEXIST
-	if (pmlmeext->cur_wireless_mode & WIRELESS_11G) {
-		if (mac_id == 0) {
-			RTW_INFO("CMCC_BT update raid entry, mask=0x%x\n", mask);
-			/*mask &=0xffffffc0; //disable CCK & <12M OFDM rate for 11G mode for CMCC */
-			mask &= 0xffffff00; /*disable CCK & <24M OFDM rate for 11G mode for CMCC */
-			RTW_INFO("CMCC_BT update raid entry, mask=0x%x\n", mask);
+#ifdef CONFIG_AP_MODE
+	if (MLME_IS_AP(padapter) || MLME_IS_MESH(padapter)) {
+		if (psta->cmn.aid > padapter->stapriv.max_aid) {
+			RTW_ERR("station aid %d exceed the max number\n", psta->cmn.aid);
+			rtw_warn_on(1);
+			return;
 		}
+		rtw_ap_update_sta_ra_info(padapter, psta);
 	}
-#endif
 #endif
 
+	psta->cmn.ra_info.ra_bw_mode = rtw_get_tx_bw_mode(padapter, psta);
 	/*set correct initial date rate for each mac_id */
-	hal_data->INIDATA_RATE[mac_id] = psta->init_rate;
-
-
-	RTW_INFO("%s => mac_id:%d, networkType:0x%02x, mask:0x%016llx\n\t ==> rssi_level:%d, rate_bitmap:0x%016llx, shortGIrate=%d\n\t ==> bw:%d, ignore_bw:0x%d\n",
-			__func__, mac_id, psta->wireless_mode, mask, rssi_level, rate_bitmap, short_gi, bw, (!is_update_bw));
-
-	rtw_macid_ctl_set_bw(macid_ctl, mac_id, bw);
-	rtw_macid_ctl_set_vht_en(macid_ctl, mac_id, is_supported_vht(psta->wireless_mode));
-	rtw_macid_ctl_set_rate_bmp0(macid_ctl, mac_id, mask);
-	rtw_macid_ctl_set_rate_bmp1(macid_ctl, mac_id, mask >> 32);
-	rtw_update_tx_rate_bmp(adapter_to_dvobj(padapter));
-
-	h2c_macid_cfg.mac_id = mac_id;
-	h2c_macid_cfg.rate_id = psta->raid;
-	h2c_macid_cfg.bandwidth = bw;
-	h2c_macid_cfg.ignore_bw = (!is_update_bw);
-	h2c_macid_cfg.short_gi = short_gi;
-	h2c_macid_cfg.ra_mask = mask;
+	hal_data->INIDATA_RATE[psta->cmn.mac_id] = psta->init_rate;
 
-	padapter->hal_func.update_ra_mask_handler(padapter, psta, &h2c_macid_cfg);
+	rtw_phydm_ra_registed(padapter, psta);
 }
 
-void rtw_hal_update_ra_mask(struct sta_info *psta, u8 rssi_level, u8 is_update_bw)
+void rtw_hal_update_ra_mask(struct sta_info *psta)
 {
 	_adapter *padapter;
-	struct mlme_priv *pmlmepriv;
 
 	if (!psta)
 		return;
 
 	padapter = psta->padapter;
-
-	pmlmepriv = &(padapter->mlmepriv);
-
-	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
-		add_RATid(padapter, psta, rssi_level, is_update_bw);
-	else {
-		psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
-		rtw_update_ramask(padapter, psta, psta->mac_id, rssi_level, is_update_bw);
-	}
+	rtw_sta_ra_registed(padapter, psta);
 }
 
 /*	Start specifical interface thread		*/
@@ -642,30 +707,34 @@ void	rtw_hal_write_bbreg(_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data)
 		padapter->hal_func.write_bbreg(padapter, RegAddr, BitMask, Data);
 }
 
-u32 rtw_hal_read_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask)
+u32 rtw_hal_read_rfreg(_adapter *padapter, enum rf_path eRFPath, u32 RegAddr, u32 BitMask)
 {
 	u32 data = 0;
 
 	if (padapter->hal_func.read_rfreg) {
 		data = padapter->hal_func.read_rfreg(padapter, eRFPath, RegAddr, BitMask);
 
-		if (match_rf_read_sniff_ranges(eRFPath, RegAddr, BitMask)) {
+		#ifdef DBG_IO
+		if (match_rf_read_sniff_ranges(padapter, eRFPath, RegAddr, BitMask)) {
 			RTW_INFO("DBG_IO rtw_hal_read_rfreg(%u, 0x%04x, 0x%08x) read:0x%08x(0x%08x)\n"
 				, eRFPath, RegAddr, BitMask, (data << PHY_CalculateBitShift(BitMask)), data);
 		}
+		#endif
 	}
 
 	return data;
 }
 
-void rtw_hal_write_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data)
+void rtw_hal_write_rfreg(_adapter *padapter, enum rf_path eRFPath, u32 RegAddr, u32 BitMask, u32 Data)
 {
 	if (padapter->hal_func.write_rfreg) {
 
-		if (match_rf_write_sniff_ranges(eRFPath, RegAddr, BitMask)) {
+		#ifdef DBG_IO
+		if (match_rf_write_sniff_ranges(padapter, eRFPath, RegAddr, BitMask)) {
 			RTW_INFO("DBG_IO rtw_hal_write_rfreg(%u, 0x%04x, 0x%08x) write:0x%08x(0x%08x)\n"
 				, eRFPath, RegAddr, BitMask, (Data << PHY_CalculateBitShift(BitMask)), Data);
 		}
+		#endif
 
 		padapter->hal_func.write_rfreg(padapter, eRFPath, RegAddr, BitMask, Data);
 
@@ -676,6 +745,23 @@ void rtw_hal_write_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMa
 	}
 }
 
+#ifdef CONFIG_SYSON_INDIRECT_ACCESS
+u32 rtw_hal_read_syson_reg(PADAPTER padapter, u32 RegAddr, u32 BitMask)
+{
+	u32 data = 0;
+	if (padapter->hal_func.read_syson_reg)
+		data = padapter->hal_func.read_syson_reg(padapter, RegAddr, BitMask);
+
+	return data;
+}
+
+void rtw_hal_write_syson_reg(_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data)
+{
+	if (padapter->hal_func.write_syson_reg)
+		padapter->hal_func.write_syson_reg(padapter, RegAddr, BitMask, Data);
+}
+#endif
+
 #if defined(CONFIG_PCI_HCI)
 s32	rtw_hal_interrupt_handler(_adapter *padapter)
 {
@@ -691,22 +777,22 @@ void	rtw_hal_interrupt_handler(_adapter *padapter, u16 pkt_len, u8 *pbuf)
 }
 #endif
 
-void	rtw_hal_set_chnl_bw(_adapter *padapter, u8 channel, CHANNEL_WIDTH Bandwidth, u8 Offset40, u8 Offset80)
+void	rtw_hal_set_chnl_bw(_adapter *padapter, u8 channel, enum channel_width Bandwidth, u8 Offset40, u8 Offset80)
 {
 	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
-	struct PHY_DM_STRUCT		*pDM_Odm = &(pHalData->odmpriv);
 	u8 cch_160 = Bandwidth == CHANNEL_WIDTH_160 ? channel : 0;
 	u8 cch_80 = Bandwidth == CHANNEL_WIDTH_80 ? channel : 0;
 	u8 cch_40 = Bandwidth == CHANNEL_WIDTH_40 ? channel : 0;
 	u8 cch_20 = Bandwidth == CHANNEL_WIDTH_20 ? channel : 0;
 
-	odm_acquire_spin_lock(pDM_Odm, RT_IQK_SPINLOCK);
-	if (pDM_Odm->rf_calibrate_info.is_iqk_in_progress == _TRUE)
+	if (rtw_phydm_is_iqk_in_progress(padapter))
 		RTW_ERR("%s, %d, IQK may race condition\n", __func__, __LINE__);
-	odm_release_spin_lock(pDM_Odm, RT_IQK_SPINLOCK);
 
+#ifdef CONFIG_MP_INCLUDED
 	/* MP mode channel don't use secondary channel */
-	if (rtw_mi_mp_mode_check(padapter) == _FALSE) {
+	if (rtw_mp_mode_check(padapter) == _FALSE)
+#endif
+	{
 		#if 0
 		if (cch_160 != 0)
 			cch_80 = rtw_get_scch_by_cch_offset(cch_160, CHANNEL_WIDTH_160, Offset80);
@@ -743,15 +829,13 @@ void	rtw_hal_get_tx_power_level(_adapter *padapter, s32 *powerlevel)
 
 void	rtw_hal_dm_watchdog(_adapter *padapter)
 {
-#ifdef CONFIG_MCC_MODE
-	if (MCC_EN(padapter)) {
-		if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC))
-			return;
-	}
-#endif /* CONFIG_MCC_MODE */
+
 	rtw_hal_turbo_edca(padapter);
 	padapter->hal_func.hal_dm_watchdog(padapter);
 
+#ifdef CONFIG_PCI_DYNAMIC_ASPM
+	rtw_pci_aspm_config_dynamic_l1_ilde_time(padapter);
+#endif
 }
 
 #ifdef CONFIG_LPS_LCLK_WD_TIMER
@@ -764,11 +848,10 @@ void	rtw_hal_dm_watchdog_in_lps(_adapter *padapter)
 #endif
 #endif
 
-	if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == _TRUE) {
-		padapter->hal_func.hal_dm_watchdog_in_lps(padapter);/* this function caller is in interrupt context					 */
-	}
+	if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == _TRUE)
+		rtw_phydm_watchdog_in_lps_lclk(padapter);/* this function caller is in interrupt context */
 }
-#endif
+#endif /*CONFIG_LPS_LCLK_WD_TIMER*/
 
 void rtw_hal_bcn_related_reg_setting(_adapter *padapter)
 {
@@ -914,8 +997,6 @@ exit:
 #endif
 s32 c2h_handler(_adapter *adapter, u8 id, u8 seq, u8 plen, u8 *payload)
 {
-	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
-	struct PHY_DM_STRUCT *odm = &hal_data->odmpriv;
 	u8 sub_id = 0;
 	s32 ret = _SUCCESS;
 
@@ -935,7 +1016,10 @@ s32 c2h_handler(_adapter *adapter, u8 id, u8 seq, u8 plen, u8 *payload)
 		rtw_btcoex_BtMpRptNotify(adapter, plen, payload);
 		break;
 	case C2H_MAILBOX_STATUS:
-		RTW_INFO_DUMP("C2H_MAILBOX_STATUS: ", payload, plen);
+		RTW_DBG_DUMP("C2H_MAILBOX_STATUS: ", payload, plen);
+		break;
+	case C2H_WLAN_INFO:
+		rtw_btcoex_WlFwDbgInfoNotify(adapter, payload, plen);
 		break;
 #endif /* CONFIG_BT_COEXIST */
 
@@ -979,13 +1063,17 @@ s32 c2h_handler(_adapter *adapter, u8 id, u8 seq, u8 plen, u8 *payload)
 		c2h_customer_str_rpt_2_hdl(adapter, payload, plen);
 		break;
 #endif
-
+#ifdef RTW_PER_CMD_SUPPORT_FW
+	case C2H_PER_RATE_RPT:
+		c2h_per_rate_rpt_hdl(adapter, payload, plen);
+		break;
+#endif
 	case C2H_EXTEND:
 		sub_id = payload[0];
 		/* no handle, goto default */
 
 	default:
-		if (phydm_c2H_content_parsing(odm, id, plen, payload) != TRUE)
+		if (phydm_c2H_content_parsing(adapter_to_phydm(adapter), id, plen, payload) != TRUE)
 			ret = _FAIL;
 		break;
 	}
@@ -1036,55 +1124,164 @@ s32 rtw_hal_is_disable_sw_channel_plan(PADAPTER padapter)
 	return GET_HAL_DATA(padapter)->bDisableSWChannelPlan;
 }
 
-s32 rtw_hal_macid_sleep(PADAPTER padapter, u8 macid)
+static s32 _rtw_hal_macid_sleep(_adapter *adapter, u8 macid, u8 sleep)
 {
-	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
-	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
-	u8 support;
-
-	support = _FALSE;
-	rtw_hal_get_def_var(padapter, HAL_DEF_MACID_SLEEP, &support);
-	if (_FALSE == support)
-		return _FAIL;
+	struct macid_ctl_t *macid_ctl = adapter_to_macidctl(adapter);
+	u16 reg_sleep;
+	u8 bit_shift;
+	u32 val32;
+	s32 ret = _FAIL;
 
 	if (macid >= macid_ctl->num) {
-		RTW_ERR(FUNC_ADPT_FMT": Invalid macid(%u)\n",
-			FUNC_ADPT_ARG(padapter), macid);
-		return _FAIL;
+		RTW_ERR(ADPT_FMT" %s invalid macid(%u)\n"
+			, ADPT_ARG(adapter), sleep ? "sleep" : "wakeup" , macid);
+		goto exit;
 	}
 
-	rtw_hal_set_hwreg(padapter, HW_VAR_MACID_SLEEP, &macid);
+	if (macid < 32) {
+		reg_sleep = macid_ctl->reg_sleep_m0;
+		bit_shift = macid;
+	#if (MACID_NUM_SW_LIMIT > 32)
+	} else if (macid < 64) {
+		reg_sleep = macid_ctl->reg_sleep_m1;
+		bit_shift = macid - 32;
+	#endif
+	#if (MACID_NUM_SW_LIMIT > 64)
+	} else if (macid < 96) {
+		reg_sleep = macid_ctl->reg_sleep_m2;
+		bit_shift = macid - 64;
+	#endif
+	#if (MACID_NUM_SW_LIMIT > 96)
+	} else if (macid < 128) {
+		reg_sleep = macid_ctl->reg_sleep_m3;
+		bit_shift = macid - 96;
+	#endif
+	} else {
+		rtw_warn_on(1);
+		goto exit;
+	}
 
-	return _SUCCESS;
+	if (!reg_sleep) {
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	val32 = rtw_read32(adapter, reg_sleep);
+	RTW_INFO(ADPT_FMT" %s macid=%d, ori reg_0x%03x=0x%08x\n"
+		, ADPT_ARG(adapter), sleep ? "sleep" : "wakeup"
+		, macid, reg_sleep, val32);
+
+	ret = _SUCCESS;
+
+	if (sleep) {
+		if (val32 & BIT(bit_shift))
+			goto exit;
+		val32 |= BIT(bit_shift);
+	} else {
+		if (!(val32 & BIT(bit_shift)))
+			goto exit;
+		val32 &= ~BIT(bit_shift);
+	}
+
+	rtw_write32(adapter, reg_sleep, val32);
+
+exit:
+	return ret;
 }
 
-s32 rtw_hal_macid_wakeup(PADAPTER padapter, u8 macid)
+inline s32 rtw_hal_macid_sleep(_adapter *adapter, u8 macid)
 {
-	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
-	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
-	u8 support;
+	return _rtw_hal_macid_sleep(adapter, macid, 1);
+}
 
-	support = _FALSE;
-	rtw_hal_get_def_var(padapter, HAL_DEF_MACID_SLEEP, &support);
-	if (_FALSE == support)
-		return _FAIL;
+inline s32 rtw_hal_macid_wakeup(_adapter *adapter, u8 macid)
+{
+	return _rtw_hal_macid_sleep(adapter, macid, 0);
+}
 
-	if (macid >= macid_ctl->num) {
-		RTW_ERR(FUNC_ADPT_FMT": Invalid macid(%u)\n",
-			FUNC_ADPT_ARG(padapter), macid);
-		return _FAIL;
-	}
+static s32 _rtw_hal_macid_bmp_sleep(_adapter *adapter, struct macid_bmp *bmp, u8 sleep)
+{
+	struct macid_ctl_t *macid_ctl = adapter_to_macidctl(adapter);
+	u16 reg_sleep;
+	u32 m;
+	u8 mid = 0;
+	u32 val32;
+
+	do {
+		if (mid == 0) {
+			m = bmp->m0;
+			reg_sleep = macid_ctl->reg_sleep_m0;
+		#if (MACID_NUM_SW_LIMIT > 32)
+		} else if (mid == 1) {
+			m = bmp->m1;
+			reg_sleep = macid_ctl->reg_sleep_m1;
+		#endif
+		#if (MACID_NUM_SW_LIMIT > 64)
+		} else if (mid == 2) {
+			m = bmp->m2;
+			reg_sleep = macid_ctl->reg_sleep_m2;
+		#endif
+		#if (MACID_NUM_SW_LIMIT > 96)
+		} else if (mid == 3) {
+			m = bmp->m3;
+			reg_sleep = macid_ctl->reg_sleep_m3;
+		#endif
+		} else {
+			rtw_warn_on(1);
+			break;
+		}
+
+		if (m == 0)
+			goto move_next;
+
+		if (!reg_sleep) {
+			rtw_warn_on(1);
+			break;
+		}
+
+		val32 = rtw_read32(adapter, reg_sleep);
+		RTW_INFO(ADPT_FMT" %s m%u=0x%08x, ori reg_0x%03x=0x%08x\n"
+			, ADPT_ARG(adapter), sleep ? "sleep" : "wakeup"
+			, mid, m, reg_sleep, val32);
+
+		if (sleep) {
+			if ((val32 & m) == m)
+				goto move_next;
+			val32 |= m;
+		} else {
+			if ((val32 & m) == 0)
+				goto move_next;
+			val32 &= ~m;
+		}
+
+		rtw_write32(adapter, reg_sleep, val32);
 
-	rtw_hal_set_hwreg(padapter, HW_VAR_MACID_WAKEUP, &macid);
+move_next:
+		mid++;
+	} while (mid * 32 < MACID_NUM_SW_LIMIT);
 
 	return _SUCCESS;
 }
 
+inline s32 rtw_hal_macid_sleep_all_used(_adapter *adapter)
+{
+	struct macid_ctl_t *macid_ctl = adapter_to_macidctl(adapter);
+
+	return _rtw_hal_macid_bmp_sleep(adapter, &macid_ctl->used, 1);
+}
+
+inline s32 rtw_hal_macid_wakeup_all_used(_adapter *adapter)
+{
+	struct macid_ctl_t *macid_ctl = adapter_to_macidctl(adapter);
+
+	return _rtw_hal_macid_bmp_sleep(adapter, &macid_ctl->used, 0);
+}
+
 s32 rtw_hal_fill_h2c_cmd(PADAPTER padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer)
 {
 	_adapter *pri_adapter = GET_PRIMARY_ADAPTER(padapter);
 
-	if (pri_adapter->bFWReady == _TRUE)
+	if (GET_HAL_DATA(pri_adapter)->bFWReady == _TRUE)
 		return padapter->hal_func.fill_h2c_cmd(padapter, ElementID, CmdLen, pCmdBuffer);
 	else if (padapter->registrypriv.mp_mode == 0)
 		RTW_PRINT(FUNC_ADPT_FMT" FW doesn't exit when no MP mode, by pass H2C id:0x%02x\n"
@@ -1098,9 +1295,21 @@ void rtw_hal_fill_fake_txdesc(_adapter *padapter, u8 *pDesc, u32 BufferLen,
 	padapter->hal_func.fill_fake_txdesc(padapter, pDesc, BufferLen, IsPsPoll, IsBTQosNull, bDataFrame);
 
 }
+
 u8 rtw_hal_get_txbuff_rsvd_page_num(_adapter *adapter, bool wowlan)
 {
-	return adapter->hal_func.hal_get_tx_buff_rsvd_page_num(adapter, wowlan);
+	u8 num = 0;
+
+
+	if (adapter->hal_func.hal_get_tx_buff_rsvd_page_num) {
+		num = adapter->hal_func.hal_get_tx_buff_rsvd_page_num(adapter, wowlan);
+	} else {
+#ifdef RTW_HALMAC
+		num = GET_HAL_DATA(adapter)->drv_rsvd_page_number;
+#endif /* RTW_HALMAC */
+	}
+
+	return num;
 }
 
 #ifdef CONFIG_GPIO_API
@@ -1127,18 +1336,20 @@ void rtw_hal_gpio_multi_func_reset(_adapter *padapter, u8 gpio_num)
 }
 #endif
 
+#ifdef CONFIG_FW_CORRECT_BCN
 void rtw_hal_fw_correct_bcn(_adapter *padapter)
 {
 	if (padapter->hal_func.fw_correct_bcn)
 		padapter->hal_func.fw_correct_bcn(padapter);
 }
+#endif
 
-void rtw_hal_set_tx_power_index(PADAPTER padapter, u32 powerindex, u8 rfpath, u8 rate)
+void rtw_hal_set_tx_power_index(PADAPTER padapter, u32 powerindex, enum rf_path rfpath, u8 rate)
 {
 	return padapter->hal_func.set_tx_power_index_handler(padapter, powerindex, rfpath, rate);
 }
 
-u8 rtw_hal_get_tx_power_index(PADAPTER padapter, u8 rfpath, u8 rate, u8 bandwidth, u8 channel, struct txpwr_idx_comp *tic)
+u8 rtw_hal_get_tx_power_index(PADAPTER padapter, enum rf_path rfpath, u8 rate, u8 bandwidth, u8 channel, struct txpwr_idx_comp *tic)
 {
 	return padapter->hal_func.get_tx_power_index_handler(padapter, rfpath, rate, bandwidth, channel, tic);
 }
@@ -1171,6 +1382,21 @@ u8 rtw_hal_init_phy(PADAPTER adapter)
 }
 #endif /* RTW_HALMAC */
 
+#ifdef CONFIG_RFKILL_POLL
+bool rtw_hal_rfkill_poll(_adapter *adapter, u8 *valid)
+{
+	bool ret;
+
+	if (adapter->hal_func.hal_radio_onoff_check)
+		ret = adapter->hal_func.hal_radio_onoff_check(adapter, valid);
+	else {
+		*valid = 0;
+		ret = _FALSE;
+	}
+	return ret;
+}
+#endif
+
 #define rtw_hal_error_msg(ops_fun)		\
 	RTW_PRINT("### %s - Error : Please hook hal_func.%s ###\n", __FUNCTION__, ops_fun)
 
@@ -1320,12 +1546,6 @@ u8 rtw_hal_ops_check(_adapter *padapter)
 		rtw_hal_error_msg("hal_dm_watchdog");
 		ret = _FAIL;
 	}
-#ifdef CONFIG_LPS_LCLK_WD_TIMER
-	if (NULL == padapter->hal_func.hal_dm_watchdog_in_lps) {
-		rtw_hal_error_msg("hal_dm_watchdog_in_lps");
-		ret = _FAIL;
-	}
-#endif
 
 	/*** xxx section ***/
 	if (NULL == padapter->hal_func.set_chnl_bw_handler) {
@@ -1357,10 +1577,6 @@ u8 rtw_hal_ops_check(_adapter *padapter)
 		rtw_hal_error_msg("SetHalODMVarHandler");
 		ret = _FAIL;
 	}
-	if (NULL == padapter->hal_func.update_ra_mask_handler) {
-		rtw_hal_error_msg("update_ra_mask_handler");
-		ret = _FAIL;
-	}
 
 	if (NULL == padapter->hal_func.SetBeaconRelatedRegistersHandler) {
 		rtw_hal_error_msg("SetBeaconRelatedRegistersHandler");
@@ -1390,10 +1606,13 @@ u8 rtw_hal_ops_check(_adapter *padapter)
 		ret = _FAIL;
 	}
 #endif
+
+#ifndef RTW_HALMAC
 	if (NULL == padapter->hal_func.hal_get_tx_buff_rsvd_page_num) {
 		rtw_hal_error_msg("hal_get_tx_buff_rsvd_page_num");
 		ret = _FAIL;
 	}
+#endif /* !RTW_HALMAC */
 
 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
 #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
@@ -1416,20 +1635,18 @@ u8 rtw_hal_ops_check(_adapter *padapter)
 	}
 #endif
 
-	if ((IS_HARDWARE_TYPE_8814A(padapter)
-	     || IS_HARDWARE_TYPE_8822BU(padapter) || IS_HARDWARE_TYPE_8822BS(padapter))
+	#ifdef CONFIG_FW_CORRECT_BCN
+	if (IS_HARDWARE_TYPE_8814A(padapter)
 	    && NULL == padapter->hal_func.fw_correct_bcn) {
 		rtw_hal_error_msg("fw_correct_bcn");
 		ret = _FAIL;
 	}
+	#endif
 
-	if (IS_HARDWARE_TYPE_8822B(padapter) || IS_HARDWARE_TYPE_8821C(padapter)) {
-		if (!padapter->hal_func.set_tx_power_index_handler) {
-			rtw_hal_error_msg("set_tx_power_index_handler");
-			ret = _FAIL;
-		}
+	if (!padapter->hal_func.set_tx_power_index_handler) {
+		rtw_hal_error_msg("set_tx_power_index_handler");
+		ret = _FAIL;
 	}
-
 	if (!padapter->hal_func.get_tx_power_index_handler) {
 		rtw_hal_error_msg("get_tx_power_index_handler");
 		ret = _FAIL;
@@ -1477,6 +1694,13 @@ u8 rtw_hal_ops_check(_adapter *padapter)
 		ret = _FAIL;
 	}
 #endif /* RTW_HALMAC */
+
+#ifdef CONFIG_RFKILL_POLL
+	if (padapter->hal_func.hal_radio_onoff_check == NULL) {
+		rtw_hal_error_msg("hal_radio_onoff_check");
+		ret = _FAIL;
+	}
+#endif
 #endif
 	return  ret;
 }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 699 - 150
hal/hal_mcc.c


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 286 - 205
hal/hal_mp.c


+ 21 - 24
hal/hal_phy.c

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2017 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
@@ -11,22 +11,11 @@
  * 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
- *
- *
- ******************************************************************************/
+ *****************************************************************************/
 #define _HAL_PHY_C_
 
 #include <drv_types.h>
 
-/* ********************************************************************************
- *	Constant.
- * ********************************************************************************
- * 2008/11/20 MH For Debug only, RF */
-static RF_SHADOW_T RF_Shadow[RF6052_MAX_PATH][RF6052_MAX_REG];
-
 /**
 * Function:	PHY_CalculateBitShift
 *
@@ -54,6 +43,13 @@ PHY_CalculateBitShift(
 }
 
 
+#ifdef CONFIG_RF_SHADOW_RW
+/* ********************************************************************************
+ *	Constant.
+ * ********************************************************************************
+ * 2008/11/20 MH For Debug only, RF */
+static RF_SHADOW_T RF_Shadow[RF6052_MAX_PATH][RF6052_MAX_REG];
+
 /*
  * ==> RF shadow Operation API Code Section!!!
  *
@@ -85,7 +81,7 @@ PHY_CalculateBitShift(
 u32
 PHY_RFShadowRead(
 	IN	PADAPTER		Adapter,
-	IN	u8				eRFPath,
+	IN	enum rf_path		eRFPath,
 	IN	u32				Offset)
 {
 	return	RF_Shadow[eRFPath][Offset].Value;
@@ -96,7 +92,7 @@ PHY_RFShadowRead(
 VOID
 PHY_RFShadowWrite(
 	IN	PADAPTER		Adapter,
-	IN	u8				eRFPath,
+	IN	enum rf_path		eRFPath,
 	IN	u32				Offset,
 	IN	u32				Data)
 {
@@ -109,7 +105,7 @@ PHY_RFShadowWrite(
 BOOLEAN
 PHY_RFShadowCompare(
 	IN	PADAPTER		Adapter,
-	IN	u8				eRFPath,
+	IN	enum rf_path		eRFPath,
 	IN	u32				Offset)
 {
 	u32	reg;
@@ -130,7 +126,7 @@ PHY_RFShadowCompare(
 VOID
 PHY_RFShadowRecorver(
 	IN	PADAPTER		Adapter,
-	IN	u8				eRFPath,
+	IN	enum rf_path		eRFPath,
 	IN	u32				Offset)
 {
 	/* Check if the address is error */
@@ -149,7 +145,7 @@ VOID
 PHY_RFShadowCompareAll(
 	IN	PADAPTER			Adapter)
 {
-	u8		eRFPath = 0 ;
+	enum rf_path	eRFPath = RF_PATH_A;
 	u32		Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
 
 	for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
@@ -164,7 +160,7 @@ VOID
 PHY_RFShadowRecorverAll(
 	IN	PADAPTER			Adapter)
 {
-	u8		eRFPath = 0;
+	enum rf_path		eRFPath = RF_PATH_A;
 	u32		Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
 
 	for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
@@ -178,7 +174,7 @@ PHY_RFShadowRecorverAll(
 VOID
 PHY_RFShadowCompareFlagSet(
 	IN	PADAPTER		Adapter,
-	IN	u8				eRFPath,
+	IN	enum rf_path		eRFPath,
 	IN	u32				Offset,
 	IN	u8				Type)
 {
@@ -191,7 +187,7 @@ PHY_RFShadowCompareFlagSet(
 VOID
 PHY_RFShadowRecorverFlagSet(
 	IN	PADAPTER		Adapter,
-	IN	u8				eRFPath,
+	IN	enum rf_path		eRFPath,
 	IN	u32				Offset,
 	IN	u8				Type)
 {
@@ -205,7 +201,7 @@ VOID
 PHY_RFShadowCompareFlagSetAll(
 	IN	PADAPTER			Adapter)
 {
-	u8		eRFPath = 0;
+	enum rf_path	eRFPath = RF_PATH_A;
 	u32		Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
 
 	for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
@@ -225,7 +221,7 @@ VOID
 PHY_RFShadowRecorverFlagSetAll(
 	IN	PADAPTER			Adapter)
 {
-	u8		eRFPath = 0;
+	enum rf_path		eRFPath = RF_PATH_A;
 	u32		Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
 
 	for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
@@ -244,7 +240,7 @@ VOID
 PHY_RFShadowRefresh(
 	IN	PADAPTER			Adapter)
 {
-	u8		eRFPath = 0;
+	enum rf_path		eRFPath = RF_PATH_A;
 	u32		Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
 
 	for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
@@ -258,3 +254,4 @@ PHY_RFShadowRefresh(
 	}
 
 }	/* PHY_RFShadowRead */
+#endif /*CONFIG_RF_SHADOW_RW*/

+ 20 - 15
hal/halmac/halmac_2_platform.h

@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved.
+ * Copyright(c) 2015 - 2018 Realtek Corporation. All rights reserved.
  *
  * 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
@@ -11,12 +11,8 @@
  * 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
- *
- *
  ******************************************************************************/
+
 #ifndef _HALMAC_2_PLATFORM_H_
 #define _HALMAC_2_PLATFORM_H_
 
@@ -32,20 +28,18 @@
 #include <osdep_service.h>		/* __BIG_ENDIAN, __LITTLE_ENDIAN, _sema, _mutex */
 #endif
 
-/*[Driver] provide the define of _TRUE, _FALSE, NULL, u8, u16, u32*/
+/*[Driver] provide the define of NULL, u8, u16, u32*/
 #ifndef NULL
 #define NULL		((void *)0)
 #endif
 
 #define HALMAC_INLINE	inline
 
-typedef u8	*pu8;
-typedef u16	*pu16;
-typedef u32	*pu32;
-typedef s8	*ps8;
-typedef s16	*ps16;
-typedef s32	*ps32;
-
+/*
+ * Ignore following typedef because Linux already have these
+ * u8, u16, u32, s8, s16, s32
+ * __le16, __le32, __be16, __be32
+ */
 
 #define HALMAC_PLATFORM_LITTLE_ENDIAN	1
 #define HALMAC_PLATFORM_BIG_ENDIAN	0
@@ -70,9 +64,20 @@ typedef s32	*ps32;
 /*[Driver] config if enable the dbg msg or notl*/
 #define HALMAC_DBG_MSG_ENABLE		1
 
+#define HALMAC_MSG_LEVEL_TRACE		3
+#define HALMAC_MSG_LEVEL_WARNING	2
+#define HALMAC_MSG_LEVEL_ERR		1
+#define HALMAC_MSG_LEVEL_NO_LOG		0
+/*[Driver] config halmac msg level
+ * Use HALMAC_MSG_LEVEL_XXXX
+ */
+#define HALMAC_MSG_LEVEL HALMAC_MSG_LEVEL_TRACE
+
 /*[Driver] define the Rx FIFO expanding mode packet size unit for 8821C and 8822B */
 /*Should be 8 Byte alignment*/
-#define HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE	48 /*Bytes*/
+#define HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE	80 /*Bytes*/
+
+#define HALMAC_USE_TYPEDEF		0
 
 /*[Driver] provide the type mutex*/
 /* Mutex type */

+ 50 - 70
hal/halmac/halmac_88xx/halmac_8821c/halmac_8821c_cfg.h

@@ -1,85 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
 #ifndef _HALMAC_8821C_CFG_H_
 #define _HALMAC_8821C_CFG_H_
 
-#include "halmac_8821c_pwr_seq.h"
-#include "halmac_api_8821c.h"
-#include "halmac_api_8821c_usb.h"
-#include "halmac_api_8821c_pcie.h"
-#include "halmac_api_8821c_sdio.h"
-#include "../../halmac_bit2.h"
-#include "../../halmac_reg2.h"
-#include "../../halmac_api.h"
-
-#if HALMAC_PLATFORM_TESTPROGRAM
-#include "halmisc_api_8821c.h"
-#include "halmisc_api_8821c_usb.h"
-#include "halmisc_api_8821c_sdio.h"
-#include "halmisc_api_8821c_pcie.h"
-#endif
-
-#define HALMAC_TX_FIFO_SIZE_8821C				65536 /* 64k */
-#define HALMAC_TX_FIFO_SIZE_LA_8821C			32768 /* 32k */
-#define HALMAC_RX_FIFO_SIZE_8821C				16384 /* 16k */
-#define HALMAC_TX_PAGE_SIZE_8821C				128 /* PageSize 128Byte */
-#define HALMAC_TX_ALIGN_SIZE_8821C					8
-#define HALMAC_TX_PAGE_SIZE_2_POWER_8821C		7 /* 128 = 2^7 */
-#define HALMAC_SECURITY_CAM_ENTRY_NUM_8821C		64 /* CAM Entry Size */
-#define HALMAC_TX_DESC_SIZE_8821C				48
-#define HALMAC_RX_DESC_SIZE_8821C				24
-#define HALMAC_C2H_PKT_BUF_8821C		256
+#include "../../halmac_hw_cfg.h"
+#include "../halmac_88xx_cfg.h"
 
-#define HALMAC_RX_FIFO_EXPANDING_UNIT_8821C		(HALMAC_RX_DESC_SIZE_8821C + HALMAC_RX_DESC_DUMMY_SIZE_MAX_88XX + HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE) /* should be 8 Byte alignment*/
-#define HALMAC_RX_FIFO_EXPANDING_UNIT_MAX_8821C		(HALMAC_RX_DESC_SIZE_8821C + HALMAC_RX_DESC_DUMMY_SIZE_MAX_88XX + HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE_MAX_88XX) /* should be 8 Byte alignment*/
-#define HALMAC_TX_FIFO_SIZE_RX_FIFO_EXPANDING_1_BLOCK_8821C			32768 /* 32k */
-#define HALMAC_RX_FIFO_SIZE_RX_FIFO_EXPANDING_1_BLOCK_8821C			((((HALMAC_RX_FIFO_EXPANDING_UNIT_8821C << 8) - 1) >> 10) << 10) /*  < 48k*/
-#define HALMAC_RX_FIFO_SIZE_RX_FIFO_EXPANDING_1_BLOCK_MAX_8821C		((((HALMAC_RX_FIFO_EXPANDING_UNIT_MAX_8821C << 8) - 1) >> 10) << 10) /* 45k < 48k*/
+#if HALMAC_8821C_SUPPORT
 
-#define HALMAC_EFUSE_SIZE_8821C					512 /* 0x2000 */
-#define HALMAC_EEPROM_SIZE_8821C				0x200
-#define HALMAC_BT_EFUSE_SIZE_8821C				128
+#define TX_FIFO_SIZE_8821C	65536
+#define RX_FIFO_SIZE_8821C	16384
+#define TRX_SHARE_SIZE_8821C	32768
 
-#define HALMAC_CR_TRX_ENABLE_8821C      (BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | \
-					 BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | \
-					 BIT_MACTXEN | BIT_MACRXEN)
+#define RX_DESC_DUMMY_SIZE_8821C	72 /* 8 * 9 Bytes */
+#define RX_FIFO_EXPANDING_MODE_PKT_SIZE_MAX_8821C	80 /* 8 Byte alignment*/
 
-#define HALMAC_BLK_DESC_NUM_8821C   0x3 /* Only for USB */
-
-/* AMPDU max time (unit : 32us) */
-#define HALMAC_AMPDU_MAX_TIME_8821C		0x70
-
-/* Protect mode control */
-#define HALMAC_PROT_RTS_LEN_TH_8821C					0xFF
-#define HALMAC_PROT_RTS_TX_TIME_TH_8821C				0x08
-#define HALMAC_PROT_MAX_AGG_PKT_LIMIT_8821C				0x10
-#define HALMAC_PROT_RTS_MAX_AGG_PKT_LIMIT_8821C			0x10
-#define HALMAC_PROT_MAX_AGG_PKT_LIMIT_8821C_SDIO		0x2B
-#define HALMAC_PROT_RTS_MAX_AGG_PKT_LIMIT_8821C_SDIO	0x2B
+/* should be 8 Byte alignment*/
+#if (HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE <= \
+	RX_FIFO_EXPANDING_MODE_PKT_SIZE_MAX_8821C)
+#define RX_FIFO_EXPANDING_UNIT_8821C	(RX_DESC_SIZE_88XX + \
+	RX_DESC_DUMMY_SIZE_8821C + HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE)
+#else
+#define RX_FIFO_EXPANDING_UNIT_8821C	(RX_DESC_SIZE_88XX + \
+	RX_DESC_DUMMY_SIZE_8821C + RX_FIFO_EXPANDING_MODE_PKT_SIZE_MAX_8821C)
+#endif
 
-/* Fast EDCA setting */
-#define HALMAC_FAST_EDCA_VO_TH_8821C		0x06
-#define HALMAC_FAST_EDCA_VI_TH_8821C		0x06
-#define HALMAC_FAST_EDCA_BE_TH_8821C		0x06
-#define HALMAC_FAST_EDCA_BK_TH_8821C		0x06
+#define TX_FIFO_SIZE_LA_8821C	(TX_FIFO_SIZE_8821C >> 1)
+#define TX_FIFO_SIZE_RX_EXPAND_1BLK_8821C	\
+		(TX_FIFO_SIZE_8821C - TRX_SHARE_SIZE_8821C)
+#define RX_FIFO_SIZE_RX_EXPAND_1BLK_8821C	\
+		((((RX_FIFO_EXPANDING_UNIT_8821C << 8) - 1) >> 10) << 10)
 
-/* BAR setting */
-#define HALMAC_BAR_RETRY_LIMIT_8821C			0x01
-#define HALMAC_RA_TRY_RATE_AGG_LIMIT_8821C		0x08
+#define EFUSE_SIZE_8821C		512
+#define EEPROM_SIZE_8821C		512
+#define BT_EFUSE_SIZE_8821C		128
 
-typedef enum _HALMAC_NORMAL_RXAGG_TH_TO_8821C {
-	HALMAC_NORMAL_RXAGG_THRESHOLD_8821C = 0xFF,
-	HALMAC_NORMAL_RXAGG_TIMEOUT_8821C = 0x01,
-} HALMAC_NORMAL_RXAGG_TH_TO_8821C;
+#define SEC_CAM_NUM_8821C		64
 
-typedef enum _HALMAC_LOOPBACK_RXAGG_TH_TO_8821C {
-	HALMAC_LOOPBACK_RXAGG_THRESHOLD_8821C = 0xFF,
-	HALMAC_LOOPBACK_RXAGG_TIMEOUT_8821C = 0x01,
-} HALMAC_LOOPBACK_RXAGG_TH_TO_8821C;
+#define	OQT_ENTRY_AC_8821C		32
+#define OQT_ENTRY_NOAC_8821C		32
+#define MACID_MAX_8821C			128
 
-#define HALMAC_RSVD_DRV_PGNUM_8821C					16 /*2048*/
-#define HALMAC_RSVD_H2C_EXTRAINFO_PGNUM_8821C		32 /*4096*/
-#define HALMAC_RSVD_H2C_QUEUE_PGNUM_8821C			8 /*1024*/
-#define HALMAC_RSVD_CPU_INSTRUCTION_PGNUM_8821C		0 /*0*/
-#define HALMAC_RSVD_FW_TXBUFF_PGNUM_8821C			4 /*512*/
+#define WLAN_FW_IRAM_MAX_SIZE_8821C	65536
+#define WLAN_FW_DRAM_MAX_SIZE_8821C	49152
+#define WLAN_FW_ERAM_MAX_SIZE_8821C	49152
+#define WLAN_FW_MAX_SIZE_8821C		(WLAN_FW_IRAM_MAX_SIZE_8821C + \
+	WLAN_FW_DRAM_MAX_SIZE_8821C + WLAN_FW_ERAM_MAX_SIZE_8821C)
 
+#endif /* HALMAC_8821C_SUPPORT */
 
 #endif

+ 145 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_cfg_wmac_8821c.c

@@ -0,0 +1,145 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2017 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "halmac_cfg_wmac_8821c.h"
+#include "halmac_8821c_cfg.h"
+
+#if HALMAC_8821C_SUPPORT
+
+/**
+ * cfg_drv_info_8821c() - config driver info
+ * @adapter : the adapter of halmac
+ * @drv_info : driver information selection
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_drv_info_8821c(struct halmac_adapter *adapter,
+		   enum halmac_drv_info drv_info)
+{
+	u8 drv_info_size = 0;
+	u8 phy_status_en = 0;
+	u8 sniffer_en = 0;
+	u8 plcp_hdr_en = 0;
+	u8 value8;
+	u32 value32;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+	PLTFM_MSG_TRACE("[TRACE]drv info = %d\n", drv_info);
+
+	switch (drv_info) {
+	case HALMAC_DRV_INFO_NONE:
+		drv_info_size = 0;
+		phy_status_en = 0;
+		sniffer_en = 0;
+		plcp_hdr_en = 0;
+		break;
+	case HALMAC_DRV_INFO_PHY_STATUS:
+		drv_info_size = 4;
+		phy_status_en = 1;
+		sniffer_en = 0;
+		plcp_hdr_en = 0;
+		break;
+	case HALMAC_DRV_INFO_PHY_SNIFFER:
+		drv_info_size = 5; /* phy status 4byte, sniffer info 1byte */
+		phy_status_en = 1;
+		sniffer_en = 1;
+		plcp_hdr_en = 0;
+		break;
+	case HALMAC_DRV_INFO_PHY_PLCP:
+		drv_info_size = 6; /* phy status 4byte, plcp header 2byte */
+		phy_status_en = 1;
+		sniffer_en = 0;
+		plcp_hdr_en = 1;
+		break;
+	default:
+		return HALMAC_RET_SW_CASE_NOT_SUPPORT;
+	}
+
+	if (adapter->txff_alloc.rx_fifo_exp_mode !=
+	    HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE)
+		drv_info_size = RX_DESC_DUMMY_SIZE_8821C >> 3;
+
+	HALMAC_REG_W8(REG_RX_DRVINFO_SZ, drv_info_size);
+
+	value8 = HALMAC_REG_R8(REG_TRXFF_BNDY + 1);
+	value8 &= 0xF0;
+	/* For rxdesc len = 0 issue */
+	value8 |= 0xF;
+	HALMAC_REG_W8(REG_TRXFF_BNDY + 1, value8);
+
+	adapter->drv_info_size = drv_info_size;
+
+	value32 = HALMAC_REG_R32(REG_RCR);
+	value32 = (value32 & (~BIT_APP_PHYSTS));
+	if (phy_status_en == 1)
+		value32 = value32 | BIT_APP_PHYSTS;
+	HALMAC_REG_W32(REG_RCR, value32);
+
+	value32 = HALMAC_REG_R32(REG_WMAC_OPTION_FUNCTION + 4);
+	value32 = (value32 & (~(BIT(8) | BIT(9))));
+	if (sniffer_en == 1)
+		value32 = value32 | BIT(9);
+	if (plcp_hdr_en == 1)
+		value32 = value32 | BIT(8);
+	HALMAC_REG_W32(REG_WMAC_OPTION_FUNCTION + 4, value32);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * init_low_pwr_8821c() - config WMAC register
+ * @adapter
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+init_low_pwr_8821c(struct halmac_adapter *adapter)
+{
+	return HALMAC_RET_SUCCESS;
+}
+
+void
+cfg_rx_ignore_8821c(struct halmac_adapter *adapter,
+		    struct halmac_mac_rx_ignore_cfg *cfg)
+{
+}
+
+enum halmac_ret_status
+cfg_ampdu_8821c(struct halmac_adapter *adapter,
+		struct halmac_ampdu_config *cfg)
+{
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	if (cfg->ht_max_len != cfg->vht_max_len) {
+		PLTFM_MSG_ERR("[ERR]max len ht != vht!!\n");
+		return HALMAC_RET_PARA_NOT_SUPPORT;
+	}
+
+	HALMAC_REG_W8(REG_PROT_MODE_CTRL + 2, cfg->max_agg_num);
+	HALMAC_REG_W8(REG_PROT_MODE_CTRL + 3, cfg->max_agg_num);
+
+	if (cfg->max_len_en == 1)
+		HALMAC_REG_W32(REG_AMPDU_MAX_LENGTH, cfg->ht_max_len);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+#endif /* HALMAC_8821C_SUPPORT */

+ 40 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_cfg_wmac_8821c.h

@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2017 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#ifndef _HALMAC_CFG_WMAC_8821C_H_
+#define _HALMAC_CFG_WMAC_8821C_H_
+
+#include "../../halmac_api.h"
+
+#if HALMAC_8821C_SUPPORT
+
+enum halmac_ret_status
+cfg_drv_info_8821c(struct halmac_adapter *adapter,
+		   enum halmac_drv_info drv_info);
+
+enum halmac_ret_status
+init_low_pwr_8821c(struct halmac_adapter *adapter);
+
+void
+cfg_rx_ignore_8821c(struct halmac_adapter *adapter,
+		    struct halmac_mac_rx_ignore_cfg *cfg);
+
+enum halmac_ret_status
+cfg_ampdu_8821c(struct halmac_adapter *adapter,
+		struct halmac_ampdu_config *cfg);
+
+#endif/* HALMAC_8821C_SUPPORT */
+
+#endif/* _HALMAC_CFG_WMAC_8821C_H_ */

+ 182 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_common_8821c.c

@@ -0,0 +1,182 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2017 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "halmac_8821c_cfg.h"
+#include "halmac_common_8821c.h"
+#include "../halmac_common_88xx.h"
+#include "halmac_cfg_wmac_8821c.h"
+#if HALMAC_PCIE_SUPPORT
+#include "halmac_pcie_8821c.h"
+#endif
+
+#if HALMAC_8821C_SUPPORT
+
+static void
+cfg_ldo25_8821c(struct halmac_adapter *adapter, u8 enable);
+
+/**
+ * get_hw_value_8821c() -get hw config value
+ * @adapter : the adapter of halmac
+ * @hw_id : hw id for driver to query
+ * @value : hw value, reference table to get data type
+ * Author : KaiYuan Chang / Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+get_hw_value_8821c(struct halmac_adapter *adapter, enum halmac_hw_id hw_id,
+		   void *value)
+{
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (!value) {
+		PLTFM_MSG_ERR("[ERR]null pointer\n");
+		return HALMAC_RET_NULL_POINTER;
+	}
+
+	if (get_hw_value_88xx(adapter, hw_id, value) == HALMAC_RET_SUCCESS)
+		return HALMAC_RET_SUCCESS;
+
+	switch (hw_id) {
+	case HALMAC_HW_FW_MAX_SIZE:
+		*(u32 *)value = WLAN_FW_MAX_SIZE_8821C;
+		break;
+	case HALMAC_HW_SDIO_INT_LAT:
+		break;
+	case HALMAC_HW_SDIO_CLK_CNT:
+		break;
+	default:
+		return HALMAC_RET_PARA_NOT_SUPPORT;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * set_hw_value_8821c() -set hw config value
+ * @adapter : the adapter of halmac
+ * @hw_id : hw id for driver to config
+ * @value : hw value, reference table to get data type
+ * Author : KaiYuan Chang / Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+set_hw_value_8821c(struct halmac_adapter *adapter, enum halmac_hw_id hw_id,
+		   void *value)
+{
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (!value) {
+		PLTFM_MSG_ERR("[ERR]null pointer\n");
+		return HALMAC_RET_NULL_POINTER;
+	}
+
+	if (set_hw_value_88xx(adapter, hw_id, value) == HALMAC_RET_SUCCESS)
+		return HALMAC_RET_SUCCESS;
+
+	switch (hw_id) {
+	case HALMAC_HW_AMPDU_CONFIG:
+		status = cfg_ampdu_8821c(adapter,
+					 (struct halmac_ampdu_config *)value);
+		break;
+	case HALMAC_HW_SDIO_TX_FORMAT:
+		break;
+	case HALMAC_HW_RXGCK_FIFO:
+		break;
+	case HALMAC_HW_RX_IGNORE:
+		break;
+	case HALMAC_HW_LDO25_EN:
+		cfg_ldo25_8821c(adapter, *(u8 *)value);
+		break;
+#if HALMAC_PCIE_SUPPORT
+	case HALMAC_HW_PCIE_REF_AUTOK:
+		if (adapter->intf != HALMAC_INTERFACE_PCIE)
+			return HALMAC_RET_WRONG_INTF;
+		status = auto_refclk_cal_8821c_pcie(adapter);
+		if (status != HALMAC_RET_SUCCESS)
+			return status;
+		break;
+#endif
+	case HALMAC_HW_SDIO_WT_EN:
+		break;
+	case HALMAC_HW_SDIO_CLK_MONITOR:
+		break;
+	default:
+		return HALMAC_RET_PARA_NOT_SUPPORT;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return status;
+}
+
+/**
+ * halmac_fill_txdesc_check_sum_88xx() -  fill in tx desc check sum
+ * @adapter : the adapter of halmac
+ * @txdesc : tx desc packet
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+fill_txdesc_check_sum_8821c(struct halmac_adapter *adapter, u8 *txdesc)
+{
+	__le16 chksum = 0;
+	__le16 *data;
+	u32 i;
+
+	if (!txdesc) {
+		PLTFM_MSG_ERR("[ERR]null pointer\n");
+		return HALMAC_RET_NULL_POINTER;
+	}
+
+	if (adapter->tx_desc_checksum != 1)
+		PLTFM_MSG_TRACE("[TRACE]chksum disable\n");
+
+	SET_TX_DESC_TXDESC_CHECKSUM(txdesc, 0x0000);
+
+	data = (__le16 *)(txdesc);
+
+	/* HW clculates only 32byte */
+	for (i = 0; i < 8; i++)
+		chksum ^= (*(data + 2 * i) ^ *(data + (2 * i + 1)));
+
+	/* *(data + 2 * i) & *(data + (2 * i + 1) have endain issue*/
+	/* Process eniadn issue after checksum calculation */
+	SET_TX_DESC_TXDESC_CHECKSUM(txdesc, rtk_le16_to_cpu(chksum));
+
+	return HALMAC_RET_SUCCESS;
+}
+
+static void
+cfg_ldo25_8821c(struct halmac_adapter *adapter, u8 enable)
+{
+	u8 value8;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	value8 = HALMAC_REG_R8(REG_LDO_EFUSE_CTRL + 3);
+
+	if (enable == 1)
+		HALMAC_REG_W8(REG_LDO_EFUSE_CTRL + 3, (u8)(value8 | BIT(7)));
+	else
+		HALMAC_REG_W8(REG_LDO_EFUSE_CTRL + 3, (u8)(value8 & ~BIT(7)));
+}
+
+#endif /* HALMAC_8821C_SUPPORT */

+ 36 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_common_8821c.h

@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2017 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#ifndef _HALMAC_COMMON_8821C_H_
+#define _HALMAC_COMMON_8821C_H_
+
+#include "../../halmac_api.h"
+
+#if HALMAC_8821C_SUPPORT
+
+enum halmac_ret_status
+get_hw_value_8821c(struct halmac_adapter *adapter, enum halmac_hw_id hw_id,
+		   void *value);
+
+enum halmac_ret_status
+set_hw_value_8821c(struct halmac_adapter *adapter, enum halmac_hw_id hw_id,
+		   void *value);
+
+enum halmac_ret_status
+fill_txdesc_check_sum_8821c(struct halmac_adapter *adapter, u8 *txdesc);
+
+#endif/* HALMAC_8821C_SUPPORT */
+
+#endif/* _HALMAC_COMMON_8821C_H_ */

+ 846 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_gpio_8821c.c

@@ -0,0 +1,846 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "halmac_gpio_8821c.h"
+#include "../halmac_gpio_88xx.h"
+
+#if HALMAC_8821C_SUPPORT
+
+/* P_LED0 definition */
+#define GPIO0_BT_GPIO0_8821C	\
+	{HALMAC_BT_GPIO, HALMAC_GPIO0, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(2), BIT(2)}
+#define GPIO0_BT_GPIO0_8821C	\
+	{HALMAC_BT_GPIO, HALMAC_GPIO0, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(2), BIT(2)}
+#define GPIO0_BT_ACT_8821C	\
+	{HALMAC_BT_PTA, HALMAC_GPIO0, HALMAC_GPIO_IN_OUT, \
+	 0x41, BIT(1), 0}
+#define GPIO0_WL_ACT_8821C	\
+	{HALMAC_WL_PTA, HALMAC_GPIO0, HALMAC_GPIO_IN_OUT, \
+	 0x41, BIT(2), BIT(2)}
+#define GPIO0_WLMAC_DBG_GPIO0_8821C	\
+	{HALMAC_WLMAC_DBG, HALMAC_GPIO0, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0)}
+#define GPIO0_WLPHY_DBG_GPIO0_8821C	\
+	{HALMAC_WLPHY_DBG, HALMAC_GPIO0, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(1)}
+#define GPIO0_BT_DBG_GPIO0_8821C	\
+	{HALMAC_BT_DBG, HALMAC_GPIO0, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0) | BIT(1)}
+#define GPIO0_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO0, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO1 definition */
+#define GPIO1_BT_GPIO1_8821C	\
+	{HALMAC_BT_GPIO, HALMAC_GPIO1, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(2), BIT(2)}
+#define GPIO1_BT_3DD_SYNC_A_8821C	\
+	{HALMAC_BT_3DDLS_A, HALMAC_GPIO1, HALMAC_GPIO_IN, \
+	 0x66, BIT(2), BIT(2)}
+#define GPIO1_WL_CK_8821C	\
+	{HALMAC_BT_PTA, HALMAC_GPIO1, HALMAC_GPIO_OUT, \
+	 0x41, BIT(1), 0}
+#define GPIO1_BT_CK_8821C	\
+	{HALMAC_WL_PTA, HALMAC_GPIO1, HALMAC_GPIO_OUT, \
+	 0x41, BIT(2), BIT(2)}
+#define GPIO1_WLMAC_DBG_GPIO1_8821C	\
+	{HALMAC_WLMAC_DBG, HALMAC_GPIO1, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0)}
+#define GPIO1_WLPHY_DBG_GPIO1_8821C	\
+	{HALMAC_WLPHY_DBG, HALMAC_GPIO1, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(1)}
+#define GPIO1_BT_DBG_GPIO1_8821C	\
+	{HALMAC_BT_DBG, HALMAC_GPIO1, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0) | BIT(1)}
+#define GPIO1_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO1, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO2 definition */
+#define GPIO2_BT_GPIO2_8821C	\
+	{HALMAC_BT_GPIO, HALMAC_GPIO2, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(2), BIT(2)}
+#define GPIO2_WL_STATE_8821C	\
+	{HALMAC_BT_PTA, HALMAC_GPIO2, HALMAC_GPIO_OUT, \
+	 0x41, BIT(1), 0}
+#define GPIO2_BT_STATE_8821C	\
+	{HALMAC_WL_PTA, HALMAC_GPIO2, HALMAC_GPIO_OUT, \
+	 0x41, BIT(2), BIT(2)}
+#define GPIO2_WLMAC_DBG_GPIO2_8821C	\
+	{HALMAC_WLMAC_DBG, HALMAC_GPIO2, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0)}
+#define GPIO2_WLPHY_DBG_GPIO2_8821C	\
+	{HALMAC_WLPHY_DBG, HALMAC_GPIO2, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(1)}
+#define GPIO2_BT_DBG_GPIO2_8821C	\
+	{HALMAC_BT_DBG, HALMAC_GPIO2, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0) | BIT(1)}
+#define GPIO2_RFE_CTRL_5_8821C	\
+	{HALMAC_WLPHY_RFE_CTRL2GPIO, HALMAC_GPIO2, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(2), BIT(2)}
+#define GPIO2_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO2, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO3 definition */
+#define GPIO3_BT_GPIO3_8821C	\
+	{HALMAC_BT_GPIO, HALMAC_GPIO3, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(2), BIT(2)}
+#define GPIO3_WL_PRI_8821C	\
+	{HALMAC_BT_PTA, HALMAC_GPIO3, HALMAC_GPIO_OUT, \
+	 0x41, BIT(1), 0}
+#define GPIO3_BT_PRI_8821C	\
+	{HALMAC_WL_PTA, HALMAC_GPIO3, HALMAC_GPIO_OUT, \
+	 0x41, BIT(2), BIT(2)}
+#define GPIO3_WLMAC_DBG_GPIO3_8821C	\
+	{HALMAC_WLMAC_DBG, HALMAC_GPIO3, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0)}
+#define GPIO3_WLPHY_DBG_GPIO3_8821C	\
+	{HALMAC_WLPHY_DBG, HALMAC_GPIO3, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(1)}
+#define GPIO3_BT_DBG_GPIO3_8821C	\
+	{HALMAC_BT_DBG, HALMAC_GPIO3, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0) | BIT(1)}
+#define GPIO3_RFE_CTRL_4_8821C	\
+	{HALMAC_WLPHY_RFE_CTRL2GPIO, HALMAC_GPIO3, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(2), BIT(2)}
+#define GPIO3_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO3, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO4 definition */
+#define GPIO4_BT_SPI_D0_8821C	\
+	{HALMAC_BT_SFLASH, HALMAC_GPIO4, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(4), BIT(4)}
+#define GPIO4_WL_SPI_D0_8821C	\
+	{HALMAC_WL_SFLASH, HALMAC_GPIO4, HALMAC_GPIO_IN_OUT, \
+	 0x42, BIT(3), BIT(3)}
+#define GPIO4_SDIO_INT_8821C	\
+	{HALMAC_SDIO_INT, HALMAC_GPIO4, HALMAC_GPIO_OUT, \
+	 0x72, BIT(2), BIT(2)}
+#define GPIO4_JTAG_TRST_8821C	\
+	{HALMAC_JTAG, HALMAC_GPIO4, HALMAC_GPIO_IN, \
+	 0x67, BIT(0), BIT(0)}
+#define GPIO4_DBG_GNT_WL_8821C	\
+	{HALMAC_DBG_GNT_WL_BT, HALMAC_GPIO4, HALMAC_GPIO_OUT, \
+	 0x73, BIT(3), BIT(3)}
+#define GPIO4_WLMAC_DBG_GPIO4_8821C	\
+	{HALMAC_WLMAC_DBG, HALMAC_GPIO4, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0)}
+#define GPIO4_WLPHY_DBG_GPIO4_8821C	\
+	{HALMAC_WLPHY_DBG, HALMAC_GPIO4, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(1)}
+#define GPIO4_BT_DBG_GPIO4_8821C	\
+	{HALMAC_BT_DBG, HALMAC_GPIO4, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0) | BIT(1)}
+#define GPIO4_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO4, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO5 definition */
+#define GPIO5_BT_SPI_D1_8821C	\
+	{HALMAC_BT_SFLASH, HALMAC_GPIO5, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(4), BIT(4)}
+#define GPIO5_WL_SPI_D1_8821C	\
+	{HALMAC_WL_SFLASH, HALMAC_GPIO5, HALMAC_GPIO_IN_OUT, \
+	 0x42, BIT(3), BIT(3)}
+#define GPIO5_JTAG_TDI_8821C	\
+	{HALMAC_JTAG, HALMAC_GPIO5, HALMAC_GPIO_IN, \
+	 0x67, BIT(0), BIT(0)}
+#define GPIO5_DBG_GNT_BT_8821C	\
+	{HALMAC_DBG_GNT_WL_BT, HALMAC_GPIO5, HALMAC_GPIO_OUT, \
+	 0x73, BIT(3), BIT(3)}
+#define GPIO5_WLMAC_DBG_GPIO5_8821C	\
+	{HALMAC_WLMAC_DBG, HALMAC_GPIO5, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0)}
+#define GPIO5_WLPHY_DBG_GPIO5_8821C	\
+	{HALMAC_WLPHY_DBG, HALMAC_GPIO5, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(1)}
+#define GPIO5_BT_DBG_GPIO5_8821C	\
+	{HALMAC_BT_DBG, HALMAC_GPIO5, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0) | BIT(1)}
+#define GPIO5_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO5, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO6 definition */
+#define GPIO6_BT_SPI_D2_8821C	\
+	{HALMAC_BT_SFLASH, HALMAC_GPIO6, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(4), BIT(4)}
+#define GPIO6_WL_SPI_D2_8821C	\
+	{HALMAC_WL_SFLASH, HALMAC_GPIO6, HALMAC_GPIO_IN_OUT, \
+	 0x42, BIT(3), BIT(3)}
+#define GPIO6_EEDO_8821C	\
+	{HALMAC_EEPROM, HALMAC_GPIO6, HALMAC_GPIO_IN, \
+	 0x40, BIT(4), BIT(4)}
+#define GPIO6_JTAG_TDO_8821C	\
+	{HALMAC_JTAG, HALMAC_GPIO6, HALMAC_GPIO_OUT, \
+	 0x67, BIT(0), BIT(0)}
+#define GPIO6_BT_3DD_SYNC_B_8821C	\
+	{HALMAC_BT_3DDLS_B, HALMAC_GPIO6, HALMAC_GPIO_IN, \
+	 0x67, BIT(1), BIT(1)}
+#define GPIO6_BT_GPIO18_8821C	\
+	{HALMAC_BT_GPIO, HALMAC_GPIO6, HALMAC_GPIO_IN_OUT, \
+	 0x67, BIT(1), BIT(1)}
+#define GPIO6_SIN_8821C	\
+	{HALMAC_WL_UART, HALMAC_GPIO6, HALMAC_GPIO_IN, \
+	 0x41, BIT(0), BIT(0)}
+#define GPIO6_WLMAC_DBG_GPIO6_8821C	\
+	{HALMAC_WLMAC_DBG, HALMAC_GPIO6, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0)}
+#define GPIO6_WLPHY_DBG_GPIO6_8821C	\
+	{HALMAC_WLPHY_DBG, HALMAC_GPIO6, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(1)}
+#define GPIO6_BT_DBG_GPIO6_8821C	\
+	{HALMAC_BT_DBG, HALMAC_GPIO6, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0) | BIT(1)}
+#define GPIO6_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO6, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO7 definition */
+#define GPIO7_BT_SPI_D3_8821C	\
+	{HALMAC_BT_SFLASH, HALMAC_GPIO7, HALMAC_GPIO_IN_OUT, \
+	 0x66, BIT(4), BIT(4)}
+#define GPIO7_WL_SPI_D3_8821C	\
+	{HALMAC_WL_SFLASH, HALMAC_GPIO7, HALMAC_GPIO_IN_OUT, \
+	 0x42, BIT(3), BIT(3)}
+#define GPIO7_EEDI_8821C	\
+	{HALMAC_EEPROM, HALMAC_GPIO7, HALMAC_GPIO_OUT, \
+	 0x40, BIT(4), BIT(4)}
+#define GPIO7_JTAG_TMS_8821C	\
+	{HALMAC_JTAG, HALMAC_GPIO7, HALMAC_GPIO_IN, \
+	 0x67, BIT(0), BIT(0)}
+#define GPIO7_BT_GPIO16_8821C	\
+	{HALMAC_BT_GPIO, HALMAC_GPIO7, HALMAC_GPIO_IN_OUT, \
+	 0x67, BIT(2), BIT(2)}
+#define GPIO7_SOUT_8821C	\
+	{HALMAC_WL_UART, HALMAC_GPIO7, HALMAC_GPIO_OUT, \
+	 0x41, BIT(0), BIT(0)}
+#define GPIO7_WLMAC_DBG_GPIO7_8821C	\
+	{HALMAC_WLMAC_DBG, HALMAC_GPIO7, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0)}
+#define GPIO7_WLPHY_DBG_GPIO7_8821C	\
+	{HALMAC_WLPHY_DBG, HALMAC_GPIO7, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(1)}
+#define GPIO7_BT_DBG_GPIO7_8821C	\
+	{HALMAC_BT_DBG, HALMAC_GPIO7, HALMAC_GPIO_OUT, \
+	 0x40, BIT(1) | BIT(0), BIT(0) | BIT(1)}
+#define GPIO7_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO7, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO8 definition */
+#define GPIO8_WL_EXT_WOL_8821C	\
+	{HALMAC_WL_HW_EXTWOL, HALMAC_GPIO8, HALMAC_GPIO_IN, \
+	 0x4a, BIT(0) | BIT(1), BIT(0) | BIT(1)}
+#define GPIO8_WL_LED_8821C	\
+	{HALMAC_WL_LED, HALMAC_GPIO8, HALMAC_GPIO_OUT, \
+	 0x4e, BIT(5), BIT(5)}
+#define GPIO8_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO8, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO9 definition */
+#define GPIO9_DIS_WL_N_8821C	\
+	{HALMAC_WL_HWPDN, HALMAC_GPIO9, HALMAC_GPIO_IN, \
+	 0x68, BIT(3) | BIT(0), BIT(3) | BIT(0)}
+#define GPIO9_WL_EXT_WOL_8821C	\
+	{HALMAC_WL_HW_EXTWOL, HALMAC_GPIO9, HALMAC_GPIO_IN, \
+	 0x4a, BIT(0) | BIT(1), BIT(0)}
+#define GPIO9_USCTS0_8821C	\
+	{HALMAC_UART0, HALMAC_GPIO9, HALMAC_GPIO_IN, \
+	 0x66, BIT(6), BIT(6)}
+#define GPIO9_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO9, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO10 definition */
+#define GPIO10_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO10, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO11 definition */
+#define GPIO11_DIS_BT_N_8821C	\
+	{HALMAC_BT_HWPDN, HALMAC_GPIO11, HALMAC_GPIO_IN, \
+	 0x6a, BIT(0), BIT(0)}
+#define GPIO11_USOUT0_8821C	\
+	{HALMAC_UART0, HALMAC_GPIO11, HALMAC_GPIO_OUT, \
+	 0x66, BIT(6), BIT(6)}
+#define GPIO11_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO11, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO12 definition */
+#define GPIO12_USIN0_8821C	\
+	{HALMAC_UART0, HALMAC_GPIO12, HALMAC_GPIO_IN, \
+	 0x66, BIT(6), BIT(6)}
+#define GPIO12_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO12, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO13 definition */
+#define GPIO13_BT_WAKE_8821C	\
+	{HALMAC_GPIO13_14_WL_CTRL_EN, HALMAC_GPIO13, HALMAC_GPIO_IN, \
+	 0x4e, BIT(6), BIT(6)}
+#define GPIO13_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO13, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO14 definition */
+#define GPIO14_UART_WAKE_8821C	\
+	{HALMAC_GPIO13_14_WL_CTRL_EN, HALMAC_GPIO14, HALMAC_GPIO_OUT, \
+	 0x4e, BIT(6), BIT(6)}
+#define GPIO14_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO14, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+/* GPIO15 definition */
+#define GPIO15_EXT_XTAL_8821C	\
+	{HALMAC_EXT_XTAL, HALMAC_GPIO15, HALMAC_GPIO_OUT, \
+	 0x66, BIT(7), BIT(7)}
+#define GPIO15_SW_IO_8821C	\
+	{HALMAC_SW_IO, HALMAC_GPIO15, HALMAC_GPIO_IN_OUT, \
+	 0x40, BIT(1) | BIT(0), 0}
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO0_8821C[] = {
+	GPIO0_BT_GPIO0_8821C,
+	GPIO0_BT_ACT_8821C,
+	GPIO0_WL_ACT_8821C,
+	GPIO0_WLMAC_DBG_GPIO0_8821C,
+	GPIO0_WLPHY_DBG_GPIO0_8821C,
+	GPIO0_BT_DBG_GPIO0_8821C,
+	GPIO0_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO1_8821C[] = {
+	GPIO1_BT_GPIO1_8821C,
+	GPIO1_BT_3DD_SYNC_A_8821C,
+	GPIO1_WL_CK_8821C,
+	GPIO1_BT_CK_8821C,
+	GPIO1_WLMAC_DBG_GPIO1_8821C,
+	GPIO1_WLPHY_DBG_GPIO1_8821C,
+	GPIO1_BT_DBG_GPIO1_8821C,
+	GPIO1_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO2_8821C[] = {
+	GPIO2_BT_GPIO2_8821C,
+	GPIO2_WL_STATE_8821C,
+	GPIO2_BT_STATE_8821C,
+	GPIO2_WLMAC_DBG_GPIO2_8821C,
+	GPIO2_WLPHY_DBG_GPIO2_8821C,
+	GPIO2_BT_DBG_GPIO2_8821C,
+	GPIO2_RFE_CTRL_5_8821C,
+	GPIO2_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO3_8821C[] = {
+	GPIO3_BT_GPIO3_8821C,
+	GPIO3_WL_PRI_8821C,
+	GPIO3_BT_PRI_8821C,
+	GPIO3_WLMAC_DBG_GPIO3_8821C,
+	GPIO3_WLPHY_DBG_GPIO3_8821C,
+	GPIO3_BT_DBG_GPIO3_8821C,
+	GPIO3_RFE_CTRL_4_8821C,
+	GPIO3_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO4_8821C[] = {
+	GPIO4_BT_SPI_D0_8821C,
+	GPIO4_WL_SPI_D0_8821C,
+	GPIO4_SDIO_INT_8821C,
+	GPIO4_JTAG_TRST_8821C,
+	GPIO4_DBG_GNT_WL_8821C,
+	GPIO4_WLMAC_DBG_GPIO4_8821C,
+	GPIO4_WLPHY_DBG_GPIO4_8821C,
+	GPIO4_BT_DBG_GPIO4_8821C,
+	GPIO4_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO5_8821C[] = {
+	GPIO5_BT_SPI_D1_8821C,
+	GPIO5_WL_SPI_D1_8821C,
+	GPIO5_JTAG_TDI_8821C,
+	GPIO5_DBG_GNT_BT_8821C,
+	GPIO5_WLMAC_DBG_GPIO5_8821C,
+	GPIO5_WLPHY_DBG_GPIO5_8821C,
+	GPIO5_BT_DBG_GPIO5_8821C,
+	GPIO5_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO6_8821C[] = {
+	GPIO6_BT_SPI_D2_8821C,
+	GPIO6_WL_SPI_D2_8821C,
+	GPIO6_EEDO_8821C,
+	GPIO6_JTAG_TDO_8821C,
+	GPIO6_BT_3DD_SYNC_B_8821C,
+	GPIO6_BT_GPIO18_8821C,
+	GPIO6_SIN_8821C,
+	GPIO6_WLMAC_DBG_GPIO6_8821C,
+	GPIO6_WLPHY_DBG_GPIO6_8821C,
+	GPIO6_BT_DBG_GPIO6_8821C,
+	GPIO6_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO7_8821C[] = {
+	GPIO7_BT_SPI_D3_8821C,
+	GPIO7_WL_SPI_D3_8821C,
+	GPIO7_EEDI_8821C,
+	GPIO7_JTAG_TMS_8821C,
+	GPIO7_BT_GPIO16_8821C,
+	GPIO7_SOUT_8821C,
+	GPIO7_WLMAC_DBG_GPIO7_8821C,
+	GPIO7_WLPHY_DBG_GPIO7_8821C,
+	GPIO7_BT_DBG_GPIO7_8821C,
+	GPIO7_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO8_8821C[] = {
+	GPIO8_WL_EXT_WOL_8821C,
+	GPIO8_WL_LED_8821C,
+	GPIO8_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO9_8821C[] = {
+	GPIO9_DIS_WL_N_8821C,
+	GPIO9_WL_EXT_WOL_8821C,
+	GPIO9_USCTS0_8821C,
+	GPIO9_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO10_8821C[] = {
+	GPIO10_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO11_8821C[] = {
+	GPIO11_DIS_BT_N_8821C,
+	GPIO11_USOUT0_8821C,
+	GPIO11_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO12_8821C[] = {
+	GPIO12_USIN0_8821C,
+	GPIO12_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO13_8821C[] = {
+	GPIO13_BT_WAKE_8821C,
+	GPIO13_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO14_8821C[] = {
+	GPIO14_UART_WAKE_8821C,
+	GPIO14_SW_IO_8821C
+};
+
+static const struct halmac_gpio_pimux_list PINMUX_LIST_GPIO15_8821C[] = {
+	GPIO15_EXT_XTAL_8821C,
+	GPIO15_SW_IO_8821C
+};
+
+static enum halmac_ret_status
+get_pinmux_list_8821c(struct halmac_adapter *adapter,
+		      enum halmac_gpio_func gpio_func,
+		      const struct halmac_gpio_pimux_list **list,
+		      u32 *list_size, u32 *gpio_id);
+
+static enum halmac_ret_status
+chk_pinmux_valid_8821c(struct halmac_adapter *adapter,
+		       enum halmac_gpio_func gpio_func);
+
+/**
+ * pinmux_get_func_8821c() -get current gpio status
+ * @adapter : the adapter of halmac
+ * @gpio_func : gpio function
+ * @enable : function is enable(1) or disable(0)
+ * Author : Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+pinmux_get_func_8821c(struct halmac_adapter *adapter,
+		      enum halmac_gpio_func gpio_func, u8 *enable)
+{
+	u32 list_size;
+	u32 cur_func;
+	u32 gpio_id;
+	enum halmac_ret_status status;
+	const struct halmac_gpio_pimux_list *list = NULL;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	status = get_pinmux_list_8821c(adapter, gpio_func, &list, &list_size,
+				       &gpio_id);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	status = pinmux_parser_88xx(adapter, list, list_size, gpio_id,
+				    &cur_func);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	switch (gpio_func) {
+	case HALMAC_GPIO_FUNC_WL_LED:
+		*enable = (cur_func == HALMAC_WL_LED) ? 1 : 0;
+		break;
+	case HALMAC_GPIO_FUNC_SDIO_INT:
+		*enable = (cur_func == HALMAC_SDIO_INT) ? 1 : 0;
+		break;
+	case HALMAC_GPIO_FUNC_BT_HOST_WAKE1:
+	case HALMAC_GPIO_FUNC_BT_DEV_WAKE1:
+		*enable = (cur_func == HALMAC_GPIO13_14_WL_CTRL_EN) ? 1 : 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_0:
+	case HALMAC_GPIO_FUNC_SW_IO_1:
+	case HALMAC_GPIO_FUNC_SW_IO_2:
+	case HALMAC_GPIO_FUNC_SW_IO_3:
+	case HALMAC_GPIO_FUNC_SW_IO_4:
+	case HALMAC_GPIO_FUNC_SW_IO_5:
+	case HALMAC_GPIO_FUNC_SW_IO_6:
+	case HALMAC_GPIO_FUNC_SW_IO_7:
+	case HALMAC_GPIO_FUNC_SW_IO_8:
+	case HALMAC_GPIO_FUNC_SW_IO_9:
+	case HALMAC_GPIO_FUNC_SW_IO_10:
+	case HALMAC_GPIO_FUNC_SW_IO_11:
+	case HALMAC_GPIO_FUNC_SW_IO_12:
+	case HALMAC_GPIO_FUNC_SW_IO_13:
+	case HALMAC_GPIO_FUNC_SW_IO_14:
+	case HALMAC_GPIO_FUNC_SW_IO_15:
+		*enable = (cur_func == HALMAC_SW_IO) ? 1 : 0;
+		break;
+	default:
+		*enable = 0;
+		return HALMAC_RET_GET_PINMUX_ERR;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * pinmux_set_func_8821c() -set gpio function
+ * @adapter : the adapter of halmac
+ * @gpio_func : gpio function
+ * Author : Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+pinmux_set_func_8821c(struct halmac_adapter *adapter,
+		      enum halmac_gpio_func gpio_func)
+{
+	u32 list_size;
+	u32 gpio_id;
+	enum halmac_ret_status status;
+	const struct halmac_gpio_pimux_list *list = NULL;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+	PLTFM_MSG_TRACE("[TRACE]func name : %d\n", gpio_func);
+
+	status = chk_pinmux_valid_8821c(adapter, gpio_func);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	status = get_pinmux_list_8821c(adapter, gpio_func, &list, &list_size,
+				       &gpio_id);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	status = pinmux_switch_88xx(adapter, list, list_size, gpio_id,
+				    gpio_func);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	status = pinmux_record_88xx(adapter, gpio_func, 1);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * pinmux_free_func_8821c() -free locked gpio function
+ * @adapter : the adapter of halmac
+ * @gpio_func : gpio function
+ * Author : Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+pinmux_free_func_8821c(struct halmac_adapter *adapter,
+		       enum halmac_gpio_func gpio_func)
+{
+	struct halmac_pinmux_info *info = &adapter->pinmux_info;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	switch (gpio_func) {
+	case HALMAC_GPIO_FUNC_SW_IO_0:
+		info->sw_io_0 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_1:
+		info->sw_io_1 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_2:
+		info->sw_io_2 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_3:
+		info->sw_io_3 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_4:
+	case HALMAC_GPIO_FUNC_SDIO_INT:
+		info->sw_io_4 = 0;
+		info->sdio_int = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_5:
+		info->sw_io_5 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_6:
+		info->sw_io_6 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_7:
+		info->sw_io_7 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_8:
+	case HALMAC_GPIO_FUNC_WL_LED:
+		info->sw_io_8 = 0;
+		info->wl_led = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_9:
+		info->sw_io_9 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_10:
+		info->sw_io_10 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_11:
+		info->sw_io_11 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_12:
+		info->sw_io_12 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_13:
+	case HALMAC_GPIO_FUNC_BT_DEV_WAKE1:
+		info->bt_dev_wake = 0;
+		info->sw_io_13 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_14:
+	case HALMAC_GPIO_FUNC_BT_HOST_WAKE1:
+		info->bt_host_wake = 0;
+		info->sw_io_14 = 0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_15:
+		info->sw_io_15 = 0;
+		break;
+	default:
+		return HALMAC_RET_SWITCH_CASE_ERROR;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]func : %X\n", gpio_func);
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+static enum halmac_ret_status
+get_pinmux_list_8821c(struct halmac_adapter *adapter,
+		      enum halmac_gpio_func gpio_func,
+		      const struct halmac_gpio_pimux_list **list,
+		      u32 *list_size, u32 *gpio_id)
+{
+	switch (gpio_func) {
+	case HALMAC_GPIO_FUNC_SW_IO_0:
+		*list = PINMUX_LIST_GPIO0_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO0_8821C);
+		*gpio_id = HALMAC_GPIO0;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_1:
+		*list = PINMUX_LIST_GPIO1_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO1_8821C);
+		*gpio_id = HALMAC_GPIO1;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_2:
+		*list = PINMUX_LIST_GPIO2_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO2_8821C);
+		*gpio_id = HALMAC_GPIO2;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_3:
+		*list = PINMUX_LIST_GPIO3_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO3_8821C);
+		*gpio_id = HALMAC_GPIO3;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_4:
+	case HALMAC_GPIO_FUNC_SDIO_INT:
+		*list = PINMUX_LIST_GPIO4_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO4_8821C);
+		*gpio_id = HALMAC_GPIO4;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_5:
+		*list = PINMUX_LIST_GPIO5_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO5_8821C);
+		*gpio_id = HALMAC_GPIO5;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_6:
+		*list = PINMUX_LIST_GPIO6_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO6_8821C);
+		*gpio_id = HALMAC_GPIO6;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_7:
+		*list = PINMUX_LIST_GPIO7_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO7_8821C);
+		*gpio_id = HALMAC_GPIO7;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_8:
+	case HALMAC_GPIO_FUNC_WL_LED:
+		*list = PINMUX_LIST_GPIO8_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO8_8821C);
+		*gpio_id = HALMAC_GPIO8;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_9:
+		*list = PINMUX_LIST_GPIO9_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO9_8821C);
+		*gpio_id = HALMAC_GPIO9;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_10:
+		*list = PINMUX_LIST_GPIO10_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO10_8821C);
+		*gpio_id = HALMAC_GPIO10;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_11:
+		*list = PINMUX_LIST_GPIO11_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO11_8821C);
+		*gpio_id = HALMAC_GPIO11;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_12:
+		*list = PINMUX_LIST_GPIO12_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO12_8821C);
+		*gpio_id = HALMAC_GPIO12;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_13:
+	case HALMAC_GPIO_FUNC_BT_DEV_WAKE1:
+		*list = PINMUX_LIST_GPIO13_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO13_8821C);
+		*gpio_id = HALMAC_GPIO13;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_14:
+	case HALMAC_GPIO_FUNC_BT_HOST_WAKE1:
+		*list = PINMUX_LIST_GPIO14_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO14_8821C);
+		*gpio_id = HALMAC_GPIO14;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_15:
+		*list = PINMUX_LIST_GPIO15_8821C;
+		*list_size = ARRAY_SIZE(PINMUX_LIST_GPIO15_8821C);
+		*gpio_id = HALMAC_GPIO15;
+		break;
+	default:
+		return HALMAC_RET_SWITCH_CASE_ERROR;
+	}
+
+	return HALMAC_RET_SUCCESS;
+}
+
+static enum halmac_ret_status
+chk_pinmux_valid_8821c(struct halmac_adapter *adapter,
+		       enum halmac_gpio_func gpio_func)
+{
+	struct halmac_pinmux_info *info = &adapter->pinmux_info;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+
+	switch (gpio_func) {
+	case HALMAC_GPIO_FUNC_SW_IO_0:
+		if (info->sw_io_0 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_1:
+		if (info->sw_io_1 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_2:
+		if (info->sw_io_2 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_3:
+		if (info->sw_io_3 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_4:
+	case HALMAC_GPIO_FUNC_SDIO_INT:
+		if (info->sw_io_4 == 1 || info->sdio_int == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_5:
+		if (info->sw_io_5 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_6:
+		if (info->sw_io_6 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_7:
+		if (info->sw_io_7 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_8:
+	case HALMAC_GPIO_FUNC_WL_LED:
+		if (info->sw_io_8 == 1 || info->wl_led == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_9:
+		if (info->sw_io_9 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_10:
+		if (info->sw_io_10 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_11:
+		if (info->sw_io_11 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_12:
+		if (info->sw_io_12 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_13:
+	case HALMAC_GPIO_FUNC_BT_DEV_WAKE1:
+		if (info->sw_io_13 == 1 || info->bt_dev_wake == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_14:
+	case HALMAC_GPIO_FUNC_BT_HOST_WAKE1:
+		if (info->sw_io_14 == 1 || info->bt_host_wake == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	case HALMAC_GPIO_FUNC_SW_IO_15:
+		if (info->sw_io_15 == 1)
+			status = HALMAC_RET_PINMUX_USED;
+		break;
+	default:
+		return HALMAC_RET_SWITCH_CASE_ERROR;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]chk_pinmux_valid func : %X status : %X\n",
+			gpio_func, status);
+
+	return status;
+}
+#endif /* HALMAC_8821C_SUPPORT */
+

+ 37 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_gpio_8821c.h

@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#ifndef _HALMAC_GPIO_8821C_H_
+#define _HALMAC_GPIO_8821C_H_
+
+#include "../../halmac_api.h"
+
+#if HALMAC_8821C_SUPPORT
+
+enum halmac_ret_status
+pinmux_get_func_8821c(struct halmac_adapter *adapter,
+		      enum halmac_gpio_func gpio_func, u8 *enable);
+
+enum halmac_ret_status
+pinmux_set_func_8821c(struct halmac_adapter *adapter,
+		      enum halmac_gpio_func gpio_func);
+
+enum halmac_ret_status
+pinmux_free_func_8821c(struct halmac_adapter *adapter,
+		       enum halmac_gpio_func gpio_func);
+
+#endif /* HALMAC_8821C_SUPPORT */
+
+#endif/* _HALMAC_GPIO_8821C_H_ */

+ 890 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_init_8821c.c

@@ -0,0 +1,890 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "halmac_init_8821c.h"
+#include "halmac_8821c_cfg.h"
+#if HALMAC_PCIE_SUPPORT
+#include "halmac_pcie_8821c.h"
+#endif
+#if HALMAC_SDIO_SUPPORT
+#include "halmac_sdio_8821c.h"
+#endif
+#if HALMAC_USB_SUPPORT
+#include "halmac_usb_8821c.h"
+#endif
+#include "halmac_gpio_8821c.h"
+#include "halmac_common_8821c.h"
+#include "halmac_cfg_wmac_8821c.h"
+#include "../halmac_common_88xx.h"
+#include "../halmac_init_88xx.h"
+
+#if HALMAC_8821C_SUPPORT
+
+#define RSVD_PG_DRV_NUM			16
+#define RSVD_PG_H2C_EXTRAINFO_NUM	24
+#define RSVD_PG_H2C_STATICINFO_NUM	8
+#define RSVD_PG_H2CQ_NUM		8
+#define RSVD_PG_CPU_INSTRUCTION_NUM	0
+#define RSVD_PG_FW_TXBUF_NUM		4
+#define RSVD_PG_CSIBUF_NUM		0
+#define RSVD_PG_DLLB_NUM		(TX_FIFO_SIZE_8821C / 3 >> \
+					TX_PAGE_SIZE_SHIFT_88XX)
+
+#define MAC_TRX_ENABLE	(BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | \
+			BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | \
+			BIT_MACTXEN | BIT_MACRXEN)
+
+#define BLK_DESC_NUM   0x3
+
+#define WLAN_SLOT_TIME		0x05
+#define WLAN_PIFS_TIME		0x19
+#define WLAN_SIFS_CCK_CONT_TX	0xA
+#define WLAN_SIFS_OFDM_CONT_TX	0xA
+#define WLAN_SIFS_CCK_TRX	0x10
+#define WLAN_SIFS_OFDM_TRX	0x10
+#define WLAN_VO_TXOP_LIMIT	0x186 /* unit : 32us */
+#define WLAN_VI_TXOP_LIMIT	0x3BC /* unit : 32us */
+#define WLAN_RDG_NAV		0x05
+#define WLAN_TXOP_NAV		0x1B
+#define WLAN_CCK_RX_TSF		0x30
+#define WLAN_OFDM_RX_TSF	0x30
+#define WLAN_TBTT_PROHIBIT	0x04 /* unit : 32us */
+#define WLAN_TBTT_HOLD_TIME	0x064 /* unit : 32us */
+#define WLAN_DRV_EARLY_INT	0x04
+#define WLAN_BCN_DMA_TIME	0x02
+#define WLAN_ACK_TO_CCK		0x40
+
+#define WLAN_RX_FILTER0		0x0FFFFFFF
+#define WLAN_RX_FILTER2		0xFFFF
+#define WLAN_RCR_CFG		0xE400220E
+#define WLAN_RXPKT_MAX_SZ	12288
+#define WLAN_RXPKT_MAX_SZ_512	(WLAN_RXPKT_MAX_SZ >> 9)
+
+#define WLAN_AMPDU_MAX_TIME		0x70
+#define WLAN_RTS_LEN_TH			0xFF
+#define WLAN_RTS_TX_TIME_TH		0x08
+#define WLAN_MAX_AGG_PKT_LIMIT		0x10
+#define WLAN_RTS_MAX_AGG_PKT_LIMIT	0x10
+#define WLAN_MAX_AGG_PKT_LIMIT_SDIO	0x2B
+#define WLAN_RTS_MAX_AGG_PKT_LIMIT_SDIO	0x2B
+#define WLAN_PRE_TXCNT_TIME_TH		0x1E4
+#define WALN_FAST_EDCA_VO_TH		0x06
+#define WLAN_FAST_EDCA_VI_TH		0x06
+#define WLAN_FAST_EDCA_BE_TH		0x06
+#define WLAN_FAST_EDCA_BK_TH		0x06
+#define WLAN_BAR_RETRY_LIMIT		0x01
+#define WLAN_RA_TRY_RATE_AGG_LIMIT	0x08
+
+#define WLAN_TX_FUNC_CFG1		0x30
+#define WLAN_TX_FUNC_CFG2		0x30
+#define WLAN_MAC_OPT_NORM_FUNC1		0x98
+#define WLAN_MAC_OPT_LB_FUNC1		0x80
+#define WLAN_MAC_OPT_FUNC2		0x30810041
+
+#define WLAN_SIFS_CFG	(WLAN_SIFS_CCK_CONT_TX | \
+			(WLAN_SIFS_OFDM_CONT_TX << BIT_SHIFT_SIFS_OFDM_CTX) | \
+			(WLAN_SIFS_CCK_TRX << BIT_SHIFT_SIFS_CCK_TRX) | \
+			(WLAN_SIFS_OFDM_TRX << BIT_SHIFT_SIFS_OFDM_TRX))
+
+#define WLAN_TBTT_TIME	(WLAN_TBTT_PROHIBIT |\
+			(WLAN_TBTT_HOLD_TIME << BIT_SHIFT_TBTT_HOLD_TIME_AP))
+
+#define WLAN_NAV_CFG		(WLAN_RDG_NAV | (WLAN_TXOP_NAV << 16))
+#define WLAN_RX_TSF_CFG		(WLAN_CCK_RX_TSF | (WLAN_OFDM_RX_TSF) << 8)
+
+#if HALMAC_PLATFORM_WINDOWS
+/*SDIO RQPN Mapping for Windows, extra queue is not implemented in Driver code*/
+static struct halmac_rqpn HALMAC_RQPN_SDIO_8821C[] = {
+	/* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */
+	{HALMAC_TRX_MODE_NORMAL,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_TRXSHARE,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_WMM,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_P2P,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_LOOPBACK,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+};
+#else
+/*SDIO RQPN Mapping*/
+static struct halmac_rqpn HALMAC_RQPN_SDIO_8821C[] = {
+	/* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */
+	{HALMAC_TRX_MODE_NORMAL,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_TRXSHARE,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_WMM,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_P2P,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_LOOPBACK,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+};
+#endif
+
+/*PCIE RQPN Mapping*/
+static struct halmac_rqpn HALMAC_RQPN_PCIE_8821C[] = {
+	/* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */
+	{HALMAC_TRX_MODE_NORMAL,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_TRXSHARE,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_WMM,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_P2P,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_LOOPBACK,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+};
+
+/*USB 2 Bulkout RQPN Mapping*/
+static struct halmac_rqpn HALMAC_RQPN_2BULKOUT_8821C[] = {
+	/* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */
+	{HALMAC_TRX_MODE_NORMAL,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_HQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_TRXSHARE,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_HQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_WMM,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_HQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_P2P,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_LOOPBACK,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+};
+
+/*USB 3 Bulkout RQPN Mapping*/
+static struct halmac_rqpn HALMAC_RQPN_3BULKOUT_8821C[] = {
+	/* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */
+	{HALMAC_TRX_MODE_NORMAL,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_TRXSHARE,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_WMM,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_P2P,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_LQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_LOOPBACK,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_LQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ, HALMAC_MAP2_LQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_HQ},
+};
+
+/*USB 4 Bulkout RQPN Mapping*/
+static struct halmac_rqpn HALMAC_RQPN_4BULKOUT_8821C[] = {
+	/* { mode, vo_map, vi_map, be_map, bk_map, mg_map, hi_map } */
+	{HALMAC_TRX_MODE_NORMAL,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_TRXSHARE,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_WMM,
+	 HALMAC_MAP2_HQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_NQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_P2P,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_LOOPBACK,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK,
+	 HALMAC_MAP2_NQ, HALMAC_MAP2_NQ, HALMAC_MAP2_LQ, HALMAC_MAP2_LQ,
+	 HALMAC_MAP2_EXQ, HALMAC_MAP2_HQ},
+};
+
+#if HALMAC_PLATFORM_WINDOWS
+/*SDIO Page Number*/
+static struct halmac_pg_num HALMAC_PG_NUM_SDIO_8821C[] = {
+	/* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */
+	{HALMAC_TRX_MODE_NORMAL, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_TRXSHARE, 8, 8, 8, 0, 1},
+	{HALMAC_TRX_MODE_WMM, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_P2P, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_LOOPBACK, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK, 16, 16, 16, 0, 1},
+};
+#else
+/*SDIO Page Number*/
+static struct halmac_pg_num HALMAC_PG_NUM_SDIO_8821C[] = {
+	/* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */
+	{HALMAC_TRX_MODE_NORMAL, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_TRXSHARE, 8, 8, 8, 8, 1},
+	{HALMAC_TRX_MODE_WMM, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_P2P, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_LOOPBACK, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK, 16, 16, 16, 14, 1},
+};
+#endif
+
+/*PCIE Page Number*/
+static struct halmac_pg_num HALMAC_PG_NUM_PCIE_8821C[] = {
+	/* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */
+	{HALMAC_TRX_MODE_NORMAL, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_TRXSHARE, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_WMM, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_P2P, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_LOOPBACK, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK, 16, 16, 16, 14, 1},
+};
+
+/*USB 2 Bulkout Page Number*/
+static struct halmac_pg_num HALMAC_PG_NUM_2BULKOUT_8821C[] = {
+	/* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */
+	{HALMAC_TRX_MODE_NORMAL, 16, 16, 0, 0, 1},
+	{HALMAC_TRX_MODE_TRXSHARE, 16, 16, 0, 0, 1},
+	{HALMAC_TRX_MODE_WMM, 16, 16, 0, 0, 1},
+	{HALMAC_TRX_MODE_P2P, 16, 16, 0, 0, 1},
+	{HALMAC_TRX_MODE_LOOPBACK, 16, 16, 0, 0, 1},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK, 16, 16, 0, 0, 1},
+};
+
+/*USB 3 Bulkout Page Number*/
+static struct halmac_pg_num HALMAC_PG_NUM_3BULKOUT_8821C[] = {
+	/* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */
+	{HALMAC_TRX_MODE_NORMAL, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_TRXSHARE, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_WMM, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_P2P, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_LOOPBACK, 16, 16, 16, 0, 1},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK, 16, 16, 16, 0, 1},
+};
+
+/*USB 4 Bulkout Page Number*/
+static struct halmac_pg_num HALMAC_PG_NUM_4BULKOUT_8821C[] = {
+	/* { mode, hq_num, nq_num, lq_num, exq_num, gap_num} */
+	{HALMAC_TRX_MODE_NORMAL, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_TRXSHARE, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_WMM, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_P2P, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_LOOPBACK, 16, 16, 16, 14, 1},
+	{HALMAC_TRX_MODE_DELAY_LOOPBACK, 16, 16, 16, 14, 1},
+};
+
+static enum halmac_ret_status
+txdma_queue_mapping_8821c(struct halmac_adapter *adapter,
+			  enum halmac_trx_mode mode);
+
+static enum halmac_ret_status
+priority_queue_cfg_8821c(struct halmac_adapter *adapter,
+			 enum halmac_trx_mode mode);
+
+static enum halmac_ret_status
+set_trx_fifo_info_8821c(struct halmac_adapter *adapter,
+			enum halmac_trx_mode mode);
+
+enum halmac_ret_status
+mount_api_8821c(struct halmac_adapter *adapter)
+{
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	adapter->chip_id = HALMAC_CHIP_ID_8821C;
+	adapter->hw_cfg_info.efuse_size = EFUSE_SIZE_8821C;
+	adapter->hw_cfg_info.eeprom_size = EEPROM_SIZE_8821C;
+	adapter->hw_cfg_info.bt_efuse_size = BT_EFUSE_SIZE_8821C;
+	adapter->hw_cfg_info.cam_entry_num = SEC_CAM_NUM_8821C;
+	adapter->hw_cfg_info.tx_fifo_size = TX_FIFO_SIZE_8821C;
+	adapter->hw_cfg_info.rx_fifo_size = RX_FIFO_SIZE_8821C;
+	adapter->hw_cfg_info.ac_oqt_size = OQT_ENTRY_AC_8821C;
+	adapter->hw_cfg_info.non_ac_oqt_size = OQT_ENTRY_NOAC_8821C;
+	adapter->hw_cfg_info.usb_txagg_num = BLK_DESC_NUM;
+	adapter->txff_alloc.rsvd_drv_pg_num = RSVD_PG_DRV_NUM;
+
+	api->halmac_init_trx_cfg = init_trx_cfg_8821c;
+	api->halmac_init_protocol_cfg = init_protocol_cfg_8821c;
+	api->halmac_init_h2c = init_h2c_8821c;
+	api->halmac_pinmux_get_func = pinmux_get_func_8821c;
+	api->halmac_pinmux_set_func = pinmux_set_func_8821c;
+	api->halmac_pinmux_free_func = pinmux_free_func_8821c;
+	api->halmac_get_hw_value = get_hw_value_8821c;
+	api->halmac_set_hw_value = set_hw_value_8821c;
+	api->halmac_cfg_drv_info = cfg_drv_info_8821c;
+	api->halmac_fill_txdesc_checksum = fill_txdesc_check_sum_8821c;
+	api->halmac_init_low_pwr = init_low_pwr_8821c;
+
+	api->halmac_init_wmac_cfg = init_wmac_cfg_8821c;
+	api->halmac_init_edca_cfg = init_edca_cfg_8821c;
+
+	if (adapter->intf == HALMAC_INTERFACE_SDIO) {
+#if HALMAC_SDIO_SUPPORT
+		api->halmac_mac_power_switch = mac_pwr_switch_sdio_8821c;
+		api->halmac_phy_cfg = phy_cfg_sdio_8821c;
+		api->halmac_pcie_switch = pcie_switch_sdio_8821c;
+		api->halmac_interface_integration_tuning = intf_tun_sdio_8821c;
+		api->halmac_tx_allowed_sdio = tx_allowed_sdio_8821c;
+		api->halmac_get_sdio_tx_addr = get_sdio_tx_addr_8821c;
+		api->halmac_reg_read_8 = reg_r8_sdio_8821c;
+		api->halmac_reg_write_8 = reg_w8_sdio_8821c;
+		api->halmac_reg_read_16 = reg_r16_sdio_8821c;
+		api->halmac_reg_write_16 = reg_w16_sdio_8821c;
+		api->halmac_reg_read_32 = reg_r32_sdio_8821c;
+		api->halmac_reg_write_32 = reg_w32_sdio_8821c;
+
+		adapter->sdio_fs.macid_map_size = MACID_MAX_8821C * 2;
+		if (!adapter->sdio_fs.macid_map) {
+			adapter->sdio_fs.macid_map =
+			(u8 *)PLTFM_MALLOC(adapter->sdio_fs.macid_map_size);
+			if (!adapter->sdio_fs.macid_map)
+				PLTFM_MSG_ERR("[ERR]mac id map malloc!!\n");
+		}
+#endif
+	} else if (adapter->intf == HALMAC_INTERFACE_USB) {
+#if HALMAC_USB_SUPPORT
+		api->halmac_mac_power_switch = mac_pwr_switch_usb_8821c;
+		api->halmac_phy_cfg = phy_cfg_usb_8821c;
+		api->halmac_pcie_switch = pcie_switch_usb_8821c;
+		api->halmac_interface_integration_tuning = intf_tun_usb_8821c;
+#endif
+	} else if (adapter->intf == HALMAC_INTERFACE_PCIE) {
+#if HALMAC_PCIE_SUPPORT
+		api->halmac_mac_power_switch = mac_pwr_switch_pcie_8821c;
+		api->halmac_phy_cfg = phy_cfg_pcie_8821c;
+		api->halmac_pcie_switch = pcie_switch_8821c;
+		api->halmac_interface_integration_tuning = intf_tun_pcie_8821c;
+#endif
+	} else {
+		PLTFM_MSG_ERR("[ERR]Undefined IC\n");
+		return HALMAC_RET_CHIP_NOT_SUPPORT;
+	}
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * init_trx_cfg_8821c() - config trx dma register
+ * @adapter : the adapter of halmac
+ * @mode : trx mode selection
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+init_trx_cfg_8821c(struct halmac_adapter *adapter, enum halmac_trx_mode mode)
+{
+	u8 value8;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	adapter->trx_mode = mode;
+
+	status = txdma_queue_mapping_8821c(adapter, mode);
+	if (status != HALMAC_RET_SUCCESS) {
+		PLTFM_MSG_ERR("[ERR]queue mapping\n");
+		return status;
+	}
+
+	value8 = 0;
+	HALMAC_REG_W8(REG_CR, value8);
+	value8 = MAC_TRX_ENABLE;
+	HALMAC_REG_W8(REG_CR, value8);
+	HALMAC_REG_W32(REG_H2CQ_CSR, BIT(31));
+
+	status = priority_queue_cfg_8821c(adapter, mode);
+	if (status != HALMAC_RET_SUCCESS) {
+		PLTFM_MSG_ERR("[ERR]priority queue cfg\n");
+		return status;
+	}
+
+	if (adapter->txff_alloc.rx_fifo_exp_mode !=
+	    HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE)
+		HALMAC_REG_W8(REG_RX_DRVINFO_SZ, RX_DESC_DUMMY_SIZE_8821C >> 3);
+
+	status = init_h2c_8821c(adapter);
+	if (status != HALMAC_RET_SUCCESS) {
+		PLTFM_MSG_ERR("[ERR]init h2cq!\n");
+		return status;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+static enum halmac_ret_status
+txdma_queue_mapping_8821c(struct halmac_adapter *adapter,
+			  enum halmac_trx_mode mode)
+{
+	u16 value16;
+	struct halmac_rqpn *cur_rqpn_sel = NULL;
+	enum halmac_ret_status status;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	if (adapter->intf == HALMAC_INTERFACE_SDIO) {
+		cur_rqpn_sel = HALMAC_RQPN_SDIO_8821C;
+	} else if (adapter->intf == HALMAC_INTERFACE_PCIE) {
+		cur_rqpn_sel = HALMAC_RQPN_PCIE_8821C;
+	} else if (adapter->intf == HALMAC_INTERFACE_USB) {
+		if (adapter->bulkout_num == 2) {
+			cur_rqpn_sel = HALMAC_RQPN_2BULKOUT_8821C;
+		} else if (adapter->bulkout_num == 3) {
+			cur_rqpn_sel = HALMAC_RQPN_3BULKOUT_8821C;
+		} else if (adapter->bulkout_num == 4) {
+			cur_rqpn_sel = HALMAC_RQPN_4BULKOUT_8821C;
+		} else {
+			PLTFM_MSG_ERR("[ERR]invalid intf\n");
+			return HALMAC_RET_NOT_SUPPORT;
+		}
+	} else {
+		return HALMAC_RET_NOT_SUPPORT;
+	}
+
+	status = rqpn_parser_88xx(adapter, mode, cur_rqpn_sel);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	value16 = 0;
+	value16 |= BIT_TXDMA_HIQ_MAP(adapter->pq_map[HALMAC_PQ_MAP_HI]);
+	value16 |= BIT_TXDMA_MGQ_MAP(adapter->pq_map[HALMAC_PQ_MAP_MG]);
+	value16 |= BIT_TXDMA_BKQ_MAP(adapter->pq_map[HALMAC_PQ_MAP_BK]);
+	value16 |= BIT_TXDMA_BEQ_MAP(adapter->pq_map[HALMAC_PQ_MAP_BE]);
+	value16 |= BIT_TXDMA_VIQ_MAP(adapter->pq_map[HALMAC_PQ_MAP_VI]);
+	value16 |= BIT_TXDMA_VOQ_MAP(adapter->pq_map[HALMAC_PQ_MAP_VO]);
+	HALMAC_REG_W16(REG_TXDMA_PQ_MAP, value16);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+static enum halmac_ret_status
+priority_queue_cfg_8821c(struct halmac_adapter *adapter,
+			 enum halmac_trx_mode mode)
+{
+	u8 transfer_mode = 0;
+	u8 value8;
+	u32 cnt;
+	struct halmac_txff_allocation *txff_info = &adapter->txff_alloc;
+	enum halmac_ret_status status;
+	struct halmac_pg_num *cur_pg_num = NULL;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	status = set_trx_fifo_info_8821c(adapter, mode);
+	if (status != HALMAC_RET_SUCCESS) {
+		PLTFM_MSG_ERR("[ERR]set trx fifo!!\n");
+		return status;
+	}
+
+	if (adapter->intf == HALMAC_INTERFACE_SDIO) {
+		cur_pg_num = HALMAC_PG_NUM_SDIO_8821C;
+	} else if (adapter->intf == HALMAC_INTERFACE_PCIE) {
+		cur_pg_num = HALMAC_PG_NUM_PCIE_8821C;
+	} else if (adapter->intf == HALMAC_INTERFACE_USB) {
+		if (adapter->bulkout_num == 2) {
+			cur_pg_num = HALMAC_PG_NUM_2BULKOUT_8821C;
+		} else if (adapter->bulkout_num == 3) {
+			cur_pg_num = HALMAC_PG_NUM_3BULKOUT_8821C;
+		} else if (adapter->bulkout_num == 4) {
+			cur_pg_num = HALMAC_PG_NUM_4BULKOUT_8821C;
+		} else {
+			PLTFM_MSG_ERR("[ERR]invalid intf\n");
+			return HALMAC_RET_NOT_SUPPORT;
+		}
+	} else {
+		return HALMAC_RET_NOT_SUPPORT;
+	}
+
+	status = pg_num_parser_88xx(adapter, mode, cur_pg_num);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	PLTFM_MSG_TRACE("[TRACE]Set FIFO page\n");
+
+	HALMAC_REG_W16(REG_FIFOPAGE_INFO_1, txff_info->high_queue_pg_num);
+	HALMAC_REG_W16(REG_FIFOPAGE_INFO_2, txff_info->low_queue_pg_num);
+	HALMAC_REG_W16(REG_FIFOPAGE_INFO_3, txff_info->normal_queue_pg_num);
+	HALMAC_REG_W16(REG_FIFOPAGE_INFO_4, txff_info->extra_queue_pg_num);
+	HALMAC_REG_W16(REG_FIFOPAGE_INFO_5, txff_info->pub_queue_pg_num);
+	HALMAC_REG_W32_SET(REG_RQPN_CTRL_2, BIT(31));
+
+	adapter->sdio_fs.hiq_pg_num = txff_info->high_queue_pg_num;
+	adapter->sdio_fs.miq_pg_num = txff_info->normal_queue_pg_num;
+	adapter->sdio_fs.lowq_pg_num = txff_info->low_queue_pg_num;
+	adapter->sdio_fs.pubq_pg_num = txff_info->pub_queue_pg_num;
+	adapter->sdio_fs.exq_pg_num = txff_info->extra_queue_pg_num;
+
+	HALMAC_REG_W16(REG_FIFOPAGE_CTRL_2, txff_info->rsvd_boundary);
+	HALMAC_REG_W8_SET(REG_FWHW_TXQ_CTRL + 2, BIT(4));
+
+	/*20170411 Soar*/
+	/* SDIO sometimes use two CMD52 to do HALMAC_REG_W16 */
+	/* and may cause a mismatch between HW status and Reg value. */
+	/* A patch is to write high byte first, suggested by Argis */
+	if (adapter->intf == HALMAC_INTERFACE_SDIO) {
+		value8 = (u8)(txff_info->rsvd_boundary >> 8 & 0xFF);
+		HALMAC_REG_W8(REG_BCNQ_BDNY_V1 + 1, value8);
+		value8 = (u8)(txff_info->rsvd_boundary & 0xFF);
+		HALMAC_REG_W8(REG_BCNQ_BDNY_V1, value8);
+	} else {
+		HALMAC_REG_W16(REG_BCNQ_BDNY_V1, txff_info->rsvd_boundary);
+	}
+
+	HALMAC_REG_W16(REG_FIFOPAGE_CTRL_2 + 2, txff_info->rsvd_boundary);
+
+	/*20170411 Soar*/
+	/* SDIO sometimes use two CMD52 to do HALMAC_REG_W16 */
+	/* and may cause a mismatch between HW status and Reg value. */
+	/* A patch is to write high byte first, suggested by Argis */
+	if (adapter->intf == HALMAC_INTERFACE_SDIO) {
+		value8 = (u8)(txff_info->rsvd_boundary >> 8 & 0xFF);
+		HALMAC_REG_W8(REG_BCNQ1_BDNY_V1 + 1, value8);
+		value8 = (u8)(txff_info->rsvd_boundary & 0xFF);
+		HALMAC_REG_W8(REG_BCNQ1_BDNY_V1, value8);
+	} else {
+		HALMAC_REG_W16(REG_BCNQ1_BDNY_V1, txff_info->rsvd_boundary);
+	}
+
+	HALMAC_REG_W32(REG_RXFF_BNDY,
+		       adapter->hw_cfg_info.rx_fifo_size -
+		       C2H_PKT_BUF_88XX - 1);
+
+	if (adapter->intf == HALMAC_INTERFACE_USB) {
+		value8 = HALMAC_REG_R8(REG_AUTO_LLT_V1);
+		value8 &= ~(BIT_MASK_BLK_DESC_NUM << BIT_SHIFT_BLK_DESC_NUM);
+		value8 |= (BLK_DESC_NUM << BIT_SHIFT_BLK_DESC_NUM);
+		HALMAC_REG_W8(REG_AUTO_LLT_V1, value8);
+
+		HALMAC_REG_W8(REG_AUTO_LLT_V1 + 3, BLK_DESC_NUM);
+		HALMAC_REG_W8_SET(REG_TXDMA_OFFSET_CHK + 1, BIT(1));
+	}
+
+	HALMAC_REG_W8_SET(REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1);
+	cnt = 1000;
+	while (HALMAC_REG_R8(REG_AUTO_LLT_V1) & BIT_AUTO_INIT_LLT_V1) {
+		cnt--;
+		if (cnt == 0)
+			return HALMAC_RET_INIT_LLT_FAIL;
+	}
+
+	if (mode == HALMAC_TRX_MODE_DELAY_LOOPBACK) {
+		transfer_mode = HALMAC_TRNSFER_LOOPBACK_DELAY;
+		HALMAC_REG_W16(REG_WMAC_LBK_BUF_HD_V1,
+			       adapter->txff_alloc.rsvd_boundary);
+	} else if (mode == HALMAC_TRX_MODE_LOOPBACK) {
+		transfer_mode = HALMAC_TRNSFER_LOOPBACK_DIRECT;
+	} else {
+		transfer_mode = HALMAC_TRNSFER_NORMAL;
+	}
+
+	adapter->hw_cfg_info.trx_mode = transfer_mode;
+	HALMAC_REG_W8(REG_CR + 3, (u8)transfer_mode);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+static enum halmac_ret_status
+set_trx_fifo_info_8821c(struct halmac_adapter *adapter,
+			enum halmac_trx_mode mode)
+{
+	u16 cur_pg_addr;
+	u32 txff_size = TX_FIFO_SIZE_8821C;
+	u32 rxff_size = RX_FIFO_SIZE_8821C;
+	struct halmac_txff_allocation *info = &adapter->txff_alloc;
+
+	if (info->rx_fifo_exp_mode == HALMAC_RX_FIFO_EXPANDING_MODE_1_BLOCK) {
+		txff_size = TX_FIFO_SIZE_RX_EXPAND_1BLK_8821C;
+		rxff_size = RX_FIFO_SIZE_RX_EXPAND_1BLK_8821C;
+	}
+
+	if (info->la_mode != HALMAC_LA_MODE_DISABLE) {
+		txff_size = TX_FIFO_SIZE_LA_8821C;
+		rxff_size = RX_FIFO_SIZE_8821C;
+	}
+
+	adapter->hw_cfg_info.tx_fifo_size = txff_size;
+	adapter->hw_cfg_info.rx_fifo_size = rxff_size;
+	info->tx_fifo_pg_num = (u16)(txff_size >> TX_PAGE_SIZE_SHIFT_88XX);
+
+	info->rsvd_pg_num = info->rsvd_drv_pg_num +
+					RSVD_PG_H2C_EXTRAINFO_NUM +
+					RSVD_PG_H2C_STATICINFO_NUM +
+					RSVD_PG_H2CQ_NUM +
+					RSVD_PG_CPU_INSTRUCTION_NUM +
+					RSVD_PG_FW_TXBUF_NUM +
+					RSVD_PG_CSIBUF_NUM;
+
+	if (mode == HALMAC_TRX_MODE_DELAY_LOOPBACK)
+		info->rsvd_pg_num += RSVD_PG_DLLB_NUM;
+
+	if (info->rsvd_pg_num > info->tx_fifo_pg_num)
+		return HALMAC_RET_CFG_TXFIFO_PAGE_FAIL;
+
+	info->acq_pg_num = info->tx_fifo_pg_num - info->rsvd_pg_num;
+	info->rsvd_boundary = info->tx_fifo_pg_num - info->rsvd_pg_num;
+
+	cur_pg_addr = info->tx_fifo_pg_num;
+	cur_pg_addr -= RSVD_PG_CSIBUF_NUM;
+	info->rsvd_csibuf_addr = cur_pg_addr;
+	cur_pg_addr -= RSVD_PG_FW_TXBUF_NUM;
+	info->rsvd_fw_txbuf_addr = cur_pg_addr;
+	cur_pg_addr -= RSVD_PG_CPU_INSTRUCTION_NUM;
+	info->rsvd_cpu_instr_addr = cur_pg_addr;
+	cur_pg_addr -= RSVD_PG_H2CQ_NUM;
+	info->rsvd_h2cq_addr = cur_pg_addr;
+	cur_pg_addr -= RSVD_PG_H2C_STATICINFO_NUM;
+	info->rsvd_h2c_sta_info_addr = cur_pg_addr;
+	cur_pg_addr -= RSVD_PG_H2C_EXTRAINFO_NUM;
+	info->rsvd_h2c_info_addr = cur_pg_addr;
+	cur_pg_addr -= info->rsvd_drv_pg_num;
+	info->rsvd_drv_addr = cur_pg_addr;
+
+	if (mode == HALMAC_TRX_MODE_DELAY_LOOPBACK)
+		info->rsvd_drv_addr -= RSVD_PG_DLLB_NUM;
+
+	if (info->rsvd_boundary != info->rsvd_drv_addr)
+		return HALMAC_RET_CFG_TXFIFO_PAGE_FAIL;
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * init_protocol_cfg_8821c() - config protocol register
+ * @adapter : the adapter of halmac
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+init_protocol_cfg_8821c(struct halmac_adapter *adapter)
+{
+	u16 pre_txcnt;
+	u32 max_agg_num;
+	u32 max_rts_agg_num;
+	u32 value32;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	HALMAC_REG_W8(REG_AMPDU_MAX_TIME_V1, WLAN_AMPDU_MAX_TIME);
+	HALMAC_REG_W8_SET(REG_TX_HANG_CTRL, BIT_EN_EOF_V1);
+
+	pre_txcnt = WLAN_PRE_TXCNT_TIME_TH | BIT_EN_PRECNT;
+	HALMAC_REG_W8(REG_PRECNT_CTRL, (u8)(pre_txcnt & 0xFF));
+	HALMAC_REG_W8(REG_PRECNT_CTRL + 1, (u8)(pre_txcnt >> 8));
+
+	max_agg_num = WLAN_MAX_AGG_PKT_LIMIT;
+	max_rts_agg_num = WLAN_RTS_MAX_AGG_PKT_LIMIT;
+
+	if (adapter->intf == HALMAC_INTERFACE_SDIO) {
+		max_agg_num = WLAN_MAX_AGG_PKT_LIMIT_SDIO;
+		max_rts_agg_num = WLAN_RTS_MAX_AGG_PKT_LIMIT_SDIO;
+	}
+
+	value32 = WLAN_RTS_LEN_TH | (WLAN_RTS_TX_TIME_TH << 8) |
+				(max_agg_num << 16) | (max_rts_agg_num << 24);
+	HALMAC_REG_W32(REG_PROT_MODE_CTRL, value32);
+
+	HALMAC_REG_W16(REG_BAR_MODE_CTRL + 2,
+		       WLAN_BAR_RETRY_LIMIT | WLAN_RA_TRY_RATE_AGG_LIMIT << 8);
+
+	HALMAC_REG_W8(REG_FAST_EDCA_VOVI_SETTING, WALN_FAST_EDCA_VO_TH);
+	HALMAC_REG_W8(REG_FAST_EDCA_VOVI_SETTING + 2, WLAN_FAST_EDCA_VI_TH);
+	HALMAC_REG_W8(REG_FAST_EDCA_BEBK_SETTING, WLAN_FAST_EDCA_BE_TH);
+	HALMAC_REG_W8(REG_FAST_EDCA_BEBK_SETTING + 2, WLAN_FAST_EDCA_BK_TH);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * init_h2c_8821c() - config h2c packet buffer
+ * @adapter : the adapter of halmac
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+init_h2c_8821c(struct halmac_adapter *adapter)
+{
+	u8 value8;
+	u32 value32;
+	u32 h2cq_addr;
+	u32 h2cq_size;
+	struct halmac_txff_allocation *txff_info = &adapter->txff_alloc;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	h2cq_addr = txff_info->rsvd_h2cq_addr << TX_PAGE_SIZE_SHIFT_88XX;
+	h2cq_size = RSVD_PG_H2CQ_NUM << TX_PAGE_SIZE_SHIFT_88XX;
+
+	value32 = HALMAC_REG_R32(REG_H2C_HEAD);
+	value32 = (value32 & 0xFFFC0000) | h2cq_addr;
+	HALMAC_REG_W32(REG_H2C_HEAD, value32);
+
+	value32 = HALMAC_REG_R32(REG_H2C_READ_ADDR);
+	value32 = (value32 & 0xFFFC0000) | h2cq_addr;
+	HALMAC_REG_W32(REG_H2C_READ_ADDR, value32);
+
+	value32 = HALMAC_REG_R32(REG_H2C_TAIL);
+	value32 &= 0xFFFC0000;
+	value32 |= (h2cq_addr + h2cq_size);
+	HALMAC_REG_W32(REG_H2C_TAIL, value32);
+
+	value8 = HALMAC_REG_R8(REG_H2C_INFO);
+	value8 = (u8)((value8 & 0xFC) | 0x01);
+	HALMAC_REG_W8(REG_H2C_INFO, value8);
+
+	value8 = HALMAC_REG_R8(REG_H2C_INFO);
+	value8 = (u8)((value8 & 0xFB) | 0x04);
+	HALMAC_REG_W8(REG_H2C_INFO, value8);
+
+	value8 = HALMAC_REG_R8(REG_TXDMA_OFFSET_CHK + 1);
+	value8 = (u8)((value8 & 0x7f) | 0x80);
+	HALMAC_REG_W8(REG_TXDMA_OFFSET_CHK + 1, value8);
+
+	adapter->h2c_info.buf_size = h2cq_size;
+	get_h2c_buf_free_space_88xx(adapter);
+
+	if (adapter->h2c_info.buf_size != adapter->h2c_info.buf_fs) {
+		PLTFM_MSG_ERR("[ERR]get h2c free space error!\n");
+		return HALMAC_RET_GET_H2C_SPACE_ERR;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]h2c fs : %d\n", adapter->h2c_info.buf_fs);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * init_edca_cfg_8821c() - init EDCA config
+ * @adapter : the adapter of halmac
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+init_edca_cfg_8821c(struct halmac_adapter *adapter)
+{
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	/* Init SYNC_CLI_SEL : reg 0x5B4[6:4] = 0 */
+	HALMAC_REG_W8_CLR(REG_TIMER0_SRC_SEL, BIT(4) | BIT(5) | BIT(6));
+
+	/* Clear TX pause */
+	HALMAC_REG_W16(REG_TXPAUSE, 0x0000);
+
+	HALMAC_REG_W8(REG_SLOT, WLAN_SLOT_TIME);
+	HALMAC_REG_W8(REG_PIFS, WLAN_PIFS_TIME);
+	HALMAC_REG_W32(REG_SIFS, WLAN_SIFS_CFG);
+
+	HALMAC_REG_W16(REG_EDCA_VO_PARAM + 2, WLAN_VO_TXOP_LIMIT);
+	HALMAC_REG_W16(REG_EDCA_VI_PARAM + 2, WLAN_VI_TXOP_LIMIT);
+
+	HALMAC_REG_W32(REG_RD_NAV_NXT, WLAN_NAV_CFG);
+	HALMAC_REG_W16(REG_RXTSF_OFFSET_CCK, WLAN_RX_TSF_CFG);
+
+	/* Set beacon cotnrol - enable TSF and other related functions */
+	HALMAC_REG_W8(REG_BCN_CTRL, (u8)(HALMAC_REG_R8(REG_BCN_CTRL) |
+					  BIT_EN_BCN_FUNCTION));
+
+	/* Set send beacon related registers */
+	HALMAC_REG_W32(REG_TBTT_PROHIBIT, WLAN_TBTT_TIME);
+	HALMAC_REG_W8(REG_DRVERLYINT, WLAN_DRV_EARLY_INT);
+	HALMAC_REG_W8(REG_BCNDMATIM, WLAN_BCN_DMA_TIME);
+
+	HALMAC_REG_W8_CLR(REG_TX_PTCL_CTRL + 1, BIT(4));
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * init_wmac_cfg_8821c() - init wmac config
+ * @adapter : the adapter of halmac
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+init_wmac_cfg_8821c(struct halmac_adapter *adapter)
+{
+	u8 value8;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	HALMAC_REG_W32(REG_RXFLTMAP0, WLAN_RX_FILTER0);
+	HALMAC_REG_W16(REG_RXFLTMAP2, WLAN_RX_FILTER2);
+
+	HALMAC_REG_W32(REG_RCR, WLAN_RCR_CFG);
+
+	HALMAC_REG_W8(REG_RX_PKT_LIMIT, WLAN_RXPKT_MAX_SZ_512);
+
+	HALMAC_REG_W8(REG_TCR + 2, WLAN_TX_FUNC_CFG2);
+	HALMAC_REG_W8(REG_TCR + 1, WLAN_TX_FUNC_CFG1);
+
+	HALMAC_REG_W8(REG_ACKTO_CCK, WLAN_ACK_TO_CCK);
+
+	HALMAC_REG_W32(REG_WMAC_OPTION_FUNCTION + 8, WLAN_MAC_OPT_FUNC2);
+
+	if (adapter->hw_cfg_info.trx_mode == HALMAC_TRNSFER_NORMAL)
+		value8 = WLAN_MAC_OPT_NORM_FUNC1;
+	else
+		value8 = WLAN_MAC_OPT_LB_FUNC1;
+
+	HALMAC_REG_W8(REG_WMAC_OPTION_FUNCTION + 4, value8);
+
+	status = api->halmac_init_low_pwr(adapter);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+#endif /* HALMAC_8821C_SUPPORT */

+ 43 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_init_8821c.h

@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#ifndef _HALMAC_INIT_8821C_H_
+#define _HALMAC_INIT_8821C_H_
+
+#include "../../halmac_api.h"
+
+#if HALMAC_8821C_SUPPORT
+
+enum halmac_ret_status
+mount_api_8821c(struct halmac_adapter *adapter);
+
+enum halmac_ret_status
+init_trx_cfg_8821c(struct halmac_adapter *adapter, enum halmac_trx_mode mode);
+
+enum halmac_ret_status
+init_protocol_cfg_8821c(struct halmac_adapter *adapter);
+
+enum halmac_ret_status
+init_h2c_8821c(struct halmac_adapter *adapter);
+
+enum halmac_ret_status
+init_edca_cfg_8821c(struct halmac_adapter *adapter);
+
+enum halmac_ret_status
+init_wmac_cfg_8821c(struct halmac_adapter *adapter);
+
+#endif /* HALMAC_8821C_SUPPORT */
+
+#endif/* _HALMAC_INIT_8821C_H_ */

+ 356 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_pcie_8821c.c

@@ -0,0 +1,356 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "halmac_pcie_8821c.h"
+#include "halmac_pwr_seq_8821c.h"
+#include "../halmac_init_88xx.h"
+#include "../halmac_common_88xx.h"
+#include "../halmac_pcie_88xx.h"
+#include "halmac_8821c_cfg.h"
+
+#if (HALMAC_8821C_SUPPORT && HALMAC_PCIE_SUPPORT)
+
+#define INTF_INTGRA_MINREF	90
+#define INTF_INTGRA_HOSTREF	100
+
+static u16
+get_target(struct halmac_adapter *adapter);
+
+static enum halmac_ret_status
+freerun_delay_us(struct halmac_adapter *adapter, u16 delay);
+
+/**
+ * mac_pwr_switch_pcie_8821c() - switch mac power
+ * @adapter : the adapter of halmac
+ * @pwr : power state
+ * Author : KaiYuan Chang / Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+mac_pwr_switch_pcie_8821c(struct halmac_adapter *adapter,
+			  enum halmac_mac_power pwr)
+{
+	u8 value8;
+	u8 rpwm;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	enum halmac_ret_status status;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+	PLTFM_MSG_TRACE("[TRACE]pwr = %x\n", pwr);
+	PLTFM_MSG_TRACE("[TRACE]8821C pwr seq ver = %s\n",
+			HALMAC_8821C_PWR_SEQ_VER);
+
+	adapter->rpwm = HALMAC_REG_R8(REG_PCIE_HRPWM1_V1);
+
+	/* Check FW still exist or not */
+	if (HALMAC_REG_R16(REG_MCUFW_CTRL) == 0xC078) {
+		/* Leave 32K */
+		rpwm = (u8)((adapter->rpwm ^ BIT(7)) & 0x80);
+		HALMAC_REG_W8(REG_PCIE_HRPWM1_V1, rpwm);
+	}
+
+	value8 = HALMAC_REG_R8(REG_CR);
+	if (value8 == 0xEA)
+		adapter->halmac_state.mac_pwr = HALMAC_MAC_POWER_OFF;
+	else
+		adapter->halmac_state.mac_pwr = HALMAC_MAC_POWER_ON;
+
+	/* Check if power switch is needed */
+	if (pwr == HALMAC_MAC_POWER_ON &&
+	    adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_ON) {
+		PLTFM_MSG_WARN("[WARN]power state unchange!!\n");
+		return HALMAC_RET_PWR_UNCHANGE;
+	}
+
+	if (pwr == HALMAC_MAC_POWER_OFF) {
+		status = trxdma_check_idle_88xx(adapter);
+		if (status != HALMAC_RET_SUCCESS)
+			return status;
+		if (pwr_seq_parser_88xx(adapter, card_dis_flow_8821c) !=
+		    HALMAC_RET_SUCCESS) {
+			PLTFM_MSG_ERR("[ERR]Handle power off cmd error\n");
+			return HALMAC_RET_POWER_OFF_FAIL;
+		}
+
+		adapter->halmac_state.mac_pwr = HALMAC_MAC_POWER_OFF;
+		adapter->halmac_state.dlfw_state = HALMAC_DLFW_NONE;
+		init_adapter_dynamic_param_88xx(adapter);
+	} else {
+		if (pwr_seq_parser_88xx(adapter, card_en_flow_8821c) !=
+		    HALMAC_RET_SUCCESS) {
+			PLTFM_MSG_ERR("[ERR]Handle power on cmd error\n");
+			return HALMAC_RET_POWER_ON_FAIL;
+		}
+
+		adapter->halmac_state.mac_pwr = HALMAC_MAC_POWER_ON;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * halmac_pcie_switch_8821c() - pcie gen1/gen2 switch
+ * @adapter : the adapter of halmac
+ * @cfg : gen1/gen2 selection
+ * Author : KaiYuan Chang / Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+pcie_switch_8821c(struct halmac_adapter *adapter, enum halmac_pcie_cfg cfg)
+{
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * phy_cfg_pcie_8821c() - phy config
+ * @adapter : the adapter of halmac
+ * Author : KaiYuan Chang / Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+phy_cfg_pcie_8821c(struct halmac_adapter *adapter,
+		   enum halmac_intf_phy_platform pltfm)
+{
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	status = parse_intf_phy_88xx(adapter, pcie_gen1_phy_param_8821c, pltfm,
+				     HAL_INTF_PHY_PCIE_GEN1);
+
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	status = parse_intf_phy_88xx(adapter, pcie_gen2_phy_param_8821c, pltfm,
+				     HAL_INTF_PHY_PCIE_GEN2);
+
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * intf_tun_pcie_8821c() - pcie interface fine tuning
+ * @adapter : the adapter of halmac
+ * Author : Rick Liu
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+intf_tun_pcie_8821c(struct halmac_adapter *adapter)
+{
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+auto_refclk_cal_8821c_pcie(struct halmac_adapter *adapter)
+{
+	u8 bdr_ori;
+	u16 tmp_u16;
+	u16 div_set;
+	u16 mgn_tmp;
+	u16 mgn_set;
+	u16 tar;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+	u8 l1_flag = 0;
+
+#if (INTF_INTGRA_HOSTREF <= INTF_INTGRA_MINREF || 0 >= INTF_INTGRA_MINREF)
+	return status;
+#endif
+	/* Disable L1BD */
+	bdr_ori = dbi_r8_88xx(adapter, PCIE_L1_BACKDOOR);
+	if (bdr_ori & (BIT(4) | BIT(3))) {
+		status = dbi_w8_88xx(adapter, PCIE_L1_BACKDOOR,
+				     bdr_ori & ~(BIT(4) | BIT(3)));
+		if (status != HALMAC_RET_SUCCESS)
+			return status;
+		l1_flag = 1;
+	}
+
+	/* Disable function */
+	tmp_u16 = mdio_read_88xx(adapter, RAC_CTRL_PPR,
+				 HAL_INTF_PHY_PCIE_GEN1);
+	if (tmp_u16 & BIT(9)) {
+		status = mdio_write_88xx(adapter, RAC_CTRL_PPR,
+					 tmp_u16 & ~(BIT(9)),
+					 HAL_INTF_PHY_PCIE_GEN1);
+		if (status != HALMAC_RET_SUCCESS)
+			return status;
+	}
+	if (adapter->pcie_refautok_en == 0) {
+		if (l1_flag == 1)
+			status = dbi_w8_88xx(adapter, PCIE_L1_BACKDOOR,
+					     bdr_ori);
+		return status;
+	}
+
+	/* Set div */
+	tmp_u16 = mdio_read_88xx(adapter, RAC_CTRL_PPR, HAL_INTF_PHY_PCIE_GEN1);
+	status = mdio_write_88xx(adapter, RAC_CTRL_PPR,
+				 tmp_u16 & ~(BIT(7) | BIT(6)),
+				 HAL_INTF_PHY_PCIE_GEN1);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	/*  Obtain div and margin */
+	tar = get_target(adapter);
+	if (tar == 0xFFFF)
+		return HALMAC_RET_FAIL;
+	mgn_tmp = tar * INTF_INTGRA_HOSTREF / INTF_INTGRA_MINREF - tar;
+
+	if (mgn_tmp >= 128) {
+		div_set = 0x0003;
+		mgn_set = 0x000F;
+	} else if (mgn_tmp >= 64) {
+		div_set = 0x0003;
+		mgn_set = mgn_tmp >> 3;
+	} else if (mgn_tmp >= 32) {
+		div_set = 0x0002;
+		mgn_set = mgn_tmp >> 2;
+	} else if (mgn_tmp >= 16) {
+		div_set = 0x0001;
+		mgn_set = mgn_tmp >> 1;
+	} else if (mgn_tmp == 0) {
+		div_set = 0x0000;
+		mgn_set = 0x0001;
+	} else {
+		div_set = 0x0000;
+		mgn_set = mgn_tmp;
+	}
+
+	/* Set div, margin, target*/
+	tmp_u16 = mdio_read_88xx(adapter, RAC_CTRL_PPR, HAL_INTF_PHY_PCIE_GEN1);
+	tmp_u16 = (tmp_u16 & ~(BIT(7) | BIT(6))) | (div_set << 6);
+	status = mdio_write_88xx(adapter, RAC_CTRL_PPR,
+				 tmp_u16, HAL_INTF_PHY_PCIE_GEN1);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+	tar = get_target(adapter);
+	if (tar == 0xFFFF)
+		return HALMAC_RET_FAIL;
+	PLTFM_MSG_TRACE("[TRACE]target = 0x%X, div = 0x%X, margin = 0x%X\n",
+			tar, div_set, mgn_set);
+	status = mdio_write_88xx(adapter, RAC_SET_PPR,
+				 (tar & 0x0FFF) | (mgn_set << 12),
+				 HAL_INTF_PHY_PCIE_GEN1);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+
+	/* Enable function */
+	tmp_u16 = mdio_read_88xx(adapter, RAC_CTRL_PPR, HAL_INTF_PHY_PCIE_GEN1);
+	status = mdio_write_88xx(adapter, RAC_CTRL_PPR, tmp_u16 | BIT(9),
+				 HAL_INTF_PHY_PCIE_GEN1);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	/* Set L1BD to ori */
+	if (l1_flag == 1)
+		status = dbi_w8_88xx(adapter, PCIE_L1_BACKDOOR, bdr_ori);
+
+	return status;
+}
+
+static u16
+get_target(struct halmac_adapter *adapter)
+{
+	u16 tmp_u16;
+	u16 tar;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+
+	/* Enable counter */
+	tmp_u16 = mdio_read_88xx(adapter, RAC_CTRL_PPR, HAL_INTF_PHY_PCIE_GEN1);
+	status = mdio_write_88xx(adapter, RAC_CTRL_PPR,
+				 tmp_u16 | BIT(11), HAL_INTF_PHY_PCIE_GEN1);
+	if (status != HALMAC_RET_SUCCESS)
+		return 0xFFFF;
+
+	/* Obtain target */
+	status = freerun_delay_us(adapter, 300);
+	if (status != HALMAC_RET_SUCCESS)
+		return 0xFFFF;
+	tar = mdio_read_88xx(adapter, RAC_TRG_PPR, HAL_INTF_PHY_PCIE_GEN1);
+	if (tar == 0) {
+		PLTFM_MSG_ERR("[ERR]Get target failed.\n");
+		return 0xFFFF;
+	}
+
+	/* Disable counter */
+	tmp_u16 = mdio_read_88xx(adapter, RAC_CTRL_PPR, HAL_INTF_PHY_PCIE_GEN1);
+	status = mdio_write_88xx(adapter, RAC_CTRL_PPR,
+				 tmp_u16 & ~(BIT(11)), HAL_INTF_PHY_PCIE_GEN1);
+	if (status != HALMAC_RET_SUCCESS)
+		return 0xFFFF;
+	return tar;
+}
+
+static enum halmac_ret_status
+freerun_delay_us(struct halmac_adapter *adapter, u16 delay)
+{
+	u16 count;
+	u8 mc_ori;
+	u32 frcnt_ori;
+	u32 frcnt_cmp;
+	u8 frcnt_onflg = 0;
+	u32 cmp_val;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+
+	/* Enable free-run counter */
+	mc_ori = HALMAC_REG_R8(REG_MISC_CTRL);
+	if ((mc_ori & BIT(3)) == 0) {
+		status = HALMAC_REG_W8(REG_MISC_CTRL, mc_ori | BIT(3));
+		if (status != HALMAC_RET_SUCCESS)
+			return status;
+		frcnt_onflg = 1;
+	}
+
+	/* counting delay */
+	count = 20;
+	frcnt_ori = HALMAC_REG_R32(REG_FREERUN_CNT);
+	PLTFM_MSG_TRACE("[TRACE]free_ori = 0x%X\n", frcnt_ori);
+	do {
+		PLTFM_DELAY_US(100);
+		count--;
+		frcnt_cmp = HALMAC_REG_R32(REG_FREERUN_CNT);
+		PLTFM_MSG_TRACE("[TRACE]Count=0x%X, free_cmp=0x%X\n"
+				, count, frcnt_cmp);
+		if (frcnt_cmp >= frcnt_ori)
+			cmp_val = frcnt_cmp - frcnt_ori;
+		else
+			cmp_val = 0xFFFFFFFF - frcnt_ori + frcnt_cmp;
+	} while ((count > 0) && (cmp_val < delay));
+
+	/*  Reset freerun counter */
+	if (frcnt_onflg != 1)
+		return status;
+
+	status = HALMAC_REG_W8(REG_MISC_CTRL, mc_ori);
+	if (status != HALMAC_RET_SUCCESS)
+		return status;
+	status = HALMAC_REG_W8(REG_DUAL_TSF_RST,
+			       HALMAC_REG_R8(REG_DUAL_TSF_RST) | BIT(5));
+	return status;
+}
+
+#endif /* HALMAC_8821C_SUPPORT */

+ 45 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_pcie_8821c.h

@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#ifndef _HALMAC_PCIE_8821C_H_
+#define _HALMAC_PCIE_8821C_H_
+
+#include "../../halmac_api.h"
+
+#if (HALMAC_8821C_SUPPORT && HALMAC_PCIE_SUPPORT)
+
+extern struct halmac_intf_phy_para pcie_gen1_phy_param_8821c[];
+extern struct halmac_intf_phy_para pcie_gen2_phy_param_8821c[];
+
+enum halmac_ret_status
+mac_pwr_switch_pcie_8821c(struct halmac_adapter *adapter,
+			  enum halmac_mac_power pwr);
+
+enum halmac_ret_status
+pcie_switch_8821c(struct halmac_adapter *adapter, enum halmac_pcie_cfg cfg);
+
+enum halmac_ret_status
+phy_cfg_pcie_8821c(struct halmac_adapter *adapter,
+		   enum halmac_intf_phy_platform pltfm);
+
+enum halmac_ret_status
+intf_tun_pcie_8821c(struct halmac_adapter *adapter);
+
+enum halmac_ret_status
+auto_refclk_cal_8821c_pcie(struct halmac_adapter *adapter);
+
+#endif /* HALMAC_8821C_SUPPORT */
+
+#endif/* _HALMAC_PCIE_8821C_H_ */

+ 76 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_phy_8821c.c

@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "../../halmac_type.h"
+#if HALMAC_USB_SUPPORT
+#include "halmac_usb_8821c.h"
+#endif
+#if HALMAC_PCIE_SUPPORT
+#include "halmac_pcie_8821c.h"
+#endif
+
+/**
+ * ============ip sel item list============
+ * HALMAC_IP_INTF_PHY
+ *	USB2 : usb2 phy, 1byte value
+ *	USB3 : usb3 phy, 2byte value
+ *	PCIE1 : pcie gen1 mdio, 2byte value
+ *	PCIE2 : pcie gen2 mdio, 2byte value
+ * HALMAC_IP_SEL_MAC
+ *	USB2, USB3, PCIE1, PCIE2 : mac ip, 1byte value
+ * HALMAC_IP_PCIE_DBI
+ *	USB2 USB3 : none
+ *	PCIE1, PCIE2 : pcie dbi, 1byte value
+ */
+
+#if HALMAC_8821C_SUPPORT
+
+struct halmac_intf_phy_para usb2_phy_param_8821c[] = {
+	/* {offset, value, ip sel, cut mask, platform mask} */
+	{0xFFFF, 0x00,
+	 HALMAC_IP_INTF_PHY,
+	 HALMAC_INTF_PHY_CUT_ALL,
+	 HALMAC_INTF_PHY_PLATFORM_ALL},
+};
+
+struct halmac_intf_phy_para usb3_phy_param_8821c[] = {
+	/* {offset, value, cut mask, platform mask} */
+	{0xFFFF, 0x0000,
+	 HALMAC_IP_INTF_PHY,
+	 HALMAC_INTF_PHY_CUT_ALL,
+	 HALMAC_INTF_PHY_PLATFORM_ALL},
+};
+
+struct halmac_intf_phy_para pcie_gen1_phy_param_8821c[] = {
+	/* {offset, value, ip sel, cut mask, platform mask} */
+	{0x0009, 0x6380,
+	 HALMAC_IP_INTF_PHY,
+	 HALMAC_INTF_PHY_CUT_ALL,
+	 HALMAC_INTF_PHY_PLATFORM_ALL},
+	{0xFFFF, 0x0000,
+	 HALMAC_IP_INTF_PHY,
+	 HALMAC_INTF_PHY_CUT_ALL,
+	 HALMAC_INTF_PHY_PLATFORM_ALL},
+};
+
+struct halmac_intf_phy_para pcie_gen2_phy_param_8821c[] = {
+	/* {offset, value, ip sel, cut mask, platform mask} */
+	{0xFFFF, 0x0000,
+	 HALMAC_IP_INTF_PHY,
+	 HALMAC_INTF_PHY_CUT_ALL,
+	 HALMAC_INTF_PHY_PLATFORM_ALL},
+};
+
+#endif /* HALMAC_8821C_SUPPORT */

+ 905 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_pwr_seq_8821c.c

@@ -0,0 +1,905 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "halmac_pwr_seq_8821c.h"
+
+#if HALMAC_8821C_SUPPORT
+
+static struct halmac_wlan_pwr_cfg TRANS_CARDDIS_TO_CARDEMU_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0086,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0},
+	{0x0086,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_POLLING, BIT(1), BIT(1)},
+	{0x004A,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3) | BIT(4) | BIT(7), 0},
+	{0x0300,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0},
+	{0x0301,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_CARDEMU_TO_ACT_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0020,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0001,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_DELAY, 1, HALMAC_PWR_DELAY_MS},
+	{0x0000,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(5), 0},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, (BIT(4) | BIT(3) | BIT(2)), 0},
+	{0x0075,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0006,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, BIT(1), BIT(1)},
+	{0x0075,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0 },
+	{0x0006,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), 0 },
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, (BIT(4) | BIT(3)), 0},
+	{0x10C3,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, BIT(0), 0},
+	{0x0020,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3), BIT(3)},
+	{0x0074,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(5), BIT(5)},
+	{0x0022,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x0062,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, (BIT(7) | BIT(6) | BIT(5)),
+	 (BIT(7) | BIT(6) | BIT(5))},
+	{0x0061,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, (BIT(7) | BIT(6) | BIT(5)), 0},
+	{0x007C,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0 },
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_ACT_TO_CARDEMU_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0093,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3), 0},
+	{0x001F,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0},
+	{0x0049,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x0006,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x10C3,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), BIT(1)},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, BIT(1), 0},
+	{0x0020,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3), 0},
+	{0x0000,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(5), BIT(5)},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_CARDEMU_TO_CARDDIS_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0007,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x20},
+	{0x0067,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(5), 0},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(2), BIT(2)},
+	{0x004A,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0},
+	{0x0067,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(5), 0 },
+	{0x0067,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(4), 0 },
+	{0x004F,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0 },
+	{0x0067,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0 },
+	{0x0046,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(6), BIT(6) },
+	{0x0067,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(2), 0 },
+	{0x0046,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), BIT(7) },
+	{0x0062,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(4), BIT(4) },
+	{0x0081,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7) | BIT(6), 0},
+	{0x0086,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0086,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_POLLING, BIT(1), 0},
+	{0x0090,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x0044,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0},
+	{0x0040,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x90},
+	{0x0041,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x00},
+	{0x0042,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x04},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+/* Card Enable Array */
+struct halmac_wlan_pwr_cfg *card_en_flow_8821c[] = {
+	TRANS_CARDDIS_TO_CARDEMU_8821C,
+	TRANS_CARDEMU_TO_ACT_8821C,
+	NULL
+};
+
+/* Card Disable Array */
+struct halmac_wlan_pwr_cfg *card_dis_flow_8821c[] = {
+	TRANS_ACT_TO_CARDEMU_8821C,
+	TRANS_CARDEMU_TO_CARDDIS_8821C,
+	NULL
+};
+
+#if HALMAC_PLATFORM_TESTPROGRAM
+
+static struct halmac_wlan_pwr_cfg TRANS_CARDEMU_TO_SUS_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(4) | BIT(3), (BIT(4) | BIT(3))},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK | HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)},
+	{0x0007,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x20},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) | BIT(4)},
+	{0x0086,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0086,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_POLLING, BIT(1), 0},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_SUS_TO_CARDEMU_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3) | BIT(7), 0},
+	{0x0086,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0},
+	{0x0086,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_POLLING, BIT(1), BIT(1)},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3) | BIT(4), 0},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_CARDEMU_TO_PDN_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0007,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK | HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x20},
+	{0x0006,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0},
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), BIT(7)},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_PDN_TO_CARDEMU_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0005,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), 0},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_ACT_TO_LPS_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0101,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(2), BIT(2)},
+	{0x0199,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3), BIT(3)},
+	{0x019B,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), BIT(7)},
+	{0x1138,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0) | BIT(1), BIT(0) | BIT(1)},
+	{0x0194,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0093,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xD6},
+	{0x0092,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x60},
+	{0x0093,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x93},
+	{0x0092,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x60},
+	{0x0093,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x2},
+	{0x0092,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x60},
+	{0x0090,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), BIT(1)},
+	{0x0301,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF},
+	{0x0522,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF},
+	{0x05F8,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, 0xFF, 0},
+	{0x05F9,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, 0xFF, 0},
+	{0x05FA,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, 0xFF, 0},
+	{0x05FB,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, 0xFF, 0},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_DELAY, 0, HALMAC_PWR_DELAY_US},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x0100,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x3F},
+	{0x0101,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x0553,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(5), BIT(5)},
+	{0x0008,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(4), BIT(4)},
+	{0x0109,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, BIT(7), BIT(7)},
+	{0x0090,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_ACT_TO_DEEP_LPS_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0101,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(2), BIT(2)},
+	{0x0199,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(3), BIT(3)},
+	{0x019B,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), BIT(7)},
+	{0x1138,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0) | BIT(1), BIT(0) | BIT(1)},
+	{0x0194,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0x0093,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xD4},
+	{0x0092,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x20},
+	{0x0093,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x91},
+	{0x0092,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x20},
+	{0x0093,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x0},
+	{0x0092,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x20},
+	{0x0090,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), BIT(1)},
+	{0x0301,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF},
+	{0x0522,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF},
+	{0x05F8,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, 0xFF, 0},
+	{0x05F9,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, 0xFF, 0},
+	{0x05FA,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, 0xFF, 0},
+	{0x05FB,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, 0xFF, 0},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), 0},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_DELAY, 0, HALMAC_PWR_DELAY_US},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x0100,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x3F},
+	{0x0101,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x0553,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(5), BIT(5)},
+	{0x0008,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(4), BIT(4)},
+	{0x0109,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, BIT(7), BIT(7)},
+	{0x0090,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(0), BIT(0)},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+static struct halmac_wlan_pwr_cfg TRANS_LPS_TO_ACT_8821C[] = {
+	/* { offset, cut_msk, interface_msk, base|cmd, msk, value } */
+	{0x0080,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), BIT(7)},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_DELAY, 0, HALMAC_PWR_DELAY_MS},
+	{0x0080,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_SDIO_MSK,
+	 HALMAC_PWR_ADDR_SDIO,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), 0},
+	{0xFE58,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x84},
+	{0xFE58,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_USB_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x04},
+	{0x03D9,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), BIT(7)},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_DELAY, 0, HALMAC_PWR_DELAY_MS},
+	{0x03D9,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_PCI_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(7), 0},
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_DELAY, 0, HALMAC_PWR_DELAY_MS},
+	{0x0008,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(4), 0},
+	{0x0109,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_POLLING, BIT(7), 0},
+	{0x0101,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), BIT(1)},
+	{0x0100,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF },
+	{0x0002,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1) | BIT(0), BIT(1) | BIT(0)},
+	{0x0522,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0},
+	{0x113C,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0x03},
+	{0x0124,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF},
+	{0x0125,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF},
+	{0x0126,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF},
+	{0x0127,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, 0xFF, 0xFF},
+	{0x0090,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(1), 0},
+	{0x0101,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 HALMAC_PWR_ADDR_MAC,
+	 HALMAC_PWR_CMD_WRITE, BIT(2), 0},
+	{0xFFFF,
+	 HALMAC_PWR_CUT_ALL_MSK,
+	 HALMAC_PWR_INTF_ALL_MSK,
+	 0,
+	 HALMAC_PWR_CMD_END, 0, 0},
+};
+
+/* Suspend Array */
+struct halmac_wlan_pwr_cfg *suspend_flow_8821c[] = {
+	TRANS_ACT_TO_CARDEMU_8821C,
+	TRANS_CARDEMU_TO_SUS_8821C,
+	NULL
+};
+
+/* Resume Array */
+struct halmac_wlan_pwr_cfg *resume_flow_8821c[] = {
+	TRANS_SUS_TO_CARDEMU_8821C,
+	TRANS_CARDEMU_TO_ACT_8821C,
+	NULL
+};
+
+/* HWPDN Array - HW behavior */
+struct halmac_wlan_pwr_cfg *hwpdn_flow_8821c[] = {
+	NULL
+};
+
+/* Enter LPS - FW behavior */
+struct halmac_wlan_pwr_cfg *enter_lps_flow_8821c[] = {
+	TRANS_ACT_TO_LPS_8821C,
+	NULL
+};
+
+/* Enter Deep LPS - FW behavior */
+struct halmac_wlan_pwr_cfg *enter_dlps_flow_8821c[] = {
+	TRANS_ACT_TO_DEEP_LPS_8821C,
+	NULL
+};
+
+/* Leave LPS -FW behavior */
+struct halmac_wlan_pwr_cfg *leave_lps_flow_8821c[] = {
+	TRANS_LPS_TO_ACT_8821C,
+	NULL
+};
+
+#endif
+
+#endif /* HALMAC_8821C_SUPPORT */

+ 37 - 0
hal/halmac/halmac_88xx/halmac_8821c/halmac_pwr_seq_8821c.h

@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#ifndef HALMAC_POWER_SEQUENCE_8821C
+#define HALMAC_POWER_SEQUENCE_8821C
+
+#include "../../halmac_pwr_seq_cmd.h"
+#include "../../halmac_hw_cfg.h"
+
+#if HALMAC_8821C_SUPPORT
+
+#define HALMAC_8821C_PWR_SEQ_VER  "V19"
+
+extern struct halmac_wlan_pwr_cfg *card_dis_flow_8821c[];
+extern struct halmac_wlan_pwr_cfg *card_en_flow_8821c[];
+extern struct halmac_wlan_pwr_cfg *suspend_flow_8821c[];
+extern struct halmac_wlan_pwr_cfg *resume_flow_8821c[];
+extern struct halmac_wlan_pwr_cfg *hwpdn_flow_8821c[];
+extern struct halmac_wlan_pwr_cfg *enter_lps_flow_8821c[];
+extern struct halmac_wlan_pwr_cfg *enter_dlps_flow_8821c[];
+extern struct halmac_wlan_pwr_cfg *leave_lps_flow_8821c[];
+
+#endif /* HALMAC_8821C_SUPPORT */
+
+#endif

+ 31 - 150
hal/halmac/halmac_88xx/halmac_88xx_cfg.h

@@ -1,163 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
 #ifndef _HALMAC_88XX_CFG_H_
 #define _HALMAC_88XX_CFG_H_
 
-#include "../halmac_2_platform.h"
-#include "../halmac_type.h"
-#include "../halmac_hw_cfg.h"
 #include "../halmac_api.h"
-#include "../halmac_bit2.h"
-#include "../halmac_reg2.h"
-#include "../halmac_pwr_seq_cmd.h"
-#include "halmac_func_88xx.h"
-#include "halmac_api_88xx.h"
-#include "halmac_api_88xx_usb.h"
-#include "halmac_api_88xx_pcie.h"
-#include "halmac_api_88xx_sdio.h"
-#if HALMAC_PLATFORM_TESTPROGRAM
-#include "halmisc_api_88xx.h"
-#include "halmisc_api_88xx_usb.h"
-#include "halmisc_api_88xx_pcie.h"
-#include "halmisc_api_88xx_sdio.h"
-#endif
-
-#define HALMAC_SVN_VER_88XX "13359M"
-
-#define HALMAC_MAJOR_VER_88XX        0x0001 /* major version, ver_1 for async_api */
-#define HALMAC_PROTOTYPE_VER_88XX    0x0003 /* For halmac_api num change or prototype change, increment prototype version */
-#define HALMAC_MINOR_VER_88XX        0x0006 /* else increment minor version */
-#define HALMAC_PATCH_VER_88XX        0x0002 /* patch version */
-
-#define HALMAC_C2H_DATA_OFFSET_88XX             10
-#define HALMAC_RX_AGG_ALIGNMENT_SIZE_88XX       8
-#define HALMAC_TX_AGG_ALIGNMENT_SIZE_88XX       8
-#define HALMAC_TX_AGG_BUFF_SIZE_88XX            32768
-#define HALMAC_RX_DESC_DUMMY_SIZE_MAX_88XX      80 /*8*10 Bytes*/
-#define HALMAC_RX_FIFO_EXPANDING_MODE_PKT_SIZE_MAX_88XX    80 /* should be 8 Byte alignment*/
-
-#define HALMAC_TX_PAGE_SIZE_88XX			128 /* PageSize 128Byte */
-#define HALMAC_TX_PAGE_SIZE_2_POWER_88XX	7   /* 128 = 2^7 */
-
-#define HALMAC_EXTRA_INFO_BUFF_SIZE_88XX				4096 /*4K*/
-#define HALMAC_EXTRA_INFO_BUFF_SIZE_FULL_FIFO_88XX		16384 /*16K*/
-#define HALMAC_FW_OFFLOAD_CMD_SIZE_88XX					12 /*Fw config parameter cmd size, each 12 byte*/
 
-#define HALMAC_H2C_CMD_ORIGINAL_SIZE_88XX       8
-#define HALMAC_H2C_CMD_SIZE_UNIT_88XX           32 /* Only support 32 byte packet now */
+#if HALMAC_88XX_SUPPORT
 
-#define HALMAC_NLO_INFO_SIZE_88XX	1024
+#define TX_PAGE_SIZE_88XX		128
+#define TX_PAGE_SIZE_SHIFT_88XX		7 /* 128 = 2^7 */
+#define TX_ALIGN_SIZE_88XX		8
+#define SDIO_TX_MAX_SIZE_88XX		31744
+#define RX_BUF_FW_88XX			12288
 
-/* Download FW */
-#define HALMAC_FW_SIZE_MAX_88XX                 0x40000
-#define HALMAC_FWHDR_SIZE_88XX                  64
-#define HALMAC_FW_CHKSUM_DUMMY_SIZE_88XX        8
-#define HALMAC_FW_MAX_DL_SIZE_88XX              0x2000 /* need power of 2 */
-/* Max dlfw size can not over 31K, because SDIO HW restriction */
-#define HALMAC_FW_CFG_MAX_DL_SIZE_MAX_88XX      0x7C00
+#define TX_DESC_SIZE_88XX		48
+#define RX_DESC_SIZE_88XX		24
 
-#define DLFW_RESTORE_REG_NUM_88XX       9
-#define ID_INFORM_DLEMEM_RDY		0x80
-
-/* FW header information */
-#define HALMAC_FWHDR_OFFSET_VERSION_88XX                4
-#define HALMAC_FWHDR_OFFSET_SUBVERSION_88XX             6
-#define HALMAC_FWHDR_OFFSET_SUBINDEX_88XX               7
-#define HALMAC_FWHDR_OFFSET_MONTH_88XX                  16
-#define HALMAC_FWHDR_OFFSET_DATE_88XX                   17
-#define HALMAC_FWHDR_OFFSET_HOUR_88XX                   18
-#define HALMAC_FWHDR_OFFSET_MIN_88XX                    19
-#define HALMAC_FWHDR_OFFSET_YEAR_88XX                   20
-#define HALMAC_FWHDR_OFFSET_MEM_USAGE_88XX              24
-#define HALMAC_FWHDR_OFFSET_H2C_FORMAT_VER_88XX			28
-#define HALMAC_FWHDR_OFFSET_DMEM_ADDR_88XX              32
-#define HALMAC_FWHDR_OFFSET_DMEM_SIZE_88XX              36
-#define HALMAC_FWHDR_OFFSET_IRAM_SIZE_88XX              48
-#define HALMAC_FWHDR_OFFSET_ERAM_SIZE_88XX              52
-#define HALMAC_FWHDR_OFFSET_EMEM_ADDR_88XX              56
-#define HALMAC_FWHDR_OFFSET_IRAM_ADDR_88XX              60
+#define H2C_PKT_SIZE_88XX		32 /* Only support 32 byte packet now */
+#define H2C_PKT_HDR_SIZE_88XX		8
+#define C2H_DATA_OFFSET_88XX		10
+#define C2H_PKT_BUF_88XX		256
 
 /* HW memory address */
-#define HALMAC_OCPBASE_TXBUF_88XX				0x18780000
-#define HALMAC_OCPBASE_DMEM_88XX                0x00200000
-#define HALMAC_OCPBASE_IMEM_88XX                0x00000000
-
-/* define the SDIO Bus CLK threshold, for avoiding CMD53 fails that result from SDIO CLK sync to ana_clk fail */
-#define HALMAC_SDIO_CLK_THRESHOLD_88XX          150 /* 150MHz */
-#define HALMAC_SDIO_CLOCK_SPEED_MAX_88XX	208 /* 208MHz */
-
-/* MAC clock */
-#define HALMAC_MAC_CLOCK_88XX   80 /* 80M */
-
-/* H2C/C2H*/
-#define HALMAC_H2C_CMD_SIZE_88XX		32
-#define HALMAC_H2C_CMD_HDR_SIZE_88XX    8
-
-#define HALMAC_PROTECTED_EFUSE_SIZE_88XX 0x60
-
-/* Function enable */
-#define HALMAC_FUNCTION_ENABLE_88XX     0xDC
-
-/* FIFO size & packet size */
-/* #define HALMAC_WOWLAN_PATTERN_SIZE	256 */
-
-/* CFEND rate */
-#define HALMAC_BASIC_CFEND_RATE_88XX    0x5
-#define HALMAC_STBC_CFEND_RATE_88XX     0xF
-
-/* Response rate */
-#define HALMAC_RESPONSE_RATE_BITMAP_ALL_88XX    0xFFFFF
-#define HALMAC_RESPONSE_RATE_88XX				HALMAC_RESPONSE_RATE_BITMAP_ALL_88XX
-
-/* Spec SIFS */
-#define HALMAC_SIFS_CCK_PTCL_88XX       16
-#define HALMAC_SIFS_OFDM_PTCL_88XX      16
-
-/* Retry limit */
-#define HALMAC_LONG_RETRY_LIMIT_88XX    8
-#define HALMAC_SHORT_RETRY_LIMIT_88XX   7
-
-/* Slot, SIFS, PIFS time */
-#define HALMAC_SLOT_TIME_88XX           0x05
-#define HALMAC_PIFS_TIME_88XX           0x19
-#define HALMAC_SIFS_CCK_CTX_88XX        0xA
-#define HALMAC_SIFS_OFDM_CTX_88XX       0xA
-#define HALMAC_SIFS_CCK_TRX_88XX        0x10
-#define HALMAC_SIFS_OFDM_TRX_88XX       0x10
-
-/* TXOP limit */
-#define HALMAC_VO_TXOP_LIMIT_88XX       0x186
-#define HALMAC_VI_TXOP_LIMIT_88XX       0x3BC
-
-/* NAV */
-#define HALMAC_RDG_NAV_88XX             0x05
-#define HALMAC_TXOP_NAV_88XX            0x1B
-
-/* TSF */
-#define HALMAC_CCK_RX_TSF_88XX			0x30
-#define HALMAC_OFDM_RX_TSF_88XX			0x30
-
-/* Send beacon related */
-#define HALMAC_TBTT_PROHIBIT_88XX       0x04
-#define HALMAC_TBTT_HOLD_TIME_88XX      0x064
-#define HALMAC_DRIVER_EARLY_INT_88XX    0x04
-#define HALMAC_BEACON_DMA_TIM_88XX      0x02
-
-/* RX filter */
-#define HALMAC_RX_FILTER0_RECIVE_ALL_88XX       0xFFFFFFF
-#define HALMAC_RX_FILTER0_88XX                  HALMAC_RX_FILTER0_RECIVE_ALL_88XX
-#define HALMAC_RX_FILTER_RECIVE_ALL_88XX        0xFFFF
-#define HALMAC_RX_FILTER_88XX                   HALMAC_RX_FILTER_RECIVE_ALL_88XX
-
-/* RCR */
-#define HALMAC_RCR_CONFIG_88XX  0xE400631E
-
-/* Security config */
-#define HALMAC_SECURITY_CONFIG_88XX     0x01CC
-
-/* CCK rate ACK timeout */
-#define HALMAC_ACK_TO_CCK_88XX    0x40
+#define OCPBASE_TXBUF_88XX		0x18780000
+#define OCPBASE_DMEM_88XX		0x00200000
+#define OCPBASE_EMEM_88XX		0x00100000
 
-/* RX pkt max size */
-#define HALMAC_RXPKT_MAX_SIZE			12288 /* 12K */
-#define HALMAC_RXPKT_MAX_SIZE_BASE512	(HALMAC_RXPKT_MAX_SIZE >> 9)
+#endif /* HALMAC_88XX_SUPPORT */
 
 #endif

+ 395 - 0
hal/halmac/halmac_88xx/halmac_bb_rf_88xx.c

@@ -0,0 +1,395 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "halmac_bb_rf_88xx.h"
+#include "halmac_88xx_cfg.h"
+#include "halmac_common_88xx.h"
+#include "halmac_init_88xx.h"
+
+#if HALMAC_88XX_SUPPORT
+
+/**
+ * start_iqk_88xx() -trigger FW IQK
+ * @adapter : the adapter of halmac
+ * @param : IQK parameter
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+start_iqk_88xx(struct halmac_adapter *adapter, struct halmac_iqk_para *param)
+{
+	u8 h2c_buf[H2C_PKT_SIZE_88XX] = { 0 };
+	u16 seq_num = 0;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+	struct halmac_h2c_header_info hdr_info;
+	enum halmac_cmd_process_status *proc_status;
+
+	proc_status = &adapter->halmac_state.iqk_state.proc_status;
+
+	if (halmac_fw_validate(adapter) != HALMAC_RET_SUCCESS)
+		return HALMAC_RET_NO_DLFW;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
+		PLTFM_MSG_TRACE("[TRACE]Wait event(iqk)\n");
+		return HALMAC_RET_BUSY_STATE;
+	}
+
+	*proc_status = HALMAC_CMD_PROCESS_SENDING;
+
+	IQK_SET_CLEAR(h2c_buf, param->clear);
+	IQK_SET_SEGMENT_IQK(h2c_buf, param->segment_iqk);
+
+	hdr_info.sub_cmd_id = SUB_CMD_ID_IQK;
+	hdr_info.content_size = 1;
+	hdr_info.ack = 1;
+	set_h2c_pkt_hdr_88xx(adapter, h2c_buf, &hdr_info, &seq_num);
+
+	adapter->halmac_state.iqk_state.seq_num = seq_num;
+
+	status = send_h2c_pkt_88xx(adapter, h2c_buf);
+
+	if (status != HALMAC_RET_SUCCESS) {
+		PLTFM_MSG_ERR("[ERR]send h2c pkt fail!!\n");
+		reset_ofld_feature_88xx(adapter, HALMAC_FEATURE_IQK);
+		return status;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * ctrl_pwr_tracking_88xx() -trigger FW power tracking
+ * @adapter : the adapter of halmac
+ * @opt : power tracking option
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+ctrl_pwr_tracking_88xx(struct halmac_adapter *adapter,
+		       struct halmac_pwr_tracking_option *opt)
+{
+	u8 h2c_buf[H2C_PKT_SIZE_88XX] = { 0 };
+	u16 seq_num = 0;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+	struct halmac_h2c_header_info hdr_info;
+	struct halmac_pwr_tracking_para *param;
+	enum halmac_cmd_process_status *proc_status;
+
+	proc_status = &adapter->halmac_state.pwr_trk_state.proc_status;
+
+	if (halmac_fw_validate(adapter) != HALMAC_RET_SUCCESS)
+		return HALMAC_RET_NO_DLFW;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
+		PLTFM_MSG_TRACE("[TRACE]Wait event(pwr tracking)...\n");
+		return HALMAC_RET_BUSY_STATE;
+	}
+
+	*proc_status = HALMAC_CMD_PROCESS_SENDING;
+
+	PWR_TRK_SET_TYPE(h2c_buf, opt->type);
+	PWR_TRK_SET_BBSWING_INDEX(h2c_buf, opt->bbswing_index);
+
+	param = &opt->pwr_tracking_para[HALMAC_RF_PATH_A];
+	PWR_TRK_SET_ENABLE_A(h2c_buf, param->enable);
+	PWR_TRK_SET_TX_PWR_INDEX_A(h2c_buf, param->tx_pwr_index);
+	PWR_TRK_SET_TSSI_VALUE_A(h2c_buf, param->tssi_value);
+	PWR_TRK_SET_OFFSET_VALUE_A(h2c_buf, param->pwr_tracking_offset_value);
+
+	param = &opt->pwr_tracking_para[HALMAC_RF_PATH_B];
+	PWR_TRK_SET_ENABLE_B(h2c_buf, param->enable);
+	PWR_TRK_SET_TX_PWR_INDEX_B(h2c_buf, param->tx_pwr_index);
+	PWR_TRK_SET_TSSI_VALUE_B(h2c_buf, param->tssi_value);
+	PWR_TRK_SET_OFFSET_VALUE_B(h2c_buf, param->pwr_tracking_offset_value);
+
+	param = &opt->pwr_tracking_para[HALMAC_RF_PATH_C];
+	PWR_TRK_SET_ENABLE_C(h2c_buf, param->enable);
+	PWR_TRK_SET_TX_PWR_INDEX_C(h2c_buf, param->tx_pwr_index);
+	PWR_TRK_SET_TSSI_VALUE_C(h2c_buf, param->tssi_value);
+	PWR_TRK_SET_OFFSET_VALUE_C(h2c_buf, param->pwr_tracking_offset_value);
+
+	param = &opt->pwr_tracking_para[HALMAC_RF_PATH_D];
+	PWR_TRK_SET_ENABLE_D(h2c_buf, param->enable);
+	PWR_TRK_SET_TX_PWR_INDEX_D(h2c_buf, param->tx_pwr_index);
+	PWR_TRK_SET_TSSI_VALUE_D(h2c_buf, param->tssi_value);
+	PWR_TRK_SET_OFFSET_VALUE_D(h2c_buf, param->pwr_tracking_offset_value);
+
+	hdr_info.sub_cmd_id = SUB_CMD_ID_PWR_TRK;
+	hdr_info.content_size = 20;
+	hdr_info.ack = 1;
+	set_h2c_pkt_hdr_88xx(adapter, h2c_buf, &hdr_info, &seq_num);
+
+	adapter->halmac_state.pwr_trk_state.seq_num = seq_num;
+
+	status = send_h2c_pkt_88xx(adapter, h2c_buf);
+
+	if (status != HALMAC_RET_SUCCESS) {
+		PLTFM_MSG_ERR("[ERR]send h2c pkt fail!!\n");
+		reset_ofld_feature_88xx(adapter, HALMAC_FEATURE_POWER_TRACKING);
+		return status;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+get_iqk_status_88xx(struct halmac_adapter *adapter,
+		    enum halmac_cmd_process_status *proc_status)
+{
+	*proc_status = adapter->halmac_state.iqk_state.proc_status;
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+get_pwr_trk_status_88xx(struct halmac_adapter *adapter,
+			enum halmac_cmd_process_status *proc_status)
+{
+	*proc_status = adapter->halmac_state.pwr_trk_state.proc_status;
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+get_psd_status_88xx(struct halmac_adapter *adapter,
+		    enum halmac_cmd_process_status *proc_status, u8 *data,
+		    u32 *size)
+{
+	struct halmac_psd_state *state = &adapter->halmac_state.psd_state;
+
+	*proc_status = state->proc_status;
+
+	if (!data)
+		return HALMAC_RET_NULL_POINTER;
+
+	if (!size)
+		return HALMAC_RET_NULL_POINTER;
+
+	if (*proc_status == HALMAC_CMD_PROCESS_DONE) {
+		if (*size < state->data_size) {
+			*size = state->data_size;
+			return HALMAC_RET_BUFFER_TOO_SMALL;
+		}
+
+		*size = state->data_size;
+		PLTFM_MEMCPY(data, state->data, *size);
+	}
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * psd_88xx() - trigger fw psd
+ * @adapter : the adapter of halmac
+ * @start_psd : start PSD
+ * @end_psd : end PSD
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+psd_88xx(struct halmac_adapter *adapter, u16 start_psd, u16 end_psd)
+{
+	u8 h2c_buf[H2C_PKT_SIZE_88XX] = { 0 };
+	u16 seq_num = 0;
+	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
+	struct halmac_h2c_header_info hdr_info;
+	enum halmac_cmd_process_status *proc_status;
+
+	proc_status = &adapter->halmac_state.psd_state.proc_status;
+
+	if (halmac_fw_validate(adapter) != HALMAC_RET_SUCCESS)
+		return HALMAC_RET_NO_DLFW;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
+		PLTFM_MSG_TRACE("[TRACE]Wait event(psd)\n");
+		return HALMAC_RET_BUSY_STATE;
+	}
+
+	if (adapter->halmac_state.psd_state.data) {
+		PLTFM_FREE(adapter->halmac_state.psd_state.data,
+			   adapter->halmac_state.psd_state.data_size);
+		adapter->halmac_state.psd_state.data = (u8 *)NULL;
+	}
+
+	adapter->halmac_state.psd_state.data_size = 0;
+	adapter->halmac_state.psd_state.seg_size = 0;
+
+	*proc_status = HALMAC_CMD_PROCESS_SENDING;
+
+	PSD_SET_START_PSD(h2c_buf, start_psd);
+	PSD_SET_END_PSD(h2c_buf, end_psd);
+
+	hdr_info.sub_cmd_id = SUB_CMD_ID_PSD;
+	hdr_info.content_size = 4;
+	hdr_info.ack = 1;
+	set_h2c_pkt_hdr_88xx(adapter, h2c_buf, &hdr_info, &seq_num);
+
+	status = send_h2c_pkt_88xx(adapter, h2c_buf);
+
+	if (status != HALMAC_RET_SUCCESS) {
+		PLTFM_MSG_ERR("[ERR]send h2c pkt fail!!\n");
+		reset_ofld_feature_88xx(adapter, HALMAC_FEATURE_PSD);
+		return status;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+get_h2c_ack_iqk_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size)
+{
+	u8 seq_num;
+	u8 fw_rc;
+	struct halmac_iqk_state *state = &adapter->halmac_state.iqk_state;
+	enum halmac_cmd_process_status proc_status;
+
+	seq_num = (u8)H2C_ACK_HDR_GET_H2C_SEQ(buf);
+	PLTFM_MSG_TRACE("[TRACE]Seq num : h2c->%d c2h->%d\n",
+			state->seq_num, seq_num);
+	if (seq_num != state->seq_num) {
+		PLTFM_MSG_ERR("[ERR]Seq num mismatch : h2c->%d c2h->%d\n",
+			      state->seq_num, seq_num);
+		return HALMAC_RET_SUCCESS;
+	}
+
+	if (state->proc_status != HALMAC_CMD_PROCESS_SENDING) {
+		PLTFM_MSG_ERR("[ERR]not cmd sending\n");
+		return HALMAC_RET_SUCCESS;
+	}
+
+	fw_rc = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(buf);
+	state->fw_rc = fw_rc;
+
+	if ((enum halmac_h2c_return_code)fw_rc == HALMAC_H2C_RETURN_SUCCESS) {
+		proc_status = HALMAC_CMD_PROCESS_DONE;
+		state->proc_status = proc_status;
+		PLTFM_EVENT_SIG(HALMAC_FEATURE_IQK, proc_status, NULL, 0);
+	} else {
+		proc_status = HALMAC_CMD_PROCESS_ERROR;
+		state->proc_status = proc_status;
+		PLTFM_EVENT_SIG(HALMAC_FEATURE_IQK, proc_status, &fw_rc, 1);
+	}
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+get_h2c_ack_pwr_trk_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size)
+{
+	u8 seq_num;
+	u8 fw_rc;
+	struct halmac_pwr_tracking_state *state;
+	enum halmac_cmd_process_status proc_status;
+
+	state = &adapter->halmac_state.pwr_trk_state;
+
+	seq_num = (u8)H2C_ACK_HDR_GET_H2C_SEQ(buf);
+	PLTFM_MSG_TRACE("[TRACE]Seq num : h2c->%d c2h->%d\n",
+			state->seq_num, seq_num);
+	if (seq_num != state->seq_num) {
+		PLTFM_MSG_ERR("[ERR]Seq num mismatch : h2c->%d c2h->%d\n",
+			      state->seq_num, seq_num);
+		return HALMAC_RET_SUCCESS;
+	}
+
+	if (state->proc_status != HALMAC_CMD_PROCESS_SENDING) {
+		PLTFM_MSG_ERR("[ERR]not cmd sending\n");
+		return HALMAC_RET_SUCCESS;
+	}
+
+	fw_rc = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(buf);
+	state->fw_rc = fw_rc;
+
+	if ((enum halmac_h2c_return_code)fw_rc == HALMAC_H2C_RETURN_SUCCESS) {
+		proc_status = HALMAC_CMD_PROCESS_DONE;
+		state->proc_status = proc_status;
+		PLTFM_EVENT_SIG(HALMAC_FEATURE_POWER_TRACKING, proc_status,
+				NULL, 0);
+	} else {
+		proc_status = HALMAC_CMD_PROCESS_ERROR;
+		state->proc_status = proc_status;
+		PLTFM_EVENT_SIG(HALMAC_FEATURE_POWER_TRACKING, proc_status,
+				&fw_rc, 1);
+	}
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+get_psd_data_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size)
+{
+	u8 seg_id;
+	u8 seg_size;
+	u8 seq_num;
+	u16 total_size;
+	enum halmac_cmd_process_status proc_status;
+	struct halmac_psd_state *state = &adapter->halmac_state.psd_state;
+
+	seq_num = (u8)PSD_DATA_GET_H2C_SEQ(buf);
+	PLTFM_MSG_TRACE("[TRACE]seq num : h2c->%d c2h->%d\n",
+			state->seq_num, seq_num);
+	if (seq_num != state->seq_num) {
+		PLTFM_MSG_ERR("[ERR]seq num mismatch : h2c->%d c2h->%d\n",
+			      state->seq_num, seq_num);
+		return HALMAC_RET_SUCCESS;
+	}
+
+	if (state->proc_status != HALMAC_CMD_PROCESS_SENDING) {
+		PLTFM_MSG_ERR("[ERR]not cmd sending\n");
+		return HALMAC_RET_SUCCESS;
+	}
+
+	total_size = (u16)PSD_DATA_GET_TOTAL_SIZE(buf);
+	seg_id = (u8)PSD_DATA_GET_SEGMENT_ID(buf);
+	seg_size = (u8)PSD_DATA_GET_SEGMENT_SIZE(buf);
+	state->data_size = total_size;
+
+	if (!state->data)
+		state->data = (u8 *)PLTFM_MALLOC(state->data_size);
+
+	if (seg_id == 0)
+		state->seg_size = seg_size;
+
+	PLTFM_MEMCPY(state->data + seg_id * state->seg_size,
+		     buf + C2H_DATA_OFFSET_88XX, seg_size);
+
+	if (PSD_DATA_GET_END_SEGMENT(buf) == 0)
+		return HALMAC_RET_SUCCESS;
+
+	proc_status = HALMAC_CMD_PROCESS_DONE;
+	state->proc_status = proc_status;
+
+	PLTFM_EVENT_SIG(HALMAC_FEATURE_PSD, proc_status, state->data,
+			state->data_size);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+#endif /* HALMAC_88XX_SUPPORT */

+ 57 - 0
hal/halmac/halmac_88xx/halmac_bb_rf_88xx.h

@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#ifndef _HALMAC_BB_RF_88XX_H_
+#define _HALMAC_BB_RF_88XX_H_
+
+#include "../halmac_api.h"
+
+#if HALMAC_88XX_SUPPORT
+
+enum halmac_ret_status
+start_iqk_88xx(struct halmac_adapter *adapter, struct halmac_iqk_para *param);
+
+enum halmac_ret_status
+ctrl_pwr_tracking_88xx(struct halmac_adapter *adapter,
+		       struct halmac_pwr_tracking_option *opt);
+
+enum halmac_ret_status
+get_iqk_status_88xx(struct halmac_adapter *adapter,
+		    enum halmac_cmd_process_status *proc_status);
+
+enum halmac_ret_status
+get_pwr_trk_status_88xx(struct halmac_adapter *adapter,
+			enum halmac_cmd_process_status *proc_status);
+
+enum halmac_ret_status
+get_psd_status_88xx(struct halmac_adapter *adapter,
+		    enum halmac_cmd_process_status *proc_status, u8 *data,
+		    u32 *size);
+
+enum halmac_ret_status
+psd_88xx(struct halmac_adapter *adapter, u16 start_psd, u16 end_psd);
+
+enum halmac_ret_status
+get_h2c_ack_iqk_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size);
+
+enum halmac_ret_status
+get_h2c_ack_pwr_trk_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size);
+
+enum halmac_ret_status
+get_psd_data_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size);
+
+#endif /* HALMAC_88XX_SUPPORT */
+
+#endif/* _HALMAC_BB_RF_88XX_H_ */

+ 1133 - 0
hal/halmac/halmac_88xx/halmac_cfg_wmac_88xx.c

@@ -0,0 +1,1133 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "halmac_cfg_wmac_88xx.h"
+#include "halmac_88xx_cfg.h"
+
+#if HALMAC_88XX_SUPPORT
+
+#define MAC_CLK_SPEED	80 /* 80M */
+
+enum mac_clock_hw_def {
+	MAC_CLK_HW_DEF_80M = 0,
+	MAC_CLK_HW_DEF_40M = 1,
+	MAC_CLK_HW_DEF_20M = 2,
+};
+
+/**
+ * cfg_mac_addr_88xx() - config mac address
+ * @adapter : the adapter of halmac
+ * @port : 0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4
+ * @addr : mac address
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_mac_addr_88xx(struct halmac_adapter *adapter, u8 port,
+		  union halmac_wlan_addr *addr)
+{
+	u32 offset;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (port >= HALMAC_PORTID_NUM) {
+		PLTFM_MSG_ERR("[ERR]port index >= 5\n");
+		return HALMAC_RET_PORT_NOT_SUPPORT;
+	}
+
+	switch (port) {
+	case HALMAC_PORTID0:
+		offset = REG_MACID;
+		break;
+	case HALMAC_PORTID1:
+		offset = REG_MACID1;
+		break;
+	case HALMAC_PORTID2:
+		offset = REG_MACID2;
+		break;
+	case HALMAC_PORTID3:
+		offset = REG_MACID3;
+		break;
+	case HALMAC_PORTID4:
+		offset = REG_MACID4;
+		break;
+	default:
+		return HALMAC_RET_PORT_NOT_SUPPORT;
+	}
+
+	HALMAC_REG_W32(offset, rtk_le32_to_cpu(addr->addr_l_h.low));
+	HALMAC_REG_W16(offset + 4, rtk_le16_to_cpu(addr->addr_l_h.high));
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_bssid_88xx() - config BSSID
+ * @adapter : the adapter of halmac
+ * @port : 0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4
+ * @addr : bssid
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_bssid_88xx(struct halmac_adapter *adapter, u8 port,
+	       union halmac_wlan_addr *addr)
+{
+	u32 offset;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (port >= HALMAC_PORTID_NUM) {
+		PLTFM_MSG_ERR("[ERR]port index > 5\n");
+		return HALMAC_RET_PORT_NOT_SUPPORT;
+	}
+
+	switch (port) {
+	case HALMAC_PORTID0:
+		offset = REG_BSSID;
+		break;
+	case HALMAC_PORTID1:
+		offset = REG_BSSID1;
+		break;
+	case HALMAC_PORTID2:
+		offset = REG_BSSID2;
+		break;
+	case HALMAC_PORTID3:
+		offset = REG_BSSID3;
+		break;
+	case HALMAC_PORTID4:
+		offset = REG_BSSID4;
+		break;
+	default:
+		return HALMAC_RET_PORT_NOT_SUPPORT;
+	}
+
+	HALMAC_REG_W32(offset, rtk_le32_to_cpu(addr->addr_l_h.low));
+	HALMAC_REG_W16(offset + 4, rtk_le16_to_cpu(addr->addr_l_h.high));
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_transmitter_addr_88xx() - config transmitter address
+ * @adapter : the adapter of halmac
+ * @port :  0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4
+ * @addr :
+ * Author : Alan
+ * Return : enum halmac_ret_status
+ */
+enum halmac_ret_status
+cfg_transmitter_addr_88xx(struct halmac_adapter *adapter, u8 port,
+			  union halmac_wlan_addr *addr)
+{
+	u32 offset;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (port >= HALMAC_PORTID_NUM) {
+		PLTFM_MSG_ERR("[ERR]port index > 5\n");
+		return HALMAC_RET_PORT_NOT_SUPPORT;
+	}
+
+	switch (port) {
+	case HALMAC_PORTID0:
+		offset = REG_TRANSMIT_ADDRSS_0;
+		break;
+	case HALMAC_PORTID1:
+		offset = REG_TRANSMIT_ADDRSS_1;
+		break;
+	case HALMAC_PORTID2:
+		offset = REG_TRANSMIT_ADDRSS_2;
+		break;
+	case HALMAC_PORTID3:
+		offset = REG_TRANSMIT_ADDRSS_3;
+		break;
+	case HALMAC_PORTID4:
+		offset = REG_TRANSMIT_ADDRSS_4;
+		break;
+	default:
+		return HALMAC_RET_PORT_NOT_SUPPORT;
+	}
+
+	HALMAC_REG_W32(offset, rtk_le32_to_cpu(addr->addr_l_h.low));
+	HALMAC_REG_W16(offset + 4, rtk_le16_to_cpu(addr->addr_l_h.high));
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_net_type_88xx() - config network type
+ * @adapter : the adapter of halmac
+ * @port :  0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4
+ * @addr : mac address
+ * Author : Alan
+ * Return : enum halmac_ret_status
+ */
+enum halmac_ret_status
+cfg_net_type_88xx(struct halmac_adapter *adapter, u8 port,
+		  enum halmac_network_type_select net_type)
+{
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	u8 value8 = 0;
+	u8 net_type_tmp = 0;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (net_type == HALMAC_NETWORK_AP) {
+		if (port >= HALMAC_PORTID1) {
+			PLTFM_MSG_ERR("[ERR]AP port > 1\n");
+			return HALMAC_RET_PORT_NOT_SUPPORT;
+		}
+	}
+
+	switch (port) {
+	case HALMAC_PORTID0:
+		net_type_tmp = net_type;
+		value8 = ((HALMAC_REG_R8(REG_CR + 2) & 0xFC) | net_type_tmp);
+		HALMAC_REG_W8(REG_CR + 2, value8);
+		break;
+	case HALMAC_PORTID1:
+		net_type_tmp = (net_type << 2);
+		value8 = ((HALMAC_REG_R8(REG_CR + 2) & 0xF3) | net_type_tmp);
+		HALMAC_REG_W8(REG_CR + 2, value8);
+		break;
+	case HALMAC_PORTID2:
+		net_type_tmp = net_type;
+		value8 = ((HALMAC_REG_R8(REG_CR_EXT) & 0xFC) | net_type_tmp);
+		HALMAC_REG_W8(REG_CR_EXT, value8);
+		break;
+	case HALMAC_PORTID3:
+		net_type_tmp = (net_type << 2);
+		value8 = ((HALMAC_REG_R8(REG_CR_EXT) & 0xF3) | net_type_tmp);
+		HALMAC_REG_W8(REG_CR_EXT, value8);
+		break;
+	case HALMAC_PORTID4:
+		net_type_tmp = (net_type << 4);
+		value8 = ((HALMAC_REG_R8(REG_CR_EXT) & 0xCF) | net_type_tmp);
+		HALMAC_REG_W8(REG_CR_EXT, value8);
+		break;
+	default:
+		break;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_tsf_rst_88xx() - tsf reset
+ * @adapter : the adapter of halmac
+ * @port :  0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4
+ * Author : Alan
+ * Return : enum halmac_ret_status
+ */
+enum halmac_ret_status
+cfg_tsf_rst_88xx(struct halmac_adapter *adapter, u8 port)
+{
+	u8 tsf_rst = 0;
+	u8 value8;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	switch (port) {
+	case HALMAC_PORTID0:
+		tsf_rst = BIT_TSFTR_RST;
+		break;
+	case HALMAC_PORTID1:
+		tsf_rst = BIT_TSFTR_CLI0_RST;
+		break;
+	case HALMAC_PORTID2:
+		tsf_rst = BIT_TSFTR_CLI1_RST;
+		break;
+	case HALMAC_PORTID3:
+		tsf_rst = BIT_TSFTR_CLI2_RST;
+		break;
+	case HALMAC_PORTID4:
+		tsf_rst = BIT_TSFTR_CLI3_RST;
+		break;
+	default:
+		break;
+	}
+
+	value8 = HALMAC_REG_R8(REG_DUAL_TSF_RST);
+	HALMAC_REG_W8(REG_DUAL_TSF_RST, value8 | tsf_rst);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_bcn_space_88xx() - config beacon space
+ * @adapter : the adapter of halmac
+ * @port :  0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4
+ * @bcn_space : beacon space
+ * Author : Alan
+ * Return : enum halmac_ret_status
+ */
+enum halmac_ret_status
+cfg_bcn_space_88xx(struct halmac_adapter *adapter, u8 port, u32 bcn_space)
+{
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	u16 bcn_space_real = 0;
+	u16 value16 = 0;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	bcn_space_real = ((u16)bcn_space);
+
+	switch (port) {
+	case HALMAC_PORTID0:
+		HALMAC_REG_W16(REG_MBSSID_BCN_SPACE, bcn_space_real);
+		break;
+	case HALMAC_PORTID1:
+		value16 = HALMAC_REG_R16(REG_MBSSID_BCN_SPACE + 2) & 0xF000;
+		value16 |= bcn_space_real;
+		HALMAC_REG_W16(REG_MBSSID_BCN_SPACE + 2, value16);
+		break;
+	case HALMAC_PORTID2:
+		value16 = HALMAC_REG_R16(REG_MBSSID_BCN_SPACE2) & 0xF000;
+		value16 |= bcn_space_real;
+		HALMAC_REG_W16(REG_MBSSID_BCN_SPACE2, value16);
+		break;
+	case HALMAC_PORTID3:
+		value16 = HALMAC_REG_R16(REG_MBSSID_BCN_SPACE2 + 2) & 0xF000;
+		value16 |= bcn_space_real;
+		HALMAC_REG_W16(REG_MBSSID_BCN_SPACE2 + 2, value16);
+		break;
+	case HALMAC_PORTID4:
+		value16 = HALMAC_REG_R16(REG_MBSSID_BCN_SPACE3) & 0xF000;
+		value16 |= bcn_space_real;
+		HALMAC_REG_W16(REG_MBSSID_BCN_SPACE3, value16);
+		break;
+	default:
+		break;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * rw_bcn_ctrl_88xx() - r/w beacon control
+ * @adapter : the adapter of halmac
+ * @port :  0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4
+ * @write_en : 1->write beacon function 0->read beacon function
+ * @pBcn_ctrl : beacon control info
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ */
+enum halmac_ret_status
+rw_bcn_ctrl_88xx(struct halmac_adapter *adapter, u8 port, u8 write_en,
+		 struct halmac_bcn_ctrl *ctrl)
+{
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	u8 ctrl_value = 0;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (write_en) {
+		if (ctrl->dis_rx_bssid_fit == 1)
+			ctrl_value |= BIT_DIS_RX_BSSID_FIT;
+
+		if (ctrl->en_txbcn_rpt == 1)
+			ctrl_value |= BIT_P0_EN_TXBCN_RPT;
+
+		if (ctrl->dis_tsf_udt == 1)
+			ctrl_value |= BIT_DIS_TSF_UDT;
+
+		if (ctrl->en_bcn == 1)
+			ctrl_value |= BIT_EN_BCN_FUNCTION;
+
+		if (ctrl->en_rxbcn_rpt == 1)
+			ctrl_value |= BIT_P0_EN_RXBCN_RPT;
+
+		if (ctrl->en_p2p_ctwin == 1)
+			ctrl_value |= BIT_EN_P2P_CTWINDOW;
+
+		if (ctrl->en_p2p_bcn_area == 1)
+			ctrl_value |= BIT_EN_P2P_BCNQ_AREA;
+
+		switch (port) {
+		case HALMAC_PORTID0:
+			HALMAC_REG_W8(REG_BCN_CTRL, ctrl_value);
+			break;
+		case HALMAC_PORTID1:
+			HALMAC_REG_W8(REG_BCN_CTRL_CLINT0, ctrl_value);
+			break;
+		case HALMAC_PORTID2:
+			HALMAC_REG_W8(REG_BCN_CTRL_CLINT1, ctrl_value);
+			break;
+		case HALMAC_PORTID3:
+			HALMAC_REG_W8(REG_BCN_CTRL_CLINT2, ctrl_value);
+			break;
+		case HALMAC_PORTID4:
+			HALMAC_REG_W8(REG_BCN_CTRL_CLINT3, ctrl_value);
+			break;
+		default:
+			break;
+		}
+
+	} else {
+		switch (port) {
+		case HALMAC_PORTID0:
+			ctrl_value = HALMAC_REG_R8(REG_BCN_CTRL);
+			break;
+		case HALMAC_PORTID1:
+			ctrl_value = HALMAC_REG_R8(REG_BCN_CTRL_CLINT0);
+			break;
+		case HALMAC_PORTID2:
+			ctrl_value = HALMAC_REG_R8(REG_BCN_CTRL_CLINT1);
+			break;
+		case HALMAC_PORTID3:
+			ctrl_value = HALMAC_REG_R8(REG_BCN_CTRL_CLINT2);
+			break;
+		case HALMAC_PORTID4:
+			ctrl_value = HALMAC_REG_R8(REG_BCN_CTRL_CLINT3);
+			break;
+		default:
+			break;
+		}
+
+		if (ctrl_value & BIT_EN_P2P_BCNQ_AREA)
+			ctrl->en_p2p_bcn_area = 1;
+		else
+			ctrl->en_p2p_bcn_area = 0;
+
+		if (ctrl_value & BIT_EN_P2P_CTWINDOW)
+			ctrl->en_p2p_ctwin = 1;
+		else
+			ctrl->en_p2p_ctwin = 0;
+
+		if (ctrl_value & BIT_P0_EN_RXBCN_RPT)
+			ctrl->en_rxbcn_rpt = 1;
+		else
+			ctrl->en_rxbcn_rpt = 0;
+
+		if (ctrl_value & BIT_EN_BCN_FUNCTION)
+			ctrl->en_bcn = 1;
+		else
+			ctrl->en_bcn = 0;
+
+		if (ctrl_value & BIT_DIS_TSF_UDT)
+			ctrl->dis_tsf_udt = 1;
+		else
+			ctrl->dis_tsf_udt = 0;
+
+		if (ctrl_value & BIT_P0_EN_TXBCN_RPT)
+			ctrl->en_txbcn_rpt = 1;
+		else
+			ctrl->en_txbcn_rpt = 0;
+
+		if (ctrl_value & BIT_DIS_RX_BSSID_FIT)
+			ctrl->dis_rx_bssid_fit = 1;
+		else
+			ctrl->dis_rx_bssid_fit = 0;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_multicast_addr_88xx() - config multicast address
+ * @adapter : the adapter of halmac
+ * @addr : multicast address
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_multicast_addr_88xx(struct halmac_adapter *adapter,
+			union halmac_wlan_addr *addr)
+{
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	HALMAC_REG_W32(REG_MAR, rtk_le32_to_cpu(addr->addr_l_h.low));
+	HALMAC_REG_W16(REG_MAR + 4, rtk_le16_to_cpu(addr->addr_l_h.high));
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_operation_mode_88xx() - config operation mode
+ * @adapter : the adapter of halmac
+ * @mode : 802.11 standard(b/g/n/ac)
+ * Author : KaiYuan Chang/Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_operation_mode_88xx(struct halmac_adapter *adapter,
+			enum halmac_wireless_mode mode)
+{
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_ch_bw_88xx() - config channel & bandwidth
+ * @adapter : the adapter of halmac
+ * @ch : WLAN channel, support 2.4G & 5G
+ * @idx : primary channel index, idx1, idx2, idx3, idx4
+ * @bw : band width, 20, 40, 80, 160, 5 ,10
+ * Author : KaiYuan Chang
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_ch_bw_88xx(struct halmac_adapter *adapter, u8 ch,
+	       enum halmac_pri_ch_idx idx, enum halmac_bw bw)
+{
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	cfg_pri_ch_idx_88xx(adapter, idx);
+	cfg_bw_88xx(adapter, bw);
+	cfg_ch_88xx(adapter, ch);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+cfg_ch_88xx(struct halmac_adapter *adapter, u8 ch)
+{
+	u8 value8;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	value8 = HALMAC_REG_R8(REG_CCK_CHECK);
+	value8 = value8 & (~(BIT(7)));
+
+	if (ch > 35)
+		value8 = value8 | BIT(7);
+
+	HALMAC_REG_W8(REG_CCK_CHECK, value8);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+cfg_pri_ch_idx_88xx(struct halmac_adapter *adapter, enum halmac_pri_ch_idx idx)
+{
+	u8 txsc40 = 0, txsc20 = 0;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	txsc20 = idx;
+	if (txsc20 == HALMAC_CH_IDX_1 || txsc20 == HALMAC_CH_IDX_3)
+		txsc40 = 9;
+	else
+		txsc40 = 10;
+
+	HALMAC_REG_W8(REG_DATA_SC, BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40));
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_bw_88xx() - config bandwidth
+ * @adapter : the adapter of halmac
+ * @bw : band width, 20, 40, 80, 160, 5 ,10
+ * Author : KaiYuan Chang
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_bw_88xx(struct halmac_adapter *adapter, enum halmac_bw bw)
+{
+	u32 value32;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	value32 = HALMAC_REG_R32(REG_WMAC_TRXPTCL_CTL);
+	value32 = value32 & (~(BIT(7) | BIT(8)));
+
+	switch (bw) {
+	case HALMAC_BW_80:
+		value32 = value32 | BIT(8);
+		break;
+	case HALMAC_BW_40:
+		value32 = value32 | BIT(7);
+		break;
+	case HALMAC_BW_20:
+	case HALMAC_BW_10:
+	case HALMAC_BW_5:
+		break;
+	default:
+		break;
+	}
+
+	HALMAC_REG_W32(REG_WMAC_TRXPTCL_CTL, value32);
+
+	/* TODO:Move to change mac clk api later... */
+	value32 = HALMAC_REG_R32(REG_AFE_CTRL1) & ~(BIT(20) | BIT(21));
+	value32 |= (MAC_CLK_HW_DEF_80M << BIT_SHIFT_MAC_CLK_SEL);
+	HALMAC_REG_W32(REG_AFE_CTRL1, value32);
+
+	HALMAC_REG_W8(REG_USTIME_TSF, MAC_CLK_SPEED);
+	HALMAC_REG_W8(REG_USTIME_EDCA, MAC_CLK_SPEED);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+void
+enable_bb_rf_88xx(struct halmac_adapter *adapter, u8 enable)
+{
+	u8 value8;
+	u32 value32;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	if (enable == 1) {
+		value8 = HALMAC_REG_R8(REG_SYS_FUNC_EN);
+		value8 = value8 | BIT(0) | BIT(1);
+		HALMAC_REG_W8(REG_SYS_FUNC_EN, value8);
+
+		value8 = HALMAC_REG_R8(REG_RF_CTRL);
+		value8 = value8 | BIT(0) | BIT(1) | BIT(2);
+		HALMAC_REG_W8(REG_RF_CTRL, value8);
+
+		value32 = HALMAC_REG_R32(REG_WLRF1);
+		value32 = value32 | BIT(24) | BIT(25) | BIT(26);
+		HALMAC_REG_W32(REG_WLRF1, value32);
+	} else {
+		value8 = HALMAC_REG_R8(REG_SYS_FUNC_EN);
+		value8 = value8 & (~(BIT(0) | BIT(1)));
+		HALMAC_REG_W8(REG_SYS_FUNC_EN, value8);
+
+		value8 = HALMAC_REG_R8(REG_RF_CTRL);
+		value8 = value8 & (~(BIT(0) | BIT(1) | BIT(2)));
+		HALMAC_REG_W8(REG_RF_CTRL, value8);
+
+		value32 = HALMAC_REG_R32(REG_WLRF1);
+		value32 = value32 & (~(BIT(24) | BIT(25) | BIT(26)));
+		HALMAC_REG_W32(REG_WLRF1, value32);
+	}
+}
+
+/**
+ * cfg_la_mode_88xx() - config la mode
+ * @adapter : the adapter of halmac
+ * @mode :
+ *	disable : no TXFF space reserved for LA debug
+ *	partial : partial TXFF space is reserved for LA debug
+ *	full : all TXFF space is reserved for LA debug
+ * Author : KaiYuan Chang
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_la_mode_88xx(struct halmac_adapter *adapter, enum halmac_la_mode mode)
+{
+	if (adapter->api_registry.la_mode_en == 0)
+		return HALMAC_RET_NOT_SUPPORT;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	adapter->txff_alloc.la_mode = mode;
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * cfg_rxfifo_expand_mode_88xx() - rx fifo expanding
+ * @adapter : the adapter of halmac
+ * @mode :
+ *	disable : normal mode
+ *	1 block : Rx FIFO + 1 FIFO block; Tx fifo - 1 FIFO block
+ *	2 block : Rx FIFO + 2 FIFO block; Tx fifo - 2 FIFO block
+ *	3 block : Rx FIFO + 3 FIFO block; Tx fifo - 3 FIFO block
+ * Author : Soar
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_rxfifo_expand_mode_88xx(struct halmac_adapter *adapter,
+			    enum halmac_rx_fifo_expanding_mode mode)
+{
+	if (adapter->api_registry.rx_exp_en == 0)
+		return HALMAC_RET_NOT_SUPPORT;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	adapter->txff_alloc.rx_fifo_exp_mode = mode;
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+config_security_88xx(struct halmac_adapter *adapter,
+		     struct halmac_security_setting *setting)
+{
+	u8 sec_cfg;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	HALMAC_REG_W16_SET(REG_CR, BIT_MAC_SEC_EN);
+
+	if (setting->compare_keyid == 1) {
+		HALMAC_REG_W8_SET(REG_SECCFG + 1, BIT(0));
+		adapter->hw_cfg_info.chk_security_keyid = 1;
+	} else {
+		adapter->hw_cfg_info.chk_security_keyid = 0;
+	}
+
+	sec_cfg = HALMAC_REG_R8(REG_SECCFG);
+
+	/* BC/MC uses default key */
+	/* cam entry 0~3, kei id = 0 -> entry0, kei id = 1 -> entry1... */
+	sec_cfg |= (BIT_TXBCUSEDK | BIT_RXBCUSEDK);
+
+	if (setting->tx_encryption == 1)
+		sec_cfg |= BIT_TXENC;
+	else
+		sec_cfg &= ~BIT_TXENC;
+
+	if (setting->rx_decryption == 1)
+		sec_cfg |= BIT_RXDEC;
+	else
+		sec_cfg &= ~BIT_RXDEC;
+
+	HALMAC_REG_W8(REG_SECCFG, sec_cfg);
+
+	if (setting->bip_enable == 1) {
+		if (adapter->chip_id == HALMAC_CHIP_ID_8822B)
+			return HALMAC_RET_BIP_NO_SUPPORT;
+#if (HALMAC_8821C_SUPPORT || HALMAC_8822C_SUPPORT || HALMAC_8812F_SUPPORT)
+		sec_cfg = HALMAC_REG_R8(REG_WSEC_OPTION + 2);
+
+		if (setting->tx_encryption == 1)
+			sec_cfg |= (BIT(3) | BIT(5));
+		else
+			sec_cfg &= ~(BIT(3) | BIT(5));
+
+		if (setting->rx_decryption == 1)
+			sec_cfg |= (BIT(4) | BIT(6));
+		else
+			sec_cfg &= ~(BIT(4) | BIT(6));
+
+		HALMAC_REG_W8(REG_WSEC_OPTION + 2, sec_cfg);
+#endif
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+u8
+get_used_cam_entry_num_88xx(struct halmac_adapter *adapter,
+			    enum hal_security_type sec_type)
+{
+	u8 entry_num;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	switch (sec_type) {
+	case HAL_SECURITY_TYPE_WEP40:
+	case HAL_SECURITY_TYPE_WEP104:
+	case HAL_SECURITY_TYPE_TKIP:
+	case HAL_SECURITY_TYPE_AES128:
+	case HAL_SECURITY_TYPE_GCMP128:
+	case HAL_SECURITY_TYPE_GCMSMS4:
+	case HAL_SECURITY_TYPE_BIP:
+		entry_num = 1;
+		break;
+	case HAL_SECURITY_TYPE_WAPI:
+	case HAL_SECURITY_TYPE_AES256:
+	case HAL_SECURITY_TYPE_GCMP256:
+		entry_num = 2;
+		break;
+	default:
+		entry_num = 0;
+		break;
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return entry_num;
+}
+
+enum halmac_ret_status
+write_cam_88xx(struct halmac_adapter *adapter, u32 idx,
+	       struct halmac_cam_entry_info *info)
+{
+	u32 i;
+	u32 cmd = 0x80010000;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	struct halmac_cam_entry_format *fmt = NULL;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (idx >= adapter->hw_cfg_info.cam_entry_num)
+		return HALMAC_RET_ENTRY_INDEX_ERROR;
+
+	if (info->key_id > 3)
+		return HALMAC_RET_FAIL;
+
+	fmt = (struct halmac_cam_entry_format *)PLTFM_MALLOC(sizeof(*fmt));
+	if (!fmt)
+		return HALMAC_RET_NULL_POINTER;
+	PLTFM_MEMSET(fmt, 0x00, sizeof(*fmt));
+
+	if (adapter->hw_cfg_info.chk_security_keyid == 1)
+		fmt->key_id = info->key_id;
+	fmt->valid = info->valid;
+	PLTFM_MEMCPY(fmt->mac_address, info->mac_address, 6);
+	PLTFM_MEMCPY(fmt->key, info->key, 16);
+
+	switch (info->security_type) {
+	case HAL_SECURITY_TYPE_NONE:
+		fmt->type = 0;
+		break;
+	case HAL_SECURITY_TYPE_WEP40:
+		fmt->type = 1;
+		break;
+	case HAL_SECURITY_TYPE_WEP104:
+		fmt->type = 5;
+		break;
+	case HAL_SECURITY_TYPE_TKIP:
+		fmt->type = 2;
+		break;
+	case HAL_SECURITY_TYPE_AES128:
+		fmt->type = 4;
+		break;
+	case HAL_SECURITY_TYPE_WAPI:
+		fmt->type = 6;
+		break;
+	case HAL_SECURITY_TYPE_AES256:
+		fmt->type = 4;
+		fmt->ext_sectype = 1;
+		break;
+	case HAL_SECURITY_TYPE_GCMP128:
+		fmt->type = 7;
+		break;
+	case HAL_SECURITY_TYPE_GCMP256:
+	case HAL_SECURITY_TYPE_GCMSMS4:
+		fmt->type = 7;
+		fmt->ext_sectype = 1;
+		break;
+	case HAL_SECURITY_TYPE_BIP:
+		fmt->type = (info->unicast == 1) ? 4 : 0;
+		fmt->mgnt = 1;
+		fmt->grp = (info->unicast == 1) ? 0 : 1;
+		break;
+	default:
+		PLTFM_FREE(fmt, sizeof(*fmt));
+		return HALMAC_RET_FAIL;
+	}
+
+	for (i = 0; i < 8; i++) {
+		HALMAC_REG_W32(REG_CAMWRITE, *((u32 *)fmt + i));
+		HALMAC_REG_W32(REG_CAMCMD, cmd | ((idx << 3) + i));
+	}
+
+	if (info->security_type == HAL_SECURITY_TYPE_WAPI ||
+	    info->security_type == HAL_SECURITY_TYPE_AES256 ||
+	    info->security_type == HAL_SECURITY_TYPE_GCMP256 ||
+	    info->security_type == HAL_SECURITY_TYPE_GCMSMS4) {
+		fmt->mic = 1;
+		PLTFM_MEMCPY(fmt->key, info->key_ext, 16);
+		idx++;
+		for (i = 0; i < 8; i++) {
+			HALMAC_REG_W32(REG_CAMWRITE, *((u32 *)fmt + i));
+			HALMAC_REG_W32(REG_CAMCMD, cmd | ((idx << 3) + i));
+		}
+	}
+
+	PLTFM_FREE(fmt, sizeof(*fmt));
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+read_cam_entry_88xx(struct halmac_adapter *adapter, u32 idx,
+		    struct halmac_cam_entry_format *content)
+{
+	u32 i;
+	u32 cmd = 0x80000000;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (idx >= adapter->hw_cfg_info.cam_entry_num)
+		return HALMAC_RET_ENTRY_INDEX_ERROR;
+
+	for (i = 0; i < 8; i++) {
+		HALMAC_REG_W32(REG_CAMCMD, cmd | ((idx << 3) + i));
+		*((u32 *)content + i) = HALMAC_REG_R32(REG_CAMREAD);
+	}
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+enum halmac_ret_status
+clear_cam_entry_88xx(struct halmac_adapter *adapter, u32 idx)
+{
+	u32 i;
+	u32 cmd = 0x80010000;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+	struct halmac_cam_entry_format *fmt = NULL;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (idx >= adapter->hw_cfg_info.cam_entry_num)
+		return HALMAC_RET_ENTRY_INDEX_ERROR;
+
+	fmt = (struct halmac_cam_entry_format *)PLTFM_MALLOC(sizeof(*fmt));
+	if (!fmt)
+		return HALMAC_RET_NULL_POINTER;
+	PLTFM_MEMSET(fmt, 0x00, sizeof(*fmt));
+
+	for (i = 0; i < 8; i++) {
+		HALMAC_REG_W32(REG_CAMWRITE, *((u32 *)fmt + i));
+		HALMAC_REG_W32(REG_CAMCMD, cmd | ((idx << 3) + i));
+	}
+
+	PLTFM_FREE(fmt, sizeof(*fmt));
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+void
+rx_shift_88xx(struct halmac_adapter *adapter, u8 enable)
+{
+	u8 value8;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	value8 = HALMAC_REG_R8(REG_TXDMA_PQ_MAP);
+
+	if (enable == 1)
+		HALMAC_REG_W8(REG_TXDMA_PQ_MAP, value8 | BIT(1));
+	else
+		HALMAC_REG_W8(REG_TXDMA_PQ_MAP, value8 & ~(BIT(1)));
+}
+
+/**
+ * cfg_edca_para_88xx() - config edca parameter
+ * @adapter : the adapter of halmac
+ * @acq_id : VO/VI/BE/BK
+ * @param : aifs, cw, txop limit
+ * Author : Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+cfg_edca_para_88xx(struct halmac_adapter *adapter, enum halmac_acq_id acq_id,
+		   struct halmac_edca_para *param)
+{
+	u32 offset;
+	u32 value32;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	switch (acq_id) {
+	case HALMAC_ACQ_ID_VO:
+		offset = REG_EDCA_VO_PARAM;
+		break;
+	case HALMAC_ACQ_ID_VI:
+		offset = REG_EDCA_VI_PARAM;
+		break;
+	case HALMAC_ACQ_ID_BE:
+		offset = REG_EDCA_BE_PARAM;
+		break;
+	case HALMAC_ACQ_ID_BK:
+		offset = REG_EDCA_BK_PARAM;
+		break;
+	default:
+		return HALMAC_RET_SWITCH_CASE_ERROR;
+	}
+
+	param->txop_limit &= 0x7FF;
+	value32 = (param->aifs) | (param->cw << 8) | (param->txop_limit << 16);
+
+	HALMAC_REG_W32(offset, value32);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+void
+rx_clk_gate_88xx(struct halmac_adapter *adapter, u8 enable)
+{
+	u8 value8;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	value8 = HALMAC_REG_R8(REG_RCR + 2);
+
+	if (enable == 1)
+		HALMAC_REG_W8(REG_RCR + 2, value8 & ~(BIT(3)));
+	else
+		HALMAC_REG_W8(REG_RCR + 2, value8 | BIT(3));
+}
+
+enum halmac_ret_status
+rx_cut_amsdu_cfg_88xx(struct halmac_adapter *adapter,
+		      struct halmac_cut_amsdu_cfg *cfg)
+{
+	return HALMAC_RET_NOT_SUPPORT;
+}
+
+enum halmac_ret_status
+fast_edca_cfg_88xx(struct halmac_adapter *adapter,
+		   struct halmac_fast_edca_cfg *cfg)
+{
+	u16 value16;
+	u32 offset;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	switch (cfg->acq_id) {
+	case HALMAC_ACQ_ID_VO:
+		offset = REG_FAST_EDCA_VOVI_SETTING;
+		break;
+	case HALMAC_ACQ_ID_VI:
+		offset = REG_FAST_EDCA_VOVI_SETTING + 2;
+		break;
+	case HALMAC_ACQ_ID_BE:
+		offset = REG_FAST_EDCA_BEBK_SETTING;
+		break;
+	case HALMAC_ACQ_ID_BK:
+		offset = REG_FAST_EDCA_BEBK_SETTING + 2;
+		break;
+	default:
+		return HALMAC_RET_SWITCH_CASE_ERROR;
+	}
+
+	value16 = HALMAC_REG_R16(offset);
+	value16 &= 0xFF;
+	value16 = value16 | (cfg->queue_to << 8);
+
+	HALMAC_REG_W16(offset, value16);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+/**
+ * get_mac_addr_88xx() - get mac address
+ * @adapter : the adapter of halmac
+ * @port : 0 for port0, 1 for port1, 2 for port2, 3 for port3, 4 for port4
+ * @addr : mac address
+ * Author : Ivan Lin
+ * Return : enum halmac_ret_status
+ * More details of status code can be found in prototype document
+ */
+enum halmac_ret_status
+get_mac_addr_88xx(struct halmac_adapter *adapter, u8 port,
+		  union halmac_wlan_addr *addr)
+{
+	u16 mac_addr_h;
+	u32 mac_addr_l;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
+
+	if (port >= HALMAC_PORTID_NUM) {
+		PLTFM_MSG_ERR("[ERR]port index >= 5\n");
+		return HALMAC_RET_PORT_NOT_SUPPORT;
+	}
+
+	switch (port) {
+	case HALMAC_PORTID0:
+		mac_addr_l = HALMAC_REG_R32(REG_MACID);
+		mac_addr_h = HALMAC_REG_R16(REG_MACID + 4);
+		break;
+	case HALMAC_PORTID1:
+		mac_addr_l = HALMAC_REG_R32(REG_MACID1);
+		mac_addr_h = HALMAC_REG_R16(REG_MACID1 + 4);
+		break;
+	case HALMAC_PORTID2:
+		mac_addr_l = HALMAC_REG_R32(REG_MACID2);
+		mac_addr_h = HALMAC_REG_R16(REG_MACID2 + 4);
+		break;
+	case HALMAC_PORTID3:
+		mac_addr_l = HALMAC_REG_R32(REG_MACID3);
+		mac_addr_h = HALMAC_REG_R16(REG_MACID3 + 4);
+		break;
+	case HALMAC_PORTID4:
+		mac_addr_l = HALMAC_REG_R32(REG_MACID4);
+		mac_addr_h = HALMAC_REG_R16(REG_MACID4 + 4);
+		break;
+	default:
+		return HALMAC_RET_PORT_NOT_SUPPORT;
+	}
+
+	addr->addr_l_h.low = rtk_cpu_to_le32(mac_addr_l);
+	addr->addr_l_h.high = rtk_cpu_to_le16(mac_addr_h);
+
+	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
+
+	return HALMAC_RET_SUCCESS;
+}
+
+void
+rts_full_bw_88xx(struct halmac_adapter *adapter, u8 enable)
+{
+	u8 value8;
+	struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
+
+	value8 = HALMAC_REG_R8(REG_INIRTS_RATE_SEL);
+
+	if (enable == 1)
+		HALMAC_REG_W8(REG_INIRTS_RATE_SEL, value8 | BIT(5));
+	else
+		HALMAC_REG_W8(REG_INIRTS_RATE_SEL, value8 & ~(BIT(5)));
+}
+
+#endif /* HALMAC_88XX_SUPPORT */

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio