From fa319f0f9238afb502c4b59d09ebe52d23c5af5f Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megi@xff.cz>
Date: Sun, 30 Jul 2023 12:06:41 +0200
Subject: [PATCH 002/480] bes2600: Update the wifi driver from bestechnic
 (0.3.5_2023.0209)

Import from https://gitlab.com/TuxThePenguin0/bes2600

New driver intended to work with Linux 6.3 provided by bestechnic.
Despite the lower version number this does appear to be a newer version.

Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
 drivers/staging/bes2600/Kconfig               |  42 +---
 drivers/staging/bes2600/Makefile              |  36 +--
 drivers/staging/bes2600/ap.c                  |  68 +++---
 drivers/staging/bes2600/ap.h                  |   2 +-
 drivers/staging/bes2600/bes2600.h             |  51 +++--
 drivers/staging/bes2600/bes2600_factory.c     |  80 ++++++-
 drivers/staging/bes2600/bes2600_factory.h     |  20 +-
 drivers/staging/bes2600/bes2600_sdio.c        |  91 +++++++-
 drivers/staging/bes2600/bes_chardev.c         |  87 ++++++--
 drivers/staging/bes2600/bes_chardev.h         |  35 ++-
 drivers/staging/bes2600/bes_fw.c              |   8 +-
 .../bes2600/bes_nl80211_testmode_msg.h        |  10 +
 drivers/staging/bes2600/bes_pwr.c             |  66 ++++--
 drivers/staging/bes2600/bes_pwr.h             |   2 +
 drivers/staging/bes2600/bh.c                  |  20 +-
 drivers/staging/bes2600/debug.c               |   6 +-
 drivers/staging/bes2600/epta_request.c        |  24 +-
 drivers/staging/bes2600/main.c                |  58 +++--
 drivers/staging/bes2600/pm.c                  | 165 ++++++++++++--
 drivers/staging/bes2600/pm.h                  |   7 +
 drivers/staging/bes2600/queue.c               | 210 +++++++++++++++---
 drivers/staging/bes2600/queue.h               |   5 +-
 drivers/staging/bes2600/scan.c                |  10 +-
 drivers/staging/bes2600/sta.c                 | 156 +++++++++----
 drivers/staging/bes2600/sta.h                 |   2 +-
 drivers/staging/bes2600/tx_loop.c             |   5 +
 drivers/staging/bes2600/tx_loop.h             |   2 +
 drivers/staging/bes2600/txrx.c                |  88 ++++++--
 drivers/staging/bes2600/txrx_opt.c            | 170 +++++++++++---
 drivers/staging/bes2600/txrx_opt.h            |  11 +-
 drivers/staging/bes2600/wifi_testmode_cmd.c   |   1 +
 drivers/staging/bes2600/wsm.c                 |  68 ++++--
 drivers/staging/bes2600/wsm.h                 |  65 ++++--
 33 files changed, 1280 insertions(+), 391 deletions(-)

diff --git a/drivers/staging/bes2600/Kconfig b/drivers/staging/bes2600/Kconfig
index 374c15db823f..9c8de42ea6e0 100644
--- a/drivers/staging/bes2600/Kconfig
+++ b/drivers/staging/bes2600/Kconfig
@@ -4,10 +4,6 @@ config BES2600
 	select CFG80211
 	select NL80211_TESTMODE
 	default m
-	---help---
-		This is an experimental driver for the bes2600 chip-set.
-		Enabling this option enables the generic driver without
-		any platform support.
 
 if BES2600
 
@@ -15,68 +11,48 @@ config BES2600_WLAN_SDIO
 	bool "SDIO bus interface support"
 	depends on MMC
 	default y
-	---help---
-		This option enables the SDIO bus interface support for Bes2600
-		WLAN driver. Say Y if you want to use SDIO.
+
 
 config BES2600_WLAN_USB
 	bool "USB bus interface support"
 	depends on USB
 	default n
-	---help---
-		This option enables the USB bus interface support for Bes2600
-		WLAN driver. Say Y if you want to use USB.
+
 
 config BES2600_WLAN_SPI
 	bool "SPI bus interface support"
 	depends on SPI
 	default n
-	---help---
-		This option enables the SPI bus interface support for Bes2600
-		WLAN driver. Say Y if you want to use USB.
+
 
 config BES2600_USE_GPIO_IRQ
 	bool "Use GPIO interrupt"
 	default n
-	---help---
-		Say Y here if you want to include GPIO IRQ support instead of SDIO IRQ.
-		If unsure, say N.
+
 
 config BES2600_5GHZ_SUPPORT
 	bool "5GHz band support"
 	default y
-	---help---
-		Say Y if your device supports 5GHz band.
-		If unsure, say N.
+
 
 config BES2600_WAPI_SUPPORT
 	bool "WAPI support"
 	default y
-	---help---
-		Say Y if your compat-wireless support WAPI.
-		If unsure, say N.
+
 
 config BES2600_USE_STE_EXTENSIONS
 	bool "STE extensions"
 	default n
-	---help---
-		Say Y if you want to include STE extensions.
-		If unsure, say N.
+
 
 config BES2600_DISABLE_BEACON_HINTS
 	bool "Disable 11d beacon hints"
 	default n
-	---help---
-		Say Y if you want to disable 11d beacon hints.
-		If unsure, say N.
 
 config BES2600_TESTMODE
 	bool "bes2600 testmode support"
 	select NL80211_TESTMODE
 	default n
-	---help---
-		Say Y if you want to enable bes2600 testmode.
-		If unsure, say N.
 
 menu "Driver debug features"
 
@@ -110,9 +86,7 @@ config BES2600_DUMP_ON_ERROR
 
 config BES2600_ITP
 	bool "Enable ITP DebugFS"
-	---help---
-		Say Y if you want to include ITP code.
-		If unsure, say N.
+
 
 endmenu
 
diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile
index 103519907e4f..6b41436f6d4e 100644
--- a/drivers/staging/bes2600/Makefile
+++ b/drivers/staging/bes2600/Makefile
@@ -6,11 +6,9 @@ CONFIG_BES2600_WLAN_SPI                 ?= n
 CONFIG_BES2600_WLAN_USB                 ?= n
 
 CONFIG_BES2600_VENDOR_CMD               ?= y
-ifneq ($(CONFIG_BES2600_WLAN_USB),y)
-CONFIG_BES2600_TESTMODE                 ?= y
-endif
+CONFIG_BES2600_TESTMODE                 ?= n
 
-CONFIG_BES2600_WAPI_SUPPORT             ?= y
+CONFIG_BES2600_WAPI_SUPPORT             ?= n
 CONFIG_BES2600_5GHZ_SUPPORT             ?= y
 CONFIG_BES2600_STA_DEBUG                ?= y
 CONFIG_BES2600_STATIC_SDD               ?= y
@@ -31,17 +29,19 @@ CONFIG_BES2600_ITP                      ?= n
 CONFIG_BES2600_NON_POWER_OF_TWO_BLOCKSIZES ?= n
 CONFIG_BES2600_CALIB_FROM_LINUX         ?= y
 
-CONFIG_BES2600_WIFI_BOOT_ON             ?= n
+CONFIG_BES2600_WIFI_BOOT_ON             ?= y
 CONFIG_BES2600_BT_BOOT_ON               ?= n
 
 PLAT_ALLWINNER_T507                     ?= n
 PLAT_ALLWINNER_R329                     ?= n
-PLAT_ROCKCHIP                           ?= y
+PLAT_ROCKCHIP                           ?= n
 PLAT_UBUNTU_VUB300                      ?= n
 PLAT_QCOM_QM215                         ?= n
+PLAT_CVITEK_182X                        ?= n
 
-BES2600_GPIO_WAKEUP_AP                  ?= y
+BES2600_GPIO_WAKEUP_AP                  ?= n
 BES2600_WRITE_DPD_TO_FILE               ?= n
+BES2600_TX_MORE_RETRY                   ?= n
 
 # bes evb
 BES2600_INDEPENDENT_EVB                 ?= n
@@ -54,13 +54,13 @@ BES2600_INTEGRATED_MODULE_V3            ?= n
 
 # 0: use dynamic_ps_timeout value
 # other: override dynamic_ps_timeout value
-BES2600_FASTPS_IDLE_TIME		?= 0
+BES2600_FASTPS_IDLE_TIME		?= 8
 
 #1.rock api(fixed macaddr)
 #2.read from file(macaddr of customers)
 #3.read from file(macaddr template)
 #4.random macaddr
-GET_MAC_ADDR_METHOD                     ?= 4
+GET_MAC_ADDR_METHOD                     ?= 0
 
 ifeq ($(CONFIG_BES2600_DEBUGFS),y)
 BES2600_DUMP_FW_DPD_LOG                 ?= n
@@ -73,7 +73,7 @@ ccflags-y += -DVENDOR_XM_KEEPALIVE
 endif
 endif
 
-BES2600_DRV_VERSION := bes2600_0.3.10_2022.1125
+BES2600_DRV_VERSION := bes2600_0.3.5_2023.0209
 
 ifeq ($(GET_MAC_ADDR_METHOD)_$(PLAT_ROCKCHIP),1_n)
  $(error Parameter setting error, GET_MAC_ADDR_METHOD can only be set to 1 on rockchip platform)
@@ -89,7 +89,8 @@ endif
 
 ifeq ($(CONFIG_BES2600_CALIB_FROM_LINUX),y)
 FACTORY_CRC_CHECK                    ?= n
-FACTORY_SAVE_MULTI_PATH              ?= n
+FACTORY_SAVE_MULTI_PATH              ?= y
+STANDARD_FACTORY_EFUSE_FLAG          ?= y
 ifeq ($(FACTORY_SAVE_MULTI_PATH),y)
 FACTORY_PATH                         ?= /data/cfg/bes2600_factory.txt
 FACTORY_DEFAULT_PATH                 ?= /lib/firmware/bes2600_factory.txt
@@ -100,7 +101,7 @@ FACTORY_PATH ?= /vendor/firmware/bes2600_factory.txt
 endif
 endif
 
-FACTORY_PATH ?= /vendor/lib/firmware/bes2600_factory.txt
+FACTORY_PATH ?= /lib/firmware/bes2600_factory.txt
 
 # basic function
 define boolen_flag
@@ -144,7 +145,7 @@ ccflags-y += -DBES_UNIFIED_PM
 endif # CONFIG_BES2600_WLAN_SPI
 
 ifeq ($(CONFIG_BES2600_WLAN_USB),y)
-FW_DOWNLOAD_BY_USB                     ?= n
+FW_DOWNLOAD_BY_USB                     ?= y
 ccflags-y += -DCONFIG_BES2600_WLAN_BES
 endif # CONFIG_BES2600_WLAN_USB
 
@@ -179,6 +180,7 @@ ccflags-y += $(call boolen_flag,PLAT_ALLWINNER_T507,y)
 ccflags-y += $(call boolen_flag,PLAT_UBUNTU_VUB300,y)
 ccflags-y += $(call boolen_flag,PLAT_ROCKCHIP,y)
 ccflags-y += $(call boolen_flag,PLAT_QCOM_QM215,y)
+ccflags-y += $(call boolen_flag,PLAT_CVITEK_182X,y)
 
 ccflags-y += $(call boolen_flag,CONFIG_BES2600_VENDOR_CMD,y)
 
@@ -192,6 +194,7 @@ ccflags-y += $(call boolen_flag,WIFI_BT_COEXIST_EPTA_ENABLE,y)
 ccflags-y += $(call boolen_flag,WIFI_BT_COEXIST_EPTA_FDD,y)
 ccflags-y += $(call boolen_flag,CONFIG_BES2600_DISABLE_BEACON_HINTS,y)
 ccflags-y += $(call boolen_flag,CONFIG_BES2600_NON_POWER_OF_TWO_BLOCKSIZES,y)
+ccflags-y += $(call boolen_flag,BES2600_TX_MORE_RETRY,y)
 
 ccflags-y += $(call boolen_flag,CONFIG_BES2600_ITP,y)
 ccflags-y += $(call boolen_flag,CONFIG_BES2600_DEBUGFS,y)
@@ -244,6 +247,7 @@ ccflags-y += $(call boolen_flag,BES2600_WRITE_DPD_TO_FILE,y)
 ccflags-y += $(call boolen_flag,BES2600_DUMP_FW_DPD_LOG,y)
 ccflags-y += $(call string_flag,BES2600_DPD_LOG_PATH)
 
+ccflags-y += $(call boolen_flag,STANDARD_FACTORY_EFUSE_FLAG,y)
 
 # internal feature options
 ccflags-y += -DAP_HT_CAP_UPDATE
@@ -259,6 +263,10 @@ ccflags-y += -DCHIP_WIFI_ROM_VER=1
 ccflags-y += -DWIFI_OUT_FEM=0
 ccflags-y += -DRF_TX_CONTROL_IO=16
 
+# stbc rx option
+ccflags-y += -DSTBC_RX_24G=0
+ccflags-y += -DSTBC_RX_5G=0
+
 #ccflags-y += -DP2P_STA_COEX
 #ccflags-y += -DCUSTOM_FEATURE
 #ccflags-y += -DMCAST_FWDING
@@ -267,7 +275,7 @@ ccflags-y += -DRF_TX_CONTROL_IO=16
 # For offloading probe response to FW, the extra IE must be included
 # in the probe response template
 #ccflags-y += -DPROBE_RESP_EXTRA_IE
-#ccflags-y += -DIPV6_FILTERING
+ccflags-y += -DIPV6_FILTERING
 
 # basic files for building module
 bes2600-y := \
diff --git a/drivers/staging/bes2600/ap.c b/drivers/staging/bes2600/ap.c
index 2126e7b516da..c6a4b8c29106 100644
--- a/drivers/staging/bes2600/ap.c
+++ b/drivers/staging/bes2600/ap.c
@@ -30,7 +30,7 @@
 
 #define BES2600_ENABLE_ARP_FILTER_OFFLOAD	3
 
-#define BES2600_KEEP_ALIVE_PERIOD	(20)
+#define BES2600_KEEP_ALIVE_PERIOD	(15)
 
 #ifndef ERP_INFO_BYTE_OFFSET
 #define ERP_INFO_BYTE_OFFSET 2
@@ -249,8 +249,11 @@ static int bes2600_set_tim_impl(struct bes2600_vif *priv, bool aid0_bit_set)
 	bes2600_dbg(BES2600_DBG_AP, "[AP] %s mcast: %s.\n",
 		__func__, aid0_bit_set ? "ena" : "dis");
 
-	skb = ieee80211_beacon_get_tim(priv->hw, priv->vif,
-			&tim_offset, &tim_length);
+	// skb = ieee80211_beacon_get_tim(priv->hw, priv->vif,
+	// 		&tim_offset, &tim_length);
+	   skb = ieee80211_beacon_get_tim(priv->hw, priv->vif,
+				       &tim_offset, &tim_length, 0);
+	
 	if (!skb) {
 		if (!__bes2600_flush(hw_priv, true, priv->if_id))
 			wsm_unlock_tx(hw_priv);
@@ -393,18 +396,19 @@ static int bes2600_set_btcoexinfo(struct bes2600_vif *priv)
 void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 			     struct ieee80211_vif *vif,
 			     struct ieee80211_bss_conf *info,
-			     u32 changed)
+			     u64 changed)
 {
 	struct bes2600_common *hw_priv = dev->priv;
 	struct bes2600_vif *priv = cw12xx_get_vif_from_ieee80211(vif);
 	struct ieee80211_conf *conf = &dev->conf;
 	const u8 override_fpsm_timeout = BES2600_FASTPS_IDLE_TIME;
+	struct ieee80211_vif_cfg cfg;
 
 #ifdef P2P_MULTIVIF
 	if (priv->if_id == CW12XX_GENERIC_IF_ID)
 		return;
 #endif
-	bes2600_info(BES2600_DBG_AP, "BSS CHANGED:	%08x\n", changed);
+	bes2600_info(BES2600_DBG_AP, "BSS CHANGED:	%08llx\n", changed);
 	down(&hw_priv->conf_lock);
 	if (changed & BSS_CHANGED_BSSID) {
 #ifdef CONFIG_BES2600_TESTMODE
@@ -430,19 +434,19 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 		struct wsm_arp_ipv4_filter filter = {0};
 		int i;
 		bes2600_dbg(BES2600_DBG_AP, "[STA] BSS_CHANGED_ARP_FILTER cnt: %d",
-				     info->arp_addr_cnt);
+				      vif->cfg.arp_addr_cnt);
 
 #ifdef WIFI_BT_COEXIST_EPTA_ENABLE
-		if (info->arp_addr_cnt > 0) {
+		if (vif->cfg.arp_addr_cnt > 0) {
 			bwifi_change_current_status(hw_priv, BWIFI_STATUS_GOT_IP);
 		}
 #endif
 		/* Currently only one IP address is supported by firmware.
 		 * In case of more IPs arp filtering will be disabled. */
-		if (info->arp_addr_cnt > 0 &&
-		    info->arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) {
-			for (i = 0; i < info->arp_addr_cnt; i++) {
-				filter.ipv4Address[i] = info->arp_addr_list[i];
+		if (vif->cfg.arp_addr_cnt > 0 &&
+		    vif->cfg.arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) {
+			for (i = 0; i < vif->cfg.arp_addr_cnt; i++) {
+				filter.ipv4Address[i] = vif->cfg.arp_addr_list[i];
 				bes2600_dbg(BES2600_DBG_AP, "[STA] addr[%d]: 0x%X\n",
 					  i, filter.ipv4Address[i]);
 			}
@@ -490,7 +494,7 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 			priv->power_set_true = 0;
 			priv->user_power_set_true = 0;
 
-			if(!info->ps) {
+			if(!cfg.ps) {
 				bes2600_pwr_set_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_PS_ACTIVE);
 			}
 		}
@@ -498,7 +502,8 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 		bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_GET_IP);
 	}
 
-#ifdef IPV6_FILTERING
+// #if (defined(IPV6_FILTERING) && LINUX_VERSION_CODE > KERNEL_VERSION(4,19,0))
+#if 0
 	if (changed & BSS_CHANGED_NDP_FILTER) {
 		struct wsm_ndp_ipv6_filter filter = {0};
 		int i;
@@ -606,7 +611,7 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 		priv->wep_default_key_id = -1;
 		wsm_unlock_tx(hw_priv);
 
-		if (!info->assoc /* && !info->ibss_joined */) {
+		if (!cfg.assoc /* && !info->ibss_joined */) {
 			#ifdef P2P_STA_COEX
 			priv->cqm_link_loss_count = 400;
 			priv->cqm_beacon_loss_count = 200;
@@ -628,8 +633,8 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 		int is_combo = 0;
 		int i;
 		struct bes2600_vif *tmp_priv;
-		bes2600_info(BES2600_DBG_AP, "BSS_CHANGED_ASSOC assoc: %d.\n", info->assoc);
-		if (info->assoc) { /* TODO: ibss_joined */
+		bes2600_info(BES2600_DBG_AP, "BSS_CHANGED_ASSOC assoc: %d.\n", vif->cfg.assoc );
+		if (cfg.assoc) { /* TODO: ibss_joined */
 			struct ieee80211_sta *sta = NULL;
 			if (info->dtim_period)
 				priv->join_dtim_period = info->dtim_period;
@@ -640,7 +645,9 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 				cancel_delayed_work_sync(&priv->join_timeout);
 				bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_JOIN);
 				bes2600_pwr_set_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_GET_IP);
-				txrx_opt_timer_init(priv->hw_priv);
+#ifdef BES2600_TX_RX_OPT
+				txrx_opt_timer_init(priv);
+#endif
 			}
 
 			rcu_read_lock();
@@ -651,11 +658,11 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 				* mac80211 changes are available */
 				enum nl80211_channel_type ch_type;
 				BUG_ON(!hw_priv->channel);
-				hw_priv->ht_info.ht_cap = sta->ht_cap;
+				hw_priv->ht_info.ht_cap = sta->deflink.ht_cap;
 				priv->bss_params.operationalRateSet =
 					__cpu_to_le32(
 					bes2600_rate_mask_to_wsm(hw_priv,
-					sta->supp_rates[
+					sta->deflink.supp_rates[
 						hw_priv->channel->band]));
 				rcu_read_unlock();
 				ch_type = cfg80211_get_chandef_type(&info->chandef);
@@ -769,7 +776,7 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 					priv->cqm_beacon_loss_count :
 					priv->cqm_link_loss_count;
 
-			priv->bss_params.aid = info->aid;
+			priv->bss_params.aid = cfg.aid;
 
 			if (priv->join_dtim_period < 1)
 				priv->join_dtim_period = 1;
@@ -975,7 +982,7 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 	if (changed & BSS_CHANGED_BANDWIDTH) {
 		enum nl80211_channel_type ch_type = cfg80211_get_chandef_type(&info->chandef);
 
-		if (info->assoc &&
+		if (cfg.assoc &&
 		    hw_priv->ht_info.channel_type != ch_type &&
 		    priv->join_status == BES2600_JOIN_STATUS_STA) {
 			struct wsm_switch_channel channel;
@@ -990,7 +997,7 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 	}
 
 	if (changed & BSS_CHANGED_PS) {
-		if (info->ps == false)
+		if (cfg.ps == false)
 			priv->powersave_mode.pmMode = WSM_PSM_ACTIVE;
 		else if (conf->dynamic_ps_timeout <= 0)
 			priv->powersave_mode.pmMode = WSM_PSM_PS;
@@ -999,7 +1006,7 @@ void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 
 		/* set/clear ps active power busy event */
 		if(priv->join_status == BES2600_JOIN_STATUS_STA) {
-			if(!info->ps) {
+			if(!cfg.ps) {
 				bes2600_pwr_set_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_PS_ACTIVE);
 			} else {
 				bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_PS_ACTIVE);
@@ -1292,7 +1299,8 @@ static int bes2600_upload_beacon(struct bes2600_vif *priv)
 #endif
 		frame.rate = WSM_TRANSMIT_RATE_6;
 
-	frame.skb = ieee80211_beacon_get(priv->hw, priv->vif);
+	// frame.skb = ieee80211_beacon_get(priv->hw, priv->vif);
+	frame.skb = ieee80211_beacon_get(priv->hw, priv->vif, 0);
 	if (WARN_ON(!frame.skb))
 		return -ENOMEM;
 
@@ -1461,7 +1469,8 @@ static int bes2600_upload_null(struct bes2600_vif *priv)
 	};
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
-	frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
+	// frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
+	frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, -1, true);
 #else
 	frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif);
 #endif
@@ -1486,7 +1495,8 @@ static int bes2600_upload_qosnull(struct bes2600_vif *priv)
 	};
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
-	frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, true);
+	// frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, true);
+	frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, -1, true);
 #else
 	frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif);
 #endif
@@ -1609,7 +1619,8 @@ static int bes2600_start_ap(struct bes2600_vif *priv)
 
 #ifndef HIDDEN_SSID
 	/* Get SSID */
-	skb = ieee80211_beacon_get(priv->hw, priv->vif);
+	// skb = ieee80211_beacon_get(priv->hw, priv->vif);
+	skb = ieee80211_beacon_get(priv->hw, priv->vif, 0);
 	if (WARN_ON(!skb))
 		return -ENOMEM;
 
@@ -1960,7 +1971,8 @@ void bes2600_ht_info_update_work(struct work_struct *work)
                 .count = 1,
         };
 
-        skb = ieee80211_beacon_get(priv->hw, priv->vif);
+        // skb = ieee80211_beacon_get(priv->hw, priv->vif);
+		skb = ieee80211_beacon_get(priv->hw, priv->vif, 0);
 	if (WARN_ON(!skb))
 		return;
 
diff --git a/drivers/staging/bes2600/ap.h b/drivers/staging/bes2600/ap.h
index f9d85d847397..63874ccf33e2 100644
--- a/drivers/staging/bes2600/ap.h
+++ b/drivers/staging/bes2600/ap.h
@@ -26,7 +26,7 @@ void bes2600_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
 void bes2600_bss_info_changed(struct ieee80211_hw *dev,
 			     struct ieee80211_vif *vif,
 			     struct ieee80211_bss_conf *info,
-			     u32 changed);
+			     u64 changed);
 
 int bes2600_ampdu_action(struct ieee80211_hw *hw,
 			struct ieee80211_vif *vif,
diff --git a/drivers/staging/bes2600/bes2600.h b/drivers/staging/bes2600/bes2600.h
index ecfe154a0283..d31dd8cf683e 100644
--- a/drivers/staging/bes2600/bes2600.h
+++ b/drivers/staging/bes2600/bes2600.h
@@ -33,8 +33,8 @@
 #define CW12XX_GENERIC_IF_ID		(2)
 #define CW12XX_HOST_VIF0_11N_THROTTLE	(63)
 #define CW12XX_HOST_VIF1_11N_THROTTLE	(63)
-#define CW12XX_HOST_VIF0_11BG_THROTTLE	(15)
-#define CW12XX_HOST_VIF1_11BG_THROTTLE	(15)
+#define CW12XX_HOST_VIF0_11BG_THROTTLE	(20)
+#define CW12XX_HOST_VIF1_11BG_THROTTLE	(20)
 #if 0
 #define CW12XX_FW_VIF0_THROTTLE		(15)
 #define CW12XX_FW_VIF1_THROTTLE		(15)
@@ -374,6 +374,13 @@ struct bes2600_common {
 	atomic_t			bh_term;
 	atomic_t			bh_suspend;
 
+#ifdef CONFIG_PM
+	/*Suspend*/
+	u8				unjoin_if_id_slots;
+	bool				suspend_in_progress;
+	struct notifier_block		pm_notify;
+#endif
+
 	struct workqueue_struct         *bh_workqueue;
 	struct work_struct              bh_work;
 
@@ -642,24 +649,28 @@ struct bes2600_vif {
 #endif
 	bool pmf;
 
-    u32 hw_value;
-    /* dot11CountersTable */
-    u32 dot11TransmittedFragmentCount;
-    u32 dot11MulticastTransmittedFrameCount;
-    u32 dot11FailedCount;
-    u32 dot11RetryCount;
-    u32 dot11MultipleRetryCount;
-    u32 dot11FrameDuplicateCount;
-    u32 dot11ReceivedFragmentCount;
-    u32 dot11RxReorderLeakCount;
-    u32 dot11ReceivedBytes;
-    u32 dot11ReceivedDataBytes;
-    u32 dot11MulticastReceivedFrameCount;
-    u32 dot11TransmittedFrameCount;
-    u32 dot11TransmittedBytes;
-    u32 dot11TransmittedDataBytes;
-    u32 dot11Txbps;
-    u32 dot11Rxbps;
+	u32 hw_value;
+	/* dot11CountersTable */
+	u32 dot11TransmittedFragmentCount;
+	u32 dot11MulticastTransmittedFrameCount;
+	u32 dot11FailedCount;
+	u32 dot11RetryCount;
+	u32 dot11MultipleRetryCount;
+	u32 dot11FrameDuplicateCount;
+	u32 dot11ReceivedFragmentCount;
+	u32 dot11RxReorderLeakCount;
+	u32 dot11ReceivedBytes;
+	u32 dot11ReceivedDataBytes;
+	u32 dot11MulticastReceivedFrameCount;
+	u32 dot11TransmittedFrameCount;
+	u32 dot11TransmittedBytes;
+	u32 dot11TransmittedDataBytes;
+	u32 dot11Txbps;
+	u32 dot11Rxbps;
+
+	/* used to calculate signal strength */
+	s32 signal;
+	s32 signal_mul;
 };
 struct bes2600_sta_priv {
 	int link_id;
diff --git a/drivers/staging/bes2600/bes2600_factory.c b/drivers/staging/bes2600/bes2600_factory.c
index c525311c2a30..f1a7a84027c2 100644
--- a/drivers/staging/bes2600/bes2600_factory.c
+++ b/drivers/staging/bes2600/bes2600_factory.c
@@ -100,13 +100,17 @@ static int bes2600_factory_crc_check(struct factory_t *factory_data)
 {
 #ifdef FACTORY_CRC_CHECK
 	u32 cal_crc = 0;
+	u32 crc_len = sizeof(factory_data_t);
+#ifndef STANDARD_FACTORY_EFUSE_FLAG
+	crc_len = (crc_len - sizeof(u16) + 3) & (~0x3);
+#endif
 
 	if (!factory_data) {
 		bes2600_err(BES2600_DBG_FACTORY, "%s NULL pointer err \n", __func__);
 		return -1;
 	}
 
-	cal_crc = factory_crc32((uint8_t *)(&(factory_data->data)), sizeof(factory_data_t));
+	cal_crc = factory_crc32((uint8_t *)(&(factory_data->data)), crc_len);
 	if (factory_data->head.crc != cal_crc) {
 		bes2600_err(BES2600_DBG_CHARDEV,
 			"bes2600 factory check failed, calc_crc:0x%08x factory_crc: 0x%08x\n",
@@ -243,9 +247,19 @@ static inline int factory_parse(uint8_t *source_buf, struct factory_t *factory)
 		&factory->data.bt_tx_power[0],\
 		&factory->data.bt_tx_power[1],\
 		&factory->data.bt_tx_power[2],\
-		&factory->data.bt_tx_power[3]);
+		&factory->data.bt_tx_power[3]
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+		,&factory->data.select_efuse);
+#else
+		);
+#endif
 
-	if (ret != 30) {
+#ifndef STANDARD_FACTORY_EFUSE_FLAG
+	factory->data.select_efuse = 0;
+#endif
+
+	if (ret != FACTORY_MEMBER_NUM)
+	{
 		bes2600_err(BES2600_DBG_FACTORY, "bes2600_factory.txt parse fail\n");
 		return -1;
 	}
@@ -401,6 +415,7 @@ void factory_little_endian_cvrt(u8 *data)
 
 	TRANS_LE16(trans_data->data.tx_power_flags_5G);
 	TRANS_LE16(trans_data->data.temperature_5G);
+	TRANS_LE16(trans_data->data.select_efuse);
 
 }
 
@@ -520,6 +535,9 @@ static int bes2600_factory_cali_file_hdr_fill(struct factory_t **factory_head)
 	(*factory_head)->data.bt_tx_power[1] = 0x10;
 	(*factory_head)->data.bt_tx_power[2] = 0x05;
 	(*factory_head)->data.bt_tx_power[3] = 0x15;
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+	(*factory_head)->data.select_efuse = 0;
+#endif
 
 	return 0;
 }
@@ -741,6 +759,49 @@ err:
 	return ret;
 }
 
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+int16_t bes2600_select_efuse_flag_write(uint16_t select_efuse_flag)
+{
+	struct factory_t *factory_flag_p = NULL;
+	u8 *file_buffer = NULL;
+	int16_t ret = 0;
+
+	if (!(file_buffer = bes2600_factory_get_file_buffer()))
+		return -FACTORY_GET_INPUT_NULL_POINTER;
+
+	bes2600_factory_lock();
+
+	/**
+	 * When it returns true, it means that the factory file has been read.
+	 * When it returns false, it means that the factory file does not exist,
+	 * or the operation of reading the text file fails. At this time, a new factory file will be created.
+	 */
+	if (bes2600_factory_file_status_read(file_buffer)) {
+		factory_flag_p = factory_p;
+	} else {
+		if (bes2600_factory_cali_file_hdr_fill(&factory_flag_p)) {
+			bes2600_warn(BES2600_DBG_FACTORY, "%s, create bes2600_factory.txt fail.", __func__);
+			ret = -FACTORY_FACTORY_TXT_CREATE_FAIL;
+			goto err;
+		}
+	}
+
+	factory_flag_p->data.select_efuse = select_efuse_flag;
+	bes2600_dbg(BES2600_DBG_FACTORY, "%s: select_efuse = %x\n", __func__, select_efuse_flag);
+
+	/* save to file */
+	if (bes2600_wifi_cali_table_save(file_buffer, factory_flag_p)) {
+		ret = -FACTORY_SAVE_WRITE_ERR;
+		goto err;
+	}
+
+err:
+	bes2600_factory_free_file_buffer(file_buffer);
+	bes2600_factory_unlock();
+	return ret;
+}
+#endif
+
 int16_t vendor_set_power_cali_flag(struct wifi_power_cali_flag_t *cali_flag)
 {
 	struct factory_t *factory_power_flag_p = NULL;
@@ -823,13 +884,22 @@ static inline int factory_build(uint8_t *dest_buf, struct factory_t *factory)
 		factory->data.bt_tx_power[0],\
 		factory->data.bt_tx_power[1],\
 		factory->data.bt_tx_power[2],\
-		factory->data.bt_tx_power[3]);
+		factory->data.bt_tx_power[3]
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+		,factory->data.select_efuse);
+#else
+		);
+#endif
 }
 
 static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *factory_save_p)
 {
 	int ret = 0;
 	int w_size;
+	u32 crc_len = sizeof(factory_data_t);
+#ifndef STANDARD_FACTORY_EFUSE_FLAG
+	crc_len = (crc_len - sizeof(u16) + 3) & (~0x3);
+#endif
 
 	bes2600_info(BES2600_DBG_FACTORY, "enter %s\n", __func__);
 
@@ -846,7 +916,7 @@ static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *facto
 	file_buffer[FACTORY_MAX_SIZE - 1] = '\n';
 
 	factory_save_p->head.crc =
-		factory_crc32((uint8_t *)(&(factory_save_p->data)), sizeof(factory_data_t));
+		factory_crc32((uint8_t *)(&(factory_save_p->data)), crc_len);
 
 	w_size = factory_build(file_buffer, factory_save_p);
 
diff --git a/drivers/staging/bes2600/bes2600_factory.h b/drivers/staging/bes2600/bes2600_factory.h
index 473840282a82..3835b0d9c96c 100644
--- a/drivers/staging/bes2600/bes2600_factory.h
+++ b/drivers/staging/bes2600/bes2600_factory.h
@@ -19,7 +19,7 @@
 #define NVREC_CURRENT_VERSION	2
 
 #define FACTORY_MAX_SIZE 600
-#define STANDARD_FACTORY "##head\n\
+#define __STANDARD_FACTORY "##head\n\
 magic:0x%hx\n\
 version:0x%hx\n\
 crc:0x%x\n\
@@ -53,8 +53,17 @@ temperature_5G:0x%hx\n\
 bdr_div:0x%x\n\
 bdr_power:0x%x\n\
 edr_div:0x%x\n\
-edr_power:0x%x\n\
-%%%%\n"
+edr_power:0x%x\n"
+
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+#define STANDARD_FACTORY_EFUSE "##select_efuse_flag\nselect_efuse:%hx\n"
+#define FACTORY_MEMBER_NUM 31
+#else
+#define STANDARD_FACTORY_EFUSE
+#define FACTORY_MEMBER_NUM 30
+#endif
+
+#define STANDARD_FACTORY  __STANDARD_FACTORY STANDARD_FACTORY_EFUSE "%%%%\n"
 
 typedef struct {
 	uint16_t magic;
@@ -103,6 +112,7 @@ typedef struct {
 	uint32_t bt_tx_power[4];
 	/* The temperature after 5G clibrating. */
 	uint16_t temperature_5G;
+	uint16_t select_efuse;
 } factory_data_t;
 
 struct factory_t {
@@ -204,5 +214,7 @@ int16_t bes2600_wifi_cali_freq_write(struct wifi_freq_cali_t *data_cali);
 int16_t vendor_get_freq_cali(struct wifi_freq_cali_t *vendor_freq);
 int16_t vendor_get_power_cali(struct wifi_get_power_cali_t *power_cali);
 int16_t vendor_set_power_cali_flag(struct wifi_power_cali_flag_t *cali_flag);
-
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+int16_t bes2600_select_efuse_flag_write(uint16_t select_efuse_flag);
+#endif
 #endif
diff --git a/drivers/staging/bes2600/bes2600_sdio.c b/drivers/staging/bes2600/bes2600_sdio.c
index 5252951cc3bb..d9b60c72fd45 100644
--- a/drivers/staging/bes2600/bes2600_sdio.c
+++ b/drivers/staging/bes2600/bes2600_sdio.c
@@ -47,6 +47,15 @@ extern void sw_mci_rescan_card(unsigned id, unsigned insert);
 extern void sunxi_wlan_set_power(bool on_off);
 #endif
 
+#ifdef PLAT_CVITEK_182X
+#include <linux/regulator/consumer.h>
+
+extern int cvi_sdio_rescan(void);
+extern int cvi_get_wifi_pwr_on_gpio(void);
+extern int cvi_get_wifi_reset_gpio(void);
+extern int cvi_get_wifi_wakeup_gpio(void);
+#endif
+
 #if defined(BES2600_BOOT_UART_TO_SDIO)
 static struct sbus_ops bes2600_sdio_sbus_ops;
 extern int bes2600_boot_uart_to_sdio(struct sbus_ops *ops);
@@ -434,15 +443,23 @@ static int bes2600_sdio_reg_write(struct sbus_priv *self, u32 reg,
 #ifndef CONFIG_BES2600_USE_GPIO_IRQ
 static void bes2600_sdio_irq_handler(struct sdio_func *func)
 {
+#ifdef PLAT_CVITEK_182X
+	int ret =0;
+#endif
 	struct sbus_priv *self = sdio_get_drvdata(func);
 	unsigned long flags;
-	bes2600_dbg(BES2600_DBG_SDIO, "\n %s called, fw_started:%d \n",
-			 __func__, self->fw_started);
 
 	if (WARN_ON(!self)) {
 		return;
 	}
 
+	bes2600_dbg(BES2600_DBG_SDIO, "\n %s called, fw_started:%d \n",
+			 __func__, self->fw_started);
+#ifdef PLAT_CVITEK_182X
+	sdio_claim_host(func);
+	sdio_readb(func, 1, &ret);
+	sdio_release_host(func);
+#endif
 	if (likely(self->fw_started && self->core)) {
 		queue_work(self->sdio_wq, &self->rx_work);
 		self->last_irq_timestamp = jiffies;
@@ -598,6 +615,16 @@ static int bes2600_sdio_off(const struct bes2600_platform_data_sdio *pdata)
 	rockchip_wifi_power(0);
 #endif
 
+#ifdef PLAT_CVITEK_182X
+	if (gpio_is_valid(pdata->powerup)) {
+		gpio_direction_output(pdata->powerup, 0);
+	}
+
+	if (gpio_is_valid(pdata->reset)) {
+		gpio_direction_output(pdata->reset, 0);
+	}
+#endif
+
 	if (pdata == NULL)
 		return 0;
 
@@ -626,6 +653,18 @@ static int bes2600_sdio_on(const struct bes2600_platform_data_sdio *pdata)
 	rockchip_wifi_set_carddetect(1);
 #endif
 
+#ifdef PLAT_CVITEK_182X
+	if (gpio_is_valid(pdata->powerup)) {
+		gpio_direction_output(pdata->powerup, 1);
+	}
+
+	msleep(10);
+	if (gpio_is_valid(pdata->reset)) {
+		gpio_direction_output(pdata->reset, 0);
+	}
+	cvi_sdio_rescan();
+#endif
+
 	if (pdata != NULL) {
 #ifdef BES2600_INDEPENDENT_EVB
 		if (gpio_is_valid(pdata->powerup)) {
@@ -1019,6 +1058,10 @@ static void sdio_scan_work(struct work_struct *work)
 #ifdef PLAT_ROCKCHIP
 	rockchip_wifi_set_carddetect(1);
 #endif
+
+#ifdef PLAT_CVITEK_182X
+	cvi_sdio_rescan();
+#endif
 	bes2600_info(BES2600_DBG_SDIO, "%s: power down, rescan card\n", __FUNCTION__);
 }
 
@@ -1362,7 +1405,7 @@ err2:
 	return 0;
 }
 
-#if defined(PLAT_ALLWINNER)|| defined (PLAT_ROCKCHIP)
+#if defined(PLAT_ALLWINNER)|| defined (PLAT_ROCKCHIP) || defined(PLAT_CVITEK_182X)
 static struct bes2600_platform_data_sdio bes_sdio_plat_data = {
 #if defined(BES2600_INDEPENDENT_EVB)
 	.reset = GPIOA(9),
@@ -1380,27 +1423,34 @@ static struct bes2600_platform_data_sdio bes_sdio_plat_data = {
 	.reset = -1,
 	.powerup = -1,
 	.wakeup = -1,
+#elif defined(PLAT_CVITEK_182X)
+	.reset = -1,
+	.powerup = -1,
+	.wakeup = -1,
+	.host_wakeup = -1,
 #endif
 };
 #endif
 
 struct bes2600_platform_data_sdio *bes2600_get_platform_data(void)
 {
-#if defined(PLAT_ALLWINNER)|| defined (PLAT_ROCKCHIP)
+#if defined(PLAT_ALLWINNER)|| defined (PLAT_ROCKCHIP) || defined(PLAT_CVITEK_182X)
 	return &bes_sdio_plat_data;
 #else
 	return NULL;
 #endif
 }
 
-static void bes2600_get_gpio_from_dts(int *gpio_num, const char *gpio_name)
+
+static void __attribute__((unused)) bes2600_get_gpio_from_dts(int *gpio_num, const char *gpio_name)
 {
 	int wakeup_gpio;
-	enum of_gpio_flags flags;
+	// enum of_gpio_flags flags;
 	struct device_node *wireless_node;
 	wireless_node = of_find_node_with_property(NULL, gpio_name);
 	if(wireless_node != NULL){
-		wakeup_gpio = of_get_named_gpio_flags(wireless_node, gpio_name, 0, &flags);
+		// wakeup_gpio = of_get_named_gpio_flags(wireless_node, gpio_name, 0, &flags);
+		wakeup_gpio = of_get_named_gpio(wireless_node, gpio_name, 0);
 		if (gpio_is_valid(wakeup_gpio))
 			*gpio_num = wakeup_gpio;
 	}else{
@@ -1408,6 +1458,7 @@ static void bes2600_get_gpio_from_dts(int *gpio_num, const char *gpio_name)
 	}
 }
 
+
 static int bes2600_platform_data_init(void)
 {
 	int ret = 0;
@@ -1416,6 +1467,9 @@ static int bes2600_platform_data_init(void)
 		return 0;
 
 		/* Ensure I/Os are pulled low */
+#ifdef PLAT_CVITEK_182X
+	pdata->reset=cvi_get_wifi_reset_gpio();
+#endif
 	if (gpio_is_valid(pdata->reset)) {
 		ret = gpio_request(pdata->reset, "bes2600_wlan_reset");
 		if (ret) {
@@ -1427,7 +1481,9 @@ static int bes2600_platform_data_init(void)
 	} else {
 		bes2600_err(BES2600_DBG_SDIO, "reset is invalid\n");
 	}
-
+#ifdef PLAT_CVITEK_182X
+	pdata->powerup=cvi_get_wifi_pwr_on_gpio();
+#endif
 	if (gpio_is_valid(pdata->powerup)) {
 		ret = gpio_request(pdata->powerup, "bes2600_wlan_powerup");
 		if (ret) {
@@ -1439,8 +1495,11 @@ static int bes2600_platform_data_init(void)
 	} else {
 		bes2600_err(BES2600_DBG_SDIO, "powerup is invalid\n");
 	}
-
+#ifdef PLAT_CVITEK_182X
+	pdata->wakeup=cvi_get_wifi_wakeup_gpio();
+#else
 	bes2600_get_gpio_from_dts(&pdata->wakeup, "WIFI,host_wakeup_wifi");
+#endif
 	if (gpio_is_valid(pdata->wakeup)) {
 		ret = gpio_request(pdata->wakeup, "bes2600_wakeup");
 		if (ret) {
@@ -1452,8 +1511,9 @@ static int bes2600_platform_data_init(void)
 	} else {
 		bes2600_err(BES2600_DBG_SDIO, "wakeup is invalid\n");
 	}
-
+#ifndef PLAT_CVITEK_182X
 	bes2600_get_gpio_from_dts(&pdata->host_wakeup, "WIFI,host_wake_irq");
+#endif
 	if (gpio_is_valid(pdata->host_wakeup)) {
 		ret = gpio_request(pdata->host_wakeup, "bes2600_host_irq");
 		if (ret) {
@@ -1957,6 +2017,14 @@ static void bes2600_sdio_power_down(struct sbus_priv *self)
 #if defined(PLAT_ALLWINNER)
 	sunxi_wlan_set_power(false);
 #endif
+
+#ifdef PLAT_CVITEK_182X
+	struct bes2600_platform_data_sdio *pdata = bes2600_get_platform_data();
+
+	if (gpio_is_valid(pdata->powerup)) {
+		gpio_direction_output(pdata->powerup, 0);
+	}
+#endif
 #endif
 
 	msleep(10);
@@ -2232,6 +2300,7 @@ static irqreturn_t bes2600_wlan_bt_hostwake_thread(int irq, void *dev_id)
 	bes2600_info(BES2600_DBG_SDIO, "bes2600_wlan_hostwake:%d\n", dev_id == (void *)pdata);
 
 	if (dev_id == (void *)pdata) {
+		bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_SETTING);
 		pdata->wakeup_source = true;
 		disable_irq_nosync(irq);
 		return IRQ_HANDLED;
@@ -2277,9 +2346,9 @@ static int bes2600_wlan_bt_hostwake_register(void)
 
 static void bes2600_wlan_bt_hostwake_unregister(void)
 {
+	int ret = 0;
 	struct bes2600_platform_data_sdio *pdata = bes2600_get_platform_data();
 
-	int ret = 0;
 #if defined(PLAT_ALLWINNER)
 	int irq = sunxi_wlan_get_oob_irq();
 #elif defined(PLAT_ROCKCHIP)
diff --git a/drivers/staging/bes2600/bes_chardev.c b/drivers/staging/bes2600/bes_chardev.c
index 77573e59952e..e4c81cf0c922 100644
--- a/drivers/staging/bes2600/bes_chardev.c
+++ b/drivers/staging/bes2600/bes_chardev.c
@@ -73,7 +73,10 @@ struct bes_cdev
 	int no_dpd;
 #endif
 	enum pend_read_op read_flag;
-	u32 wakeup_state; /* for userspace check wakeup reason */
+	enum wakeup_event wakeup_by_event;	/* used to filter unwanted event wakeup reason report */
+	u16 wakeup_state; /* for userspace check wakeup reason */
+	wait_queue_head_t wakeup_reason_wq;
+	u16 src_port;
 #ifdef BES2600_DUMP_FW_DPD_LOG
 	u8 *dpd_log;
 	u16 dpd_log_len;
@@ -608,10 +611,17 @@ static ssize_t bes2600_chrdev_read(struct file *file, char __user *user_buf,
 {
 	char buf[64] = {0};
 	unsigned int len;
+	long status = 0;
 
 	switch (bes2600_cdev.read_flag) {
 	case BES_CDEV_READ_WAKEUP_STATE:
-		len = sprintf(buf, "wakeup_state:%u\n", bes2600_cdev.wakeup_state);
+		if (bes2600_chrdev_wakeup_by_event_get() > WAKEUP_EVENT_NONE) {
+			status = wait_event_timeout(bes2600_cdev.wakeup_reason_wq, 
+				bes2600_chrdev_wakeup_by_event_get() ==  WAKEUP_EVENT_NONE, HZ * 2);
+			WARN_ON(status <= 0);
+		}
+		len = sprintf(buf, "wakeup_reason: %u, src_port: %u\n",
+		              bes2600_cdev.wakeup_state, bes2600_cdev.src_port);
 		break;
 	default:
 		len = sprintf(buf, "dpd_calied:%d wifi_opened:%d bt_opened:%d fw_type:%d\n",
@@ -729,13 +739,35 @@ static int bes2600_chrdev_write_dpd_data_to_file(const char *path, void *buffer,
 	return ret;
 }
 
+static bool bes2600_chrdev_dpd_is_vaild(u8 *dpd_data)
+{
+	u32 cal_crc = 0;
+	u32 dpd_crc = le32_to_cpup((__le32 *)(dpd_data));
+	u32 dpd_ver = le32_to_cpup((__le32 *)(dpd_data + DPD_VERSION_OFFSET));
+
+	/* check version */
+	if (dpd_ver < DPD_CUR_VERSION)
+		return false;
+
+	cal_crc ^= 0xffffffffL;
+	cal_crc = crc32_le(cal_crc, dpd_data + 4, DPD_BIN_SIZE - 4);
+	cal_crc ^= 0xffffffffL;
+
+	/* check if the dpd data is valid */
+	if (cal_crc != dpd_crc) {
+		bes2600_err(BES2600_DBG_CHARDEV,
+			"bes2600 dpd data from file check failed, calc_crc:0x%08x dpd_crc: 0x%08x\n",
+			cal_crc, dpd_crc);
+		return false;
+	}
+
+	return true;
+}
+
 static int bes2600_chrdev_read_and_check_dpd_data(const char *file, u8 **data, u32 *len)
 {
 	int ret = 0;
-	u32 read_len = 0;
 	u8* read_data = NULL;
-	u32 cal_crc = 0;
-	u32 dpd_crc = 0;
 	struct file *fp;
 
 	/* open file */
@@ -773,27 +805,16 @@ static int bes2600_chrdev_read_and_check_dpd_data(const char *file, u8 **data, u
 		goto err2;
 	}
 
-	/* calculate crc value */
-	read_len = DPD_BIN_SIZE;
-	dpd_crc = *((u32 *)read_data);
-	cal_crc ^= 0xffffffffL;
-	cal_crc = crc32_le(cal_crc, read_data + 4, read_len - 4);
-	cal_crc ^= 0xffffffffL;
-
-	/* check if the dpd data is valid */
-	if(cal_crc != dpd_crc) {
-		bes2600_err(BES2600_DBG_CHARDEV,
-			"bes2600 dpd data from file check failed, calc_crc:0x%08x dpd_crc: 0x%08x\n",
-			cal_crc, dpd_crc);
+	/* check dpd version and crc */
+	if (!bes2600_chrdev_dpd_is_vaild(read_data))
 		goto err2;
-	}
 
 	/* close file */
 	filp_close(fp, NULL);
 
 	/* copy data to external */
 	*data = read_data;
-	*len = read_len;
+	*len = DPD_BIN_SIZE;;
 
 	/* output debug information */
 	bes2600_info(BES2600_DBG_CHARDEV, "read dpd data from %s\n", file);
@@ -862,7 +883,7 @@ void bes2600_chrdev_free_dpd_data(void)
 int bes2600_chrdev_update_dpd_data(void)
 {
 	u32 cal_crc = 0;
-	u32 dpd_crc = *((u32 *)bes2600_cdev.dpd_data);
+	u32 dpd_crc = le32_to_cpup((__le32 *)(bes2600_cdev.dpd_data));
 
 	/* check if the dpd data is valid */
 	cal_crc ^= 0xffffffffL;
@@ -1165,7 +1186,7 @@ void bes2600_chrdev_start_bus_probe(void)
 	spin_unlock(&bes2600_cdev.status_lock);
 
 	cancel_delayed_work_sync(&bes2600_cdev.probe_timeout_work);
-	schedule_delayed_work(&bes2600_cdev.probe_timeout_work, (HZ * 8) / 10);
+	schedule_delayed_work(&bes2600_cdev.probe_timeout_work, 3 * HZ);
 }
 
 void bes2600_chrdev_bus_probe_notify(void)
@@ -1178,13 +1199,30 @@ void bes2600_chrdev_bus_probe_notify(void)
 	wake_up(&bes2600_cdev.probe_done_wq);
 }
 
-void bes2600_chrdev_wifi_update_wakeup_reason(u32 val)
+#if defined(CONFIG_BES2600_WLAN_SDIO) || defined(CONFIG_BES2600_WLAN_SPI)
+void bes2600_chrdev_wifi_update_wakeup_reason(u16 reason, u16 port)
 {
 	spin_lock(&bes2600_cdev.status_lock);
-	bes2600_cdev.wakeup_state = val;
+	bes2600_cdev.wakeup_state = reason;
+	bes2600_cdev.src_port = port;
 	spin_unlock(&bes2600_cdev.status_lock);
 }
 
+void bes2600_chrdev_wakeup_by_event_set(enum wakeup_event wakeup_event)
+{
+	spin_lock(&bes2600_cdev.status_lock);
+	bes2600_cdev.wakeup_by_event = wakeup_event;
+	spin_unlock(&bes2600_cdev.status_lock);
+	if (wakeup_event == WAKEUP_EVENT_NONE)
+		wake_up(&bes2600_cdev.wakeup_reason_wq);
+}
+
+int bes2600_chrdev_wakeup_by_event_get(void)
+{
+	return bes2600_cdev.wakeup_by_event;
+}
+#endif
+
 int bes2600_chrdev_init(struct sbus_ops *ops)
 {
 	int ret = 0;
@@ -1234,6 +1272,8 @@ int bes2600_chrdev_init(struct sbus_ops *ops)
 	init_waitqueue_head(&bes2600_cdev.probe_done_wq);
 	INIT_WORK(&bes2600_cdev.wifi_force_close_work, bes2600_chrdev_wifi_force_close_work);
 	INIT_DELAYED_WORK(&bes2600_cdev.probe_timeout_work, bes2600_probe_timeout_work);
+	init_waitqueue_head(&bes2600_cdev.wakeup_reason_wq);
+	bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_NONE);
 #ifdef CONFIG_BES2600_WIFI_BOOT_ON
 	bes2600_cdev.wifi_opened = true;
 #else
@@ -1252,6 +1292,7 @@ int bes2600_chrdev_init(struct sbus_ops *ops)
 	bes2600_cdev.bus_error = false;
 	bes2600_cdev.halt_dev = false;
 	bes2600_cdev.read_flag = BES_CDEV_READ_NUM_MAX;
+	bes2600_cdev.wakeup_by_event = false;
 	bes2600_info(BES2600_DBG_CHARDEV, "%s done\n", __func__);
 
 	return 0;
diff --git a/drivers/staging/bes2600/bes_chardev.h b/drivers/staging/bes2600/bes_chardev.h
index 8c7257c087a4..5c2519879135 100644
--- a/drivers/staging/bes2600/bes_chardev.h
+++ b/drivers/staging/bes2600/bes_chardev.h
@@ -16,8 +16,10 @@
 #define BES2600_FW_TYPE_BT		2
 #define BES2600_FW_TYPE_MAX_NUM     3
 
-#define DPD_BIN_SIZE            0x3AF8
+#define DPD_VERSION_OFFSET      0x3AF4
+#define DPD_BIN_SIZE            0x3B14
 #define DPD_BIN_FILE_SIZE       0x4000
+#define DPD_CUR_VERSION         7
 
 enum pend_read_op {
 	BES_CDEV_READ_WAKEUP_STATE = 0,
@@ -26,6 +28,25 @@ enum pend_read_op {
 	BES_CDEV_READ_NUM_MAX,
 };
 
+enum wifi_wakeup_reason_code {
+	WAKEUP_REASON_WIFI_DEAUTH_DISASSOC = 0x1000,
+	WAKEUP_REASON_WIFI_BSSLOST,
+	/* add new here */
+};
+
+enum bt_wakeup_reason_code {
+	WAKEUP_REASON_BT_PLAY = 0x0100,
+	/* add new here */
+};
+
+enum wakeup_event {
+	WAKEUP_EVENT_NONE = 0,
+	WAKEUP_EVENT_SETTING,
+	WAKEUP_EVENT_WSME,
+	WAKEUP_EVENT_PEER_DETACH,
+	/* add new here */
+};
+
 /* dpd management */
 u8* bes2600_chrdev_get_dpd_buffer(u32 size);
 int bes2600_chrdev_update_dpd_data(void);
@@ -54,9 +75,17 @@ bool bes2600_chrdev_is_bus_error(void);
 void bes2600_chrdev_start_bus_probe(void);
 void bes2600_chrdev_bus_probe_notify(void);
 
+#if defined(CONFIG_BES2600_WLAN_SDIO) || defined(CONFIG_BES2600_WLAN_SPI)
 /* set wifi wakeup state */
-void bes2600_chrdev_wifi_update_wakeup_reason(u32 val);
-
+void bes2600_chrdev_wifi_update_wakeup_reason(u16 reason, u16 port);
+void bes2600_chrdev_wakeup_by_event_set(enum wakeup_event wakeup_event);
+int bes2600_chrdev_wakeup_by_event_get(void);
+#else
+/* set wifi wakeup state */
+static inline void bes2600_chrdev_wifi_update_wakeup_reason(u16 reason, u16 port) { }
+static inline void bes2600_chrdev_wakeup_by_event_set(enum wakeup_event wakeup_event) { }
+static inline int bes2600_chrdev_wakeup_by_event_get(void) { return 0; }
+#endif
 /* init and deinit module */
 int bes2600_chrdev_init(struct sbus_ops *ops);
 void bes2600_chrdev_free(void);
diff --git a/drivers/staging/bes2600/bes_fw.c b/drivers/staging/bes2600/bes_fw.c
index 67f361c0431f..b32d514c0ec9 100644
--- a/drivers/staging/bes2600/bes_fw.c
+++ b/drivers/staging/bes2600/bes_fw.c
@@ -1341,7 +1341,13 @@ static int bes_read_dpd_data(struct sbus_ops *ops, struct sbus_priv *priv)
 		goto exit;
 	}
 
-	dpd_data = bes2600_chrdev_get_dpd_buffer(dpd_data_len);
+	/* dpd size check */
+	if (dpd_data_len != DPD_BIN_SIZE) {
+		bes2600_err(BES2600_DBG_DOWNLOAD, "get dpd data size err:%u\n", dpd_data_len);
+		return -1;
+	}
+
+	dpd_data = bes2600_chrdev_get_dpd_buffer(DPD_BIN_FILE_SIZE);
 	if (!dpd_data) {
 		ret = -ENOMEM;
 		goto exit;
diff --git a/drivers/staging/bes2600/bes_nl80211_testmode_msg.h b/drivers/staging/bes2600/bes_nl80211_testmode_msg.h
index a05f9f862704..b70a0dddc6c3 100644
--- a/drivers/staging/bes2600/bes_nl80211_testmode_msg.h
+++ b/drivers/staging/bes2600/bes_nl80211_testmode_msg.h
@@ -27,6 +27,13 @@ struct bes_event_test_t {
 	int dummy;
 };
 
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+/*example command structure for set select efuse*/
+struct bes_select_calib_t {
+    uint16_t select_efuse_flag;
+};
+#endif
+
 /* vendor to mcu cmd msg reply structure */
 struct vendor_rf_cmd_msg_reply {
 	u32 id;
@@ -65,6 +72,8 @@ enum bes_msg_id {
 	BES_MSG_EPTA_PARM_CONFIG,
 	BES_MSG_GET_KEEP_ALIVE_STREAM,
 	BES_MSG_MCU_CPUUSAGE,
+	BES_MSG_SAVE_CALI_TXT_TO_EFUSE,
+	BES_MSG_SET_SELECT_EFUSE_FLAG,
 	/* Add new IDs here */
 
 	BES_MSG_ID_MAX,
@@ -78,6 +87,7 @@ enum vendor_rf_cmd_type {
 	VENDOR_RF_SAVE_FREQOFFSET_CMD,
 	VENDOR_RF_SAVE_POWERLEVEL_CMD,
 	VENDOR_RF_POWER_CALIB_FINISH,
+	VENDOR_RF_GET_CALI_FROM_EFUSE,
 	/* add new here */
 
 	VENDOR_RF_CMD_MAX,
diff --git a/drivers/staging/bes2600/bes_pwr.c b/drivers/staging/bes2600/bes_pwr.c
index 19d7ed26fde8..4da84cf519bc 100644
--- a/drivers/staging/bes2600/bes_pwr.c
+++ b/drivers/staging/bes2600/bes_pwr.c
@@ -436,8 +436,8 @@ static void bes2600_pwr_delete_all_cb(struct bes2600_common *hw_priv)
 
 	/* delete all cb in exit_cb_list */
 	list_for_each_entry_safe(item1, temp1, &hw_priv->bes_power.exit_cb_list, link) {
-		list_del(&item->link);
-		kfree(item);
+		list_del(&item1->link);
+		kfree(item1);
 	}
 
 	mutex_unlock(&hw_priv->bes_power.pwr_cb_mutex);
@@ -487,13 +487,14 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv)
 
 		if (priv->join_status == BES2600_JOIN_STATUS_STA &&
 		    priv->bss_params.aid &&
-		    priv->setbssparams_done &&
-		    priv->filter4.enable) {
+		    priv->setbssparams_done) {
 			/* enable arp filter */
-			bes2600_dbg(BES2600_DBG_PWR, "%s, arp filter, enable:%d addr:%s\n",
-				__func__, priv->filter4.enable, bes2600_get_mac_str(ip_str, priv->filter4.ipv4Address[0]));
-			ret = wsm_set_arp_ipv4_filter(hw_priv, &priv->filter4, priv->if_id);
-			bes2600_err_with_cond(ret, BES2600_DBG_PWR, "%s, set arp filter failed\n", __func__);
+			if (priv->filter4.enable) {
+				bes2600_dbg(BES2600_DBG_PWR, "%s, arp filter, enable:%d addr:%s\n",
+					__func__, priv->filter4.enable, bes2600_get_mac_str(ip_str, priv->filter4.ipv4Address[0]));
+				ret = wsm_set_arp_ipv4_filter(hw_priv, &priv->filter4, priv->if_id);
+				bes2600_err_with_cond(ret, BES2600_DBG_PWR, "%s, set arp filter failed\n", __func__);
+			}
 
 			/* skip beacon receive if applications don't have muticast service */
 			if(priv->join_dtim_period && !priv->has_multicast_subscription) {
@@ -501,14 +502,15 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv)
 				if(priv->join_dtim_period >= CONFIG_BES2600_LISTEN_INTERVAL) {
 					listen_interval = priv->join_dtim_period;
 				} else {
-					listen_interval = CONFIG_BES2600_LISTEN_INTERVAL / priv->join_dtim_period;
+					listen_interval = CONFIG_BES2600_LISTEN_INTERVAL / priv->join_dtim_period * priv->join_dtim_period;
 				}
 				ret = wsm_set_beacon_wakeup_period(hw_priv, 1, listen_interval, priv->if_id);
 				bes2600_err_with_cond(ret, BES2600_DBG_PWR, "%s, set wakeup period failed\n", __func__);
 			}
 
 			/* Set Enable Broadcast Address Filter */
-			priv->broadcast_filter.action_mode = WSM_FILTER_ACTION_FILTER_OUT;
+			priv->broadcast_filter.action_mode = priv->filter4.enable ? 
+						WSM_FILTER_ACTION_FILTER_OUT : WSM_FILTER_ACTION_IGNORE;
 			if (priv->join_status == BES2600_JOIN_STATUS_AP)
 				priv->broadcast_filter.address_mode = WSM_FILTER_ADDR_MODE_A3;
 			ret = bes2600_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter);
@@ -587,15 +589,16 @@ static int bes2600_pwr_exit_lp_mode(struct bes2600_common *hw_priv)
 
 		if (priv->join_status == BES2600_JOIN_STATUS_STA &&
 		    priv->bss_params.aid &&
-		    priv->setbssparams_done &&
-		    priv->filter4.enable) {
-			/* enable arp filter */
-			filter = priv->filter4;
-			filter.enable = false;
-			bes2600_dbg(BES2600_DBG_PWR, "%s, arp filter, enable:%d addr:%s\n",
-				__func__, filter.enable, bes2600_get_mac_str(ip_str, filter.ipv4Address[0]));
-			ret = wsm_set_arp_ipv4_filter(hw_priv, &filter, priv->if_id);
-			bes2600_err_with_cond(ret, BES2600_DBG_PWR, "%s, set arp filter failed\n", __func__);
+		    priv->setbssparams_done) {
+			/* disable arp filter */
+			if (priv->filter4.enable) {
+				filter = priv->filter4;
+				filter.enable = false;
+				bes2600_dbg(BES2600_DBG_PWR, "%s, arp filter, enable:%d addr:%s\n",
+					__func__, filter.enable, bes2600_get_mac_str(ip_str, filter.ipv4Address[0]));
+				ret = wsm_set_arp_ipv4_filter(hw_priv, &filter, priv->if_id);
+				bes2600_err_with_cond(ret, BES2600_DBG_PWR, "%s, set arp filter failed\n", __func__);
+			}
 
 			/* set wakeup perioid */
 			wsm_set_beacon_wakeup_period(hw_priv, priv->join_dtim_period, 0, priv->if_id);
@@ -1404,3 +1407,28 @@ int bes2600_pwr_busy_event_dump(struct bes2600_common *hw_priv, char *buffer, u3
 
 	return 0;
 }
+
+int bes2600_pwr_busy_event_record(struct bes2600_common *hw_priv, char *buffer, u32 buf_len)
+{
+	unsigned long max_timeout = 0;
+	struct bes2600_pwr_event_t *item = NULL;
+	unsigned long flags;
+
+	if(!buffer) {
+		return -1;
+	}
+
+	spin_lock_irqsave(&hw_priv->bes_power.pwr_lock, flags);
+	bes2600_update_power_delay_events(&hw_priv->bes_power, &max_timeout);
+	if(!list_empty(&hw_priv->bes_power.pending_event_list)) {
+		list_for_each_entry(item, &hw_priv->bes_power.pending_event_list, link) {
+					snprintf(buffer, buf_len, "Event: %9s. Flag: %s. timeout(ticks): %lu.\n",
+					bes2600_get_pwr_busy_event_name(item),
+					BES_PWR_IS_CONSTANT_EVENT(item->event) ? "C" : "D",
+					bes2600_get_pwr_busy_event_timeout(item));
+		}
+	}
+	spin_unlock_irqrestore(&hw_priv->bes_power.pwr_lock, flags);
+
+	return 0;
+}
\ No newline at end of file
diff --git a/drivers/staging/bes2600/bes_pwr.h b/drivers/staging/bes2600/bes_pwr.h
index 2c27f4293a55..1ba866c25c42 100644
--- a/drivers/staging/bes2600/bes_pwr.h
+++ b/drivers/staging/bes2600/bes_pwr.h
@@ -135,6 +135,7 @@ void bes2600_pwr_mcu_sleep_directly(struct bes2600_common *hw_priv);
 void bes2600_pwr_mark_ap_lp_bad(struct bes2600_common *hw_priv);
 void bes2600_pwr_clear_ap_lp_bad_mark(struct bes2600_common *hw_priv);
 int bes2600_pwr_busy_event_dump(struct bes2600_common *hw_priv, char *buffer, u32 buf_len);
+int bes2600_pwr_busy_event_record(struct bes2600_common *hw_priv, char *buffer, u32 buf_len);
 #else
 static inline void bes2600_pwr_init(struct bes2600_common *hw_priv) { }
 static inline void bes2600_pwr_exit(struct bes2600_common *hw_priv) { }
@@ -162,6 +163,7 @@ static inline void bes2600_pwr_mcu_sleep_directly(struct bes2600_common *hw_priv
 static inline void bes2600_pwr_mark_ap_lp_bad(struct bes2600_common *hw_priv) { }
 static inline void bes2600_pwr_clear_ap_lp_bad_mark(struct bes2600_common *hw_priv) { }
 static inline int bes2600_pwr_busy_event_dump(struct bes2600_common *hw_priv, char *buffer, u32 buf_len) { return 0; }
+static inline int bes2600_pwr_busy_event_record(struct bes2600_common *hw_priv, char *buffer, u32 buf_len) { return 0; }
 #endif
 
 #endif
\ No newline at end of file
diff --git a/drivers/staging/bes2600/bh.c b/drivers/staging/bes2600/bh.c
index fed5101d42c6..082eaa8e200f 100644
--- a/drivers/staging/bes2600/bh.c
+++ b/drivers/staging/bes2600/bh.c
@@ -955,6 +955,7 @@ static void bes2600_bh_parse_wakeup_event(struct bes2600_common *hw_priv, struct
 {
 	struct wsm_hdr *wsm = (struct wsm_hdr *)skb->data;
 	u16 wsm_id = __le16_to_cpu(wsm->id) & 0xFFF;
+	bool set_wakeup_reason_later = false;
 
 	if (hw_priv->sbus_ops->wakeup_source &&
 	    hw_priv->sbus_ops->wakeup_source(hw_priv->sbus_priv)) {
@@ -966,15 +967,29 @@ static void bes2600_bh_parse_wakeup_event(struct bes2600_common *hw_priv, struct
 			if (ieee80211_is_mgmt(fctl)) {
 				u16 type = (fctl & cpu_to_le16(IEEE80211_FCTL_FTYPE)) >> 2;
 				u16 stype = (fctl & cpu_to_le16(IEEE80211_FCTL_STYPE)) >> 4;
+				if (ieee80211_is_deauth(fctl) || ieee80211_is_disassoc(fctl)) {
+					bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_PEER_DETACH);
+					set_wakeup_reason_later = true;
+					bes2600_info(BES2600_DBG_BH, "Host was waked by mgmt(deauth or disassoc)\n");
+				}
 				bes2600_info(BES2600_DBG_BH, "Host was waked by mgmt, type:%d(%d)\n", type, stype);
-			} else if(ieee80211_is_data(fctl)){
+			} else if (ieee80211_is_data(fctl)){
 				bes2600_bh_parse_data_pkt(hw_priv, skb);
 			} else {
 				bes2600_info(BES2600_DBG_BH, "Host was waked by unexpected frame, fctl:0x%04x\n", fctl);
 			}
+		} else if (wsm_id == 0x0C31) {
+			bes2600_info(BES2600_DBG_BH, "Host was waked by BT:0x%04x.\n", wsm_id);
+			bes2600_chrdev_wifi_update_wakeup_reason(WAKEUP_REASON_BT_PLAY, 0);
 		} else {
+			if (wsm_id == 0x0805) {
+				bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_WSME);
+				set_wakeup_reason_later = true;
+			}
 			bes2600_info(BES2600_DBG_BH, "Host was waked by event:0x%04x.\n", wsm_id);
 		}
+		if (!set_wakeup_reason_later)
+			bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_NONE);
 	}
 }
 
@@ -1451,7 +1466,8 @@ static int bes2600_bh(void *arg)
 
 		if (!hw_priv->hw_bufs_used &&
 		    !bes2600_pwr_device_is_idle(hw_priv) &&
-		    !atomic_read(&hw_priv->recent_scan)) {
+		    !atomic_read(&hw_priv->recent_scan) &&
+			bes2600_chrdev_is_signal_mode()) {
 			status = 5 * HZ;
 		} else if (hw_priv->hw_bufs_used) {
 			/* Interrupt loss detection */
diff --git a/drivers/staging/bes2600/debug.c b/drivers/staging/bes2600/debug.c
index c5bba0789a3c..0e51f53f3af2 100644
--- a/drivers/staging/bes2600/debug.c
+++ b/drivers/staging/bes2600/debug.c
@@ -82,7 +82,11 @@ static void bes2600_queue_status_show(struct seq_file *seq,
 	seq_printf(seq, "  pending:  %ld\n", (long)q->num_pending);
 	seq_printf(seq, "  sent:     %ld\n", (long)q->num_sent);
 	seq_printf(seq, "  locked:   %s\n", q->tx_locked_cnt ? "yes" : "no");
-	seq_printf(seq, "  overfull: %s\n", q->overfull ? "yes" : "no");
+	seq_printf(seq, "  vif_overfull[0]: %s\n", q->vif_overfull[0] ? "yes" : "no");
+	seq_printf(seq, "  vif_overfull[1]: %s\n", q->vif_overfull[1] ? "yes" : "no");
+#ifdef P2P_MULTIVIF
+	seq_printf(seq, "  vif_overfull[2]: %s\n", q->vif_overfull[2] ? "yes" : "no");
+#endif
 	seq_puts(seq,   "  link map: 0-> ");
 	for (if_id = 0; if_id < CW12XX_MAX_VIFS; if_id++) {
 		for (i = 0; i < q->stats->map_capacity; ++i)
diff --git a/drivers/staging/bes2600/epta_request.c b/drivers/staging/bes2600/epta_request.c
index 44676dcbc6d7..abbd4abc31ae 100644
--- a/drivers/staging/bes2600/epta_request.c
+++ b/drivers/staging/bes2600/epta_request.c
@@ -105,8 +105,8 @@ typedef enum {
 	BWIFI_BT_STATUS_SHUTDOWN          = 0,
 	BWIFI_BT_STATUS_DISCONNECTED      = 1,
 	BWIFI_BT_STATUS_CONNECTING        = 2,
-	BWIFI_BT_STATUS_CONNECTED_SNIFF   = 3,//
-	BWIFI_BT_STATUS_CONNECTED         = 4,//
+	BWIFI_BT_STATUS_CONNECTED_SNIFF   = 3,
+	BWIFI_BT_STATUS_CONNECTED         = 4,
 } BWIFI_BT_STATUS_T;
 
 typedef enum {
@@ -123,23 +123,23 @@ typedef enum {
 } BWIFI_BT_AUDIO_T;
 
 typedef enum {
-	BWIFI_BT_INQ_STOP                 = 0,//
-	BWIFI_BT_INQ_START                = 1,//
+	BWIFI_BT_INQ_STOP                 = 0,
+	BWIFI_BT_INQ_START                = 1,
 } BWIFI_BT_INQ_T;
 
 typedef enum {
-	BWIFI_LE_SCAN_STOP                = 0,//
-	BWIFI_LE_SCAN_START               = 1,//
+	BWIFI_LE_SCAN_STOP                = 0,
+	BWIFI_LE_SCAN_START               = 1,
 } BWIFI_BT_LE_SCAN_T;
 
 typedef enum {
-	BWIFI_LE_ADV_STOP                 = 0,//
-	BWIFI_LE_ADV_START                = 1,//
+	BWIFI_LE_ADV_STOP                 = 0,
+	BWIFI_LE_ADV_START                = 1,
 } BWIFI_BT_LE_ADV_T;
 
 typedef enum {
-	BWIFI_LE_DISCONNECTED             = 0,//
-	BWIFI_LE_CONNECTED                = 1,//
+	BWIFI_LE_DISCONNECTED             = 0,
+	BWIFI_LE_CONNECTED                = 1,
 } BWIFI_BT_LE_STATUS_T;
 
 enum COEX_BT_OPER_T {
@@ -206,8 +206,8 @@ void coex_calc_wifi_scan_time(uint32_t *min_chan, uint32_t *max_chan)
 	uint32_t time = coex_calc_bt_time();
 
 	if (time == 0) {
-		*min_chan = 90;
-		*max_chan = 90;
+		*min_chan = 100;
+		*max_chan = 100;
 	} else if (time < 40000) {
 		*min_chan = 50;
 		*max_chan = 110;
diff --git a/drivers/staging/bes2600/main.c b/drivers/staging/bes2600/main.c
index 675839d7177a..cc33b16a3b5a 100644
--- a/drivers/staging/bes2600/main.c
+++ b/drivers/staging/bes2600/main.c
@@ -46,6 +46,9 @@ MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>");
 MODULE_DESCRIPTION("Softmac BES2600 common code");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("bes2600");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
+#endif
 
 static u8 bes2600_mac_template[ETH_ALEN] = {
 #if (GET_MAC_ADDR_METHOD == 2)||(GET_MAC_ADDR_METHOD == 3)
@@ -199,7 +202,7 @@ static struct ieee80211_supported_band bes2600_band_2ghz = {
 	.n_bitrates = bes2600_g_rates_size,
 	.ht_cap = {
 		.cap = IEEE80211_HT_CAP_GRN_FLD |
-			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
+			(STBC_RX_24G << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
 			IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 			IEEE80211_HT_CAP_SGI_20 |
 			IEEE80211_HT_CAP_SGI_40 |
@@ -223,7 +226,7 @@ static struct ieee80211_supported_band bes2600_band_5ghz = {
 	.n_bitrates = bes2600_a_rates_size,
 	.ht_cap = {
 		.cap = IEEE80211_HT_CAP_GRN_FLD |
-			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
+			(STBC_RX_5G << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
 			IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 			IEEE80211_HT_CAP_SGI_20 |
 			IEEE80211_HT_CAP_SGI_40 |
@@ -320,23 +323,23 @@ static const struct wiphy_wowlan_support bes2600_wowlan_support = {
 #endif
 
 #ifdef CONFIG_BES2600_WAPI_SUPPORT
-static void bes2600_init_wapi_cipher(struct ieee80211_hw *hw)
-{
-	static struct ieee80211_cipher_scheme wapi_cs = {
-		.cipher = WLAN_CIPHER_SUITE_SMS4,
-		.iftype = BIT(NL80211_IFTYPE_STATION),
-		.hdr_len = 18,
-		.pn_len = 16,
-		.pn_off = 2,
-		.key_idx_off = 0,
-		.key_idx_mask = 0x01,
-		.key_idx_shift = 0,
-		.mic_len = 16
-	};
-
-	hw->cipher_schemes = &wapi_cs;
-	hw->n_cipher_schemes = 1;
-}
+// static void bes2600_init_wapi_cipher(struct ieee80211_hw *hw)
+// {
+// 	static struct ieee80211_cipher_scheme wapi_cs = {
+// 		.cipher = WLAN_CIPHER_SUITE_SMS4,
+// 		.iftype = BIT(NL80211_IFTYPE_STATION),
+// 		.hdr_len = 18,
+// 		.pn_len = 16,
+// 		.pn_off = 2,
+// 		.key_idx_off = 0,
+// 		.key_idx_mask = 0x01,
+// 		.key_idx_shift = 0,
+// 		.mic_len = 16
+// 	};
+
+// 	hw->cipher_schemes = &wapi_cs;
+// 	hw->n_cipher_schemes = 1;
+// }
 #endif
 
 static void bes2600_get_base_mac(struct bes2600_common *hw_priv)
@@ -532,7 +535,7 @@ struct ieee80211_hw *bes2600_init_common(size_t hw_priv_data_len)
 #ifdef CONFIG_BES2600_WAPI_SUPPORT
 	hw_priv->last_ins_wapi_usk_id = -1;
 	hw_priv->last_del_wapi_usk_id = -1;
-	bes2600_init_wapi_cipher(hw);
+	// bes2600_init_wapi_cipher(hw);
 #endif
 
 	SET_IEEE80211_PERM_ADDR(hw, hw_priv->addresses[0].addr);
@@ -609,6 +612,11 @@ struct ieee80211_hw *bes2600_init_common(size_t hw_priv_data_len)
 
 	bes2600_tx_loop_init(hw_priv);
 
+#ifdef CONFIG_PM
+	bes2600_suspend_status_set(hw_priv, false);
+	bes2600_pending_unjoin_reset(hw_priv);
+#endif
+
 #ifdef CONFIG_BES2600_TESTMODE
 	hw_priv->test_frame.data = NULL;
 	hw_priv->test_frame.len = 0;
@@ -659,7 +667,9 @@ int bes2600_register_common(struct ieee80211_hw *dev)
 #endif /* CONFIG_BES2600_LEDS */
 
 	bes2600_debug_init_common(hw_priv);
-
+#ifdef CONFIG_PM
+	bes2600_register_pm_notifier(hw_priv);
+#endif /* CONFIG_PM */
 	bes2600_info(BES2600_DBG_INIT, "is registered as '%s'\n",
 			wiphy_name(dev->wiphy));
 	return 0;
@@ -697,7 +707,9 @@ void bes2600_unregister_common(struct ieee80211_hw *dev)
 	bes2600_unregister_bh(hw_priv);
 
 	bes2600_debug_release_common(hw_priv);
-
+#ifdef CONFIG_PM
+	bes2600_unregister_pm_notifier(hw_priv);
+#endif /* CONFIG_PM */
 #ifdef CONFIG_BES2600_LEDS
 	bes2600_unregister_leds(hw_priv);
 #endif /* CONFIG_BES2600_LEDS */
@@ -1014,7 +1026,7 @@ int access_file(char *path, char *buffer, int size, int isRead)
 #ifdef CONFIG_BES2600_WLAN_BES
 int bes2600_wifi_start(struct bes2600_common *hw_priv)
 {
-	int ret, if_id;
+	int ret = 0, if_id;
 #ifndef CONFIG_BES2600_WLAN_USB
 	if(hw_priv->sbus_ops->gpio_wake) {
 		hw_priv->sbus_ops->gpio_wake(hw_priv->sbus_priv, GPIO_WAKE_FLAG_WIFI_ON);
diff --git a/drivers/staging/bes2600/pm.c b/drivers/staging/bes2600/pm.c
index fbd6a8867332..d3213339e11c 100644
--- a/drivers/staging/bes2600/pm.c
+++ b/drivers/staging/bes2600/pm.c
@@ -11,6 +11,7 @@
 
 #include <linux/platform_device.h>
 #include <linux/if_ether.h>
+#include <linux/suspend.h>
 #include "bes2600.h"
 #include "pm.h"
 #include "sta.h"
@@ -30,9 +31,9 @@ struct bes2600_udp_port_filter {
 
 struct bes2600_ether_type_filter {
 	struct wsm_ether_type_filter_hdr hdr;
-	struct wsm_ether_type_filter ip;
 	struct wsm_ether_type_filter pae;
 	struct wsm_ether_type_filter wapi;
+	struct wsm_ether_type_filter append;
 } __packed;
 
 static struct bes2600_udp_port_filter bes2600_udp_port_filter_on = {
@@ -65,12 +66,10 @@ static struct wsm_udp_port_filter_hdr bes2600_udp_port_filter_off = {
 #define ETH_P_WAPI     0x88B4
 #endif
 
+#define ETH_P_UNKNOWN 0xFFFF
 static struct bes2600_ether_type_filter bes2600_ether_type_filter_on = {
 	.hdr.nrFilters = 3,
-	.ip = {
-		.filterAction = WSM_FILTER_ACTION_FILTER_OUT,
-		.etherType = __cpu_to_le16(ETH_P_IPV6),
-	},
+	.hdr.extFlags = WSM_ETH_FILTER_EXT_DISABLE_IPV6_MATCH, // patch for disable lmac SUSPEND_MODE_IPV6_FIX
 	.pae = {
 		.filterAction = WSM_FILTER_ACTION_FILTER_IN,
 		.etherType = __cpu_to_le16(ETH_P_PAE),
@@ -79,6 +78,11 @@ static struct bes2600_ether_type_filter bes2600_ether_type_filter_on = {
 		.filterAction = WSM_FILTER_ACTION_FILTER_IN,
 		.etherType = __cpu_to_le16(ETH_P_WAPI),
 	},
+	// add for lmac ether filter strategy: If every filtermode is FilterIN, discard all the frame which is mismatched
+	.append = {
+		.filterAction = WSM_FILTER_ACTION_FILTER_OUT,
+		.etherType = __cpu_to_le16(ETH_P_UNKNOWN),
+	},
 	/* Please add other known ether types to be filtered out here and
 	 * update nrFilters field in the header.
 	 * Up to 4 filters are allowed. */
@@ -88,6 +92,25 @@ static struct wsm_ether_type_filter_hdr bes2600_ether_type_filter_off = {
 	.nrFilters = 0,
 };
 
+#ifdef IPV6_FILTERING
+static struct wsm_ipv6_filter bes2600_ipv6_filter_on = {
+	.hdr.numfilter = 1,
+	.hdr.action_mode = WSM_FILTER_ACTION_FILTER_IN,
+	.ipv6filter[0] = {
+		.filter_mode = WSM_FILTER_ACTION_FILTER_IN,
+		.address_mode = WSM_IP_DATA_FRAME_ADDRMODE_DEST,
+		/* a random ipvd addr, in order to filter all ipv6 packet */
+		.ipv6 = {0x01, 0x28, 0x35, 0xde, 0xbf, 0x34, 0x9d, 0x8a,
+				 0x47, 0x62, 0x85, 0x69, 0x7e, 0x8c, 0x29, 0x38},
+	}
+};
+
+static struct wsm_ipv6_filter bes2600_ipv6_filter_off = {
+	.hdr.numfilter = 0,
+	.hdr.action_mode = WSM_FILTER_ACTION_IGNORE,
+};
+#endif
+
 static int __bes2600_wow_suspend(struct bes2600_vif *priv,
 				struct cfg80211_wowlan *wowlan);
 static int __bes2600_wow_resume(struct bes2600_vif *priv);
@@ -102,6 +125,88 @@ struct bes2600_suspend_state {
 	unsigned long link_id_gc;
 };
 
+void bes2600_suspend_status_set(struct bes2600_common *hw_priv, bool status)
+{
+	hw_priv->suspend_in_progress = status;
+}
+
+bool bes2600_suspend_status_get(struct bes2600_common *hw_priv)
+{
+	return hw_priv->suspend_in_progress;
+}
+
+void bes2600_pending_unjoin_reset(struct bes2600_common *hw_priv)
+{
+	hw_priv->unjoin_if_id_slots = 0x00;
+}
+
+void bes2600_pending_unjoin_set(struct bes2600_common *hw_priv, int if_id)
+{
+	if(if_id > 1)
+		bes2600_err(BES2600_DBG_PM, "unexpected if_id: %d\n", if_id);
+	else
+		hw_priv->unjoin_if_id_slots |= (1 << if_id);
+}
+
+bool bes2600_pending_unjoin_get(struct bes2600_common *hw_priv, int if_id)
+{
+	if(if_id > 1) {
+		bes2600_err(BES2600_DBG_PM, "unexpected if_id: %d\n", if_id);
+		return false;
+	} else
+		return hw_priv->unjoin_if_id_slots & (1 << if_id);
+}
+
+static int bes2600_pm_notifier(struct notifier_block *notifier,
+			       unsigned long pm_event,
+			       void *unused)
+{
+	int if_id;
+	struct bes2600_vif *priv;
+	struct bes2600_common *hw_priv = container_of(notifier,
+						    struct bes2600_common,
+						    pm_notify);
+
+	switch (pm_event) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		bes2600_suspend_status_set(hw_priv, true);
+		break;
+
+	case PM_POST_RESTORE:
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		bes2600_suspend_status_set(hw_priv, false);
+		if(hw_priv->unjoin_if_id_slots) {
+			for(if_id = 0; if_id < 2; if_id++) {
+				if(bes2600_pending_unjoin_get(hw_priv, if_id)) {
+					priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, if_id);
+					ieee80211_connection_loss(priv->vif);
+				}
+			}
+			bes2600_pending_unjoin_reset(hw_priv);
+		}
+		break;
+
+	case PM_RESTORE_PREPARE:
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+void bes2600_register_pm_notifier(struct bes2600_common *hw_priv)
+{
+	hw_priv->pm_notify.notifier_call = bes2600_pm_notifier;
+	register_pm_notifier(&hw_priv->pm_notify);
+}
+
+void bes2600_unregister_pm_notifier(struct bes2600_common *hw_priv)
+{
+	unregister_pm_notifier(&hw_priv->pm_notify);
+}
+
 static long bes2600_suspend_work(struct delayed_work *work)
 {
 	int ret = cancel_delayed_work(work);
@@ -143,13 +248,14 @@ int bes2600_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 	struct bes2600_vif *priv;
 	int i, ret = 0;
 	unsigned long begin, end, diff;
+	char *busy_event_buffer = NULL;
 
 	bes2600_info(BES2600_DBG_PM, "bes2600_wow_suspend enter\n");
 
 	WARN_ON(!atomic_read(&hw_priv->num_vifs));
 
 	/* reset wakeup reason to default */
-	bes2600_chrdev_wifi_update_wakeup_reason(0);
+	bes2600_chrdev_wifi_update_wakeup_reason(0, 0);
 
 #ifdef ROAM_OFFLOAD
 	bes2600_for_each_vif(hw_priv, priv, i) {
@@ -198,6 +304,18 @@ int bes2600_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 		if (wait_event_timeout(hw_priv->bes_power.dev_lp_wq,
 			bes2600_pwr_device_is_idle(hw_priv), HZ * 5) <= 0) {
 			bes2600_err(BES2600_DBG_PM, "wait device idle timeout\n");
+			busy_event_buffer = kmalloc(4096, GFP_KERNEL);
+
+			if(!busy_event_buffer)
+				goto revert2;
+
+			if(bes2600_pwr_busy_event_record(hw_priv, busy_event_buffer, 4096) == 0) {
+				bes2600_info(BES2600_DBG_PM, "%s\n", busy_event_buffer);
+			} else {
+				bes2600_err(BES2600_DBG_PM, "busy event show failed\n");
+			}
+
+			kfree(busy_event_buffer);
 			goto revert2;
 		}
 	}
@@ -287,10 +405,10 @@ static int __bes2600_wow_suspend(struct bes2600_vif *priv,
 	int ret;
 
 #ifdef MCAST_FWDING
-        struct wsm_forwarding_offload fwdoffload = {
-                .fwenable = 0x1,
-                .flags = 0x1,
-        };
+	struct wsm_forwarding_offload fwdoffload = {
+		.fwenable = 0x1,
+		.flags = 0x1,
+	};
 #endif
 
 	/* Do not suspend when join work is scheduled */
@@ -300,6 +418,11 @@ static int __bes2600_wow_suspend(struct bes2600_vif *priv,
 	bes2600_set_ehter_and_udp_filter(hw_priv, &bes2600_ether_type_filter_on.hdr,
 				&bes2600_udp_port_filter_on.hdr, priv->if_id);
 
+	/* Set ipv6 filer */
+#ifdef IPV6_FILTERING
+	wsm_set_ipv6_filter(hw_priv, &bes2600_ipv6_filter_on.hdr, priv->if_id);
+#endif
+
   	if (priv->join_status == BES2600_JOIN_STATUS_AP)
 		WARN_ON(wsm_set_keepalive_filter(priv, true));
 
@@ -307,7 +430,7 @@ static int __bes2600_wow_suspend(struct bes2600_vif *priv,
 	if (priv->multicast_filter.numOfAddresses) {
 		priv->multicast_filter.enable = __cpu_to_le32(2);
 		wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id);
-       }
+	}
 
 #ifdef MCAST_FWDING
 	if (priv->join_status == BES2600_JOIN_STATUS_AP)
@@ -362,7 +485,7 @@ revert2:
 	if (priv->multicast_filter.numOfAddresses) {
 		priv->multicast_filter.enable = __cpu_to_le32(1);
 		wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id);
-       }
+	}
 
 
 #ifdef MCAST_FWDING
@@ -422,10 +545,10 @@ static int __bes2600_wow_resume(struct bes2600_vif *priv)
 	struct bes2600_suspend_state *state;
 
 #ifdef MCAST_FWDING
-        struct wsm_forwarding_offload fwdoffload = {
-                .fwenable = 0x1,
-                .flags = 0x0,
-        };
+	struct wsm_forwarding_offload fwdoffload = {
+		.fwenable = 0x1,
+		.flags = 0x0,
+	};
 #endif
 	state = pm_state_vif->suspend_state;
 	pm_state_vif->suspend_state = NULL;
@@ -443,7 +566,7 @@ static int __bes2600_wow_resume(struct bes2600_vif *priv)
 	if (priv->multicast_filter.numOfAddresses) {
 		priv->multicast_filter.enable = __cpu_to_le32(1);
 		wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id);
-       }
+	}
 
 #ifdef MCAST_FWDING
 	if (priv->join_status == BES2600_JOIN_STATUS_AP)
@@ -467,8 +590,14 @@ static int __bes2600_wow_resume(struct bes2600_vif *priv)
 	/* Remove ethernet frame type filter */
 	wsm_set_ether_type_filter(hw_priv, &bes2600_ether_type_filter_off,
 				  priv->if_id);
+
+	/* Remove ipv6 filer */
+#ifdef IPV6_FILTERING
+	wsm_set_ipv6_filter(hw_priv, &bes2600_ipv6_filter_off.hdr, priv->if_id);
+#endif
+
 	/* Free memory */
 	kfree(state);
 
 	return 0;
-}
+}
\ No newline at end of file
diff --git a/drivers/staging/bes2600/pm.h b/drivers/staging/bes2600/pm.h
index dbf887367877..0f6943ecd870 100644
--- a/drivers/staging/bes2600/pm.h
+++ b/drivers/staging/bes2600/pm.h
@@ -21,6 +21,13 @@ struct bes2600_pm_state_vif {
 	struct bes2600_suspend_state *suspend_state;
 };
 
+void bes2600_suspend_status_set(struct bes2600_common *hw_priv, bool status);
+bool bes2600_suspend_status_get(struct bes2600_common *hw_priv);
+void bes2600_pending_unjoin_reset(struct bes2600_common *hw_priv);
+void bes2600_pending_unjoin_set(struct bes2600_common *hw_priv, int if_id);
+bool bes2600_pending_unjoin_get(struct bes2600_common *hw_priv, int if_id);
+void bes2600_register_pm_notifier(struct bes2600_common *hw_priv);
+void bes2600_unregister_pm_notifier(struct bes2600_common *hw_priv);
 int bes2600_can_suspend(struct bes2600_common *priv);
 int bes2600_wow_suspend(struct ieee80211_hw *hw,
 		       struct cfg80211_wowlan *wowlan);
diff --git a/drivers/staging/bes2600/queue.c b/drivers/staging/bes2600/queue.c
index de8edb2a3433..868ad23e95a3 100644
--- a/drivers/staging/bes2600/queue.c
+++ b/drivers/staging/bes2600/queue.c
@@ -129,6 +129,34 @@ static void bes2600_queue_register_post_gc(struct list_head *gc_list,
 	list_add_tail(&gc_item->head, gc_list);
 }
 
+static void bes2600_queue_pending_record(struct list_head *pending_record_list,
+				     struct bes2600_queue_item *pending_item)
+{
+	struct bes2600_queue_item *record_item;
+
+	record_item = kmalloc(sizeof(struct bes2600_queue_item),GFP_ATOMIC);
+	BUG_ON(!record_item);
+	memcpy(record_item, pending_item, sizeof(struct bes2600_queue_item));
+	record_item->skb = skb_clone(pending_item->skb, GFP_ATOMIC);
+	list_add_tail(&record_item->head, pending_record_list);
+}
+
+static void bes2600_queue_vif_wake_subqueue(struct bes2600_queue_stats *stats,
+				     struct bes2600_queue *queue, int vif)
+{
+	struct bes2600_vif *priv;
+	struct wireless_dev *wdev;
+
+	priv = __cw12xx_hwpriv_to_vifpriv(stats->hw_priv, vif);
+	if (priv && unlikely(queue->vif_overfull[vif])) {
+		wdev = ieee80211_vif_to_wdev(priv->vif);
+		if (wdev->netdev && !ieee80211_queue_stopped(stats->hw_priv->hw, queue->queue_id)) {
+			queue->vif_overfull[vif] = false;
+			netif_wake_subqueue(wdev->netdev, queue->queue_id);
+		}
+	}
+}
+
 static void __bes2600_queue_gc(struct bes2600_queue *queue,
 			      struct list_head *head,
 			      bool unlock)
@@ -136,6 +164,9 @@ static void __bes2600_queue_gc(struct bes2600_queue *queue,
 	struct bes2600_queue_stats *stats = queue->stats;
 	struct bes2600_queue_item *item = NULL;
 	struct bes2600_vif *priv;
+	struct wireless_dev *wdev;
+	int throttle;
+	int vif_i;
 	int if_id;
 	bool wakeup_stats = false;
 
@@ -169,17 +200,28 @@ static void __bes2600_queue_gc(struct bes2600_queue *queue,
 	if (wakeup_stats)
 		wake_up(&stats->wait_link_id_empty);
 
-	if (queue->overfull) {
-		if (queue->num_queued <= ((stats->hw_priv->vif0_throttle +
-						stats->hw_priv->vif1_throttle + 2)/2)) {
-			queue->overfull = false;
-			if (unlock)
-				__bes2600_queue_unlock(queue);
-		} else if (item) {
-			unsigned long tmo = item->queue_timestamp + queue->ttl;
-			mod_timer(&queue->gc, tmo);
-			bes2600_pwr_set_busy_event_with_timeout_async(stats->hw_priv,
-				BES_PWR_LOCK_ON_QUEUE_GC, jiffies_to_msecs(tmo - jiffies));
+	for (vif_i = 0; vif_i < CW12XX_MAX_VIFS; vif_i++) {
+		if (vif_i == 0)
+			throttle = stats->hw_priv->vif0_throttle - (num_present_cpus() - 1);
+		else if (vif_i == 1)
+			throttle = stats->hw_priv->vif1_throttle - (num_present_cpus() - 1);
+		else
+			throttle = 2;
+
+		priv = __cw12xx_hwpriv_to_vifpriv(stats->hw_priv, vif_i);
+
+		if (priv && queue->vif_overfull[vif_i]) {
+			wdev = ieee80211_vif_to_wdev(priv->vif);
+			if (wdev->netdev && queue->num_queued_vif[vif_i] < (throttle + 1)/2 && unlock &&
+			    !ieee80211_queue_stopped(stats->hw_priv->hw, queue->queue_id)) {
+				queue->vif_overfull[vif_i] = false;
+				netif_wake_subqueue(wdev->netdev, queue->queue_id);
+			} else if (item) {
+				unsigned long tmo = item->queue_timestamp + queue->ttl;
+				mod_timer(&queue->gc, tmo);
+				bes2600_pwr_set_busy_event_with_timeout_async(stats->hw_priv,
+					BES_PWR_LOCK_ON_QUEUE_GC, jiffies_to_msecs(tmo - jiffies));
+			}
 		}
 	}
 }
@@ -282,14 +324,24 @@ int bes2600_queue_init(struct bes2600_queue *queue,
 /* TODO:COMBO: Flush only a particular interface specific parts */
 int bes2600_queue_clear(struct bes2600_queue *queue, int if_id)
 {
-	int i, cnt, iter;
+	int i, cnt, iter, vif_i;
 	struct bes2600_queue_stats *stats = queue->stats;
 	LIST_HEAD(gc_list);
+	struct bes2600_queue_item *pending_item = NULL,  *temp_pending_item = NULL;
 
 	cnt = 0;
 	spin_lock_bh(&queue->lock);
 	queue->generation++;
 	queue->generation &= 0xf;
+
+	spin_lock(&stats->hw_priv->tx_loop.pending_record_lock);
+	if (!list_empty(&queue->pending)) {
+		list_for_each_entry_safe(pending_item, temp_pending_item, &queue->pending, head) {
+			bes2600_queue_pending_record(&stats->hw_priv->tx_loop.pending_record_list, pending_item);
+		}
+	}
+	spin_unlock(&stats->hw_priv->tx_loop.pending_record_lock);
+
 	list_splice_tail_init(&queue->queue, &queue->pending);
 	while (!list_empty(&queue->pending)) {
 		struct bes2600_queue_item *item = list_first_entry(
@@ -334,9 +386,12 @@ int bes2600_queue_clear(struct bes2600_queue *queue, int if_id)
 		}
 	}
 	spin_unlock_bh(&stats->lock);
-	if (unlikely(queue->overfull)) {
-		queue->overfull = false;
-		__bes2600_queue_unlock(queue);
+	if (CW12XX_ALL_IFS == if_id) {
+		for (vif_i = 0; vif_i < CW12XX_MAX_VIFS; vif_i++) {
+			bes2600_queue_vif_wake_subqueue(stats, queue, vif_i);
+		}
+	} else {
+		bes2600_queue_vif_wake_subqueue(stats, queue, if_id);
 	}
 	spin_unlock_bh(&queue->lock);
 	wake_up(&stats->wait_link_id_empty);
@@ -403,8 +458,15 @@ int bes2600_queue_put(struct bes2600_queue *queue,
 {
 	int ret = 0;
 #ifdef CONFIG_BES2600_TESTMODE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+	struct timespec64 tmval;
+#else
 	struct timeval tmval;
+#endif
 #endif /*CONFIG_BES2600_TESTMODE*/
+	struct bes2600_vif *priv;
+	struct wireless_dev *wdev;
+	int throttle = 0;
 
 	LIST_HEAD(gc_list);
 	struct bes2600_queue_stats *stats = queue->stats;
@@ -436,8 +498,13 @@ int bes2600_queue_put(struct bes2600_queue *queue,
 		}
 #endif
 #ifdef CONFIG_BES2600_TESTMODE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+		ktime_get_real_ts64(&tmval);
+		item->qdelay_timestamp = tmval.tv_nsec / 1000;
+#else
 		do_gettimeofday(&tmval);
 		item->qdelay_timestamp = tmval.tv_usec;
+#endif
 #endif /*CONFIG_BES2600_TESTMODE*/
 
 		++queue->num_queued;
@@ -453,14 +520,24 @@ int bes2600_queue_put(struct bes2600_queue *queue,
 		 * TX may happen in parallel sometimes.
 		 * Leave extra queue slots so we don't overflow.
 		 */
-		if (queue->overfull == false &&
-				queue->num_queued >=
-		((stats->hw_priv->vif0_throttle +
-			stats->hw_priv->vif1_throttle + 2)
-				- (num_present_cpus() - 1))) {
-			queue->overfull = true;
-			__bes2600_queue_lock(queue);
-			mod_timer(&queue->gc, jiffies);
+		if (txpriv->if_id == 0)
+			throttle = stats->hw_priv->vif0_throttle - (num_present_cpus() - 1);
+		else if (txpriv->if_id == 1)
+			throttle = stats->hw_priv->vif1_throttle - (num_present_cpus() - 1);
+		else if (txpriv->if_id == 2)
+			throttle = 2;
+		else
+			bes2600_warn(BES2600_DBG_TXRX, "%s: unexpected if_id = %d\n", __func__, txpriv->if_id);
+
+		priv = __cw12xx_hwpriv_to_vifpriv(stats->hw_priv, txpriv->if_id);
+
+		if (priv && queue->num_queued_vif[txpriv->if_id] >= throttle) {
+			wdev = ieee80211_vif_to_wdev(priv->vif);
+			if (wdev->netdev) {
+				queue->vif_overfull[txpriv->if_id] = true;
+				netif_stop_subqueue(wdev->netdev, queue->queue_id);
+				mod_timer(&queue->gc, jiffies);
+			}
 		}
 	} else {
 		ret = -ENOENT;
@@ -489,7 +566,11 @@ int bes2600_queue_get(struct bes2600_queue *queue,
 	struct bes2600_queue_stats *stats = queue->stats;
 	bool wakeup_stats = false;
 #ifdef CONFIG_BES2600_TESTMODE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+	struct timespec64 tmval;
+#else
 	struct timeval tmval;
+#endif
 #endif /*CONFIG_BES2600_TESTMODE*/
 
 	spin_lock_bh(&queue->lock);
@@ -513,8 +594,13 @@ int bes2600_queue_get(struct bes2600_queue *queue,
 				[item->txpriv.link_id];
 		item->xmit_timestamp = jiffies;
 #ifdef CONFIG_BES2600_TESTMODE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+		ktime_get_real_ts64(&tmval);
+		item->mdelay_timestamp = tmval.tv_nsec / 1000;
+#else
 		do_gettimeofday(&tmval);
 		item->mdelay_timestamp = tmval.tv_usec;
+#endif
 #endif /*CONFIG_BES2600_TESTMODE*/
 
 		spin_lock_bh(&stats->lock);
@@ -726,6 +812,9 @@ int bes2600_queue_remove(struct bes2600_queue *queue, u32 packetID)
 	struct bes2600_queue_stats *stats = queue->stats;
 	struct sk_buff *gc_skb = NULL;
 	struct bes2600_txpriv gc_txpriv;
+	struct bes2600_vif *priv;
+	struct wireless_dev *wdev;
+	int throttle = 0;
 
 	bes2600_queue_parse_id(packetID, &queue_generation, &queue_id,
 				&item_generation, &item_id, &if_id, &link_id);
@@ -758,9 +847,30 @@ int bes2600_queue_remove(struct bes2600_queue *queue, u32 packetID)
 		spin_lock_bh(&hw_priv->tsm_lock);
 		if (hw_priv->start_stop_tsm.start) {
 			if (queue_id == hw_priv->tsm_info.ac) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+				struct timespec64 tmval;
+#else
 				struct timeval tmval;
+#endif
 				unsigned long queue_delay;
 				unsigned long media_delay;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+				ktime_get_real_ts64(&tmval);
+
+				if (tmval.tv_nsec / 1000 > item->qdelay_timestamp)
+					queue_delay = tmval.tv_nsec / 1000 -
+						item->qdelay_timestamp;
+				else
+					queue_delay = tmval.tv_nsec / 1000 +
+					1000000 - item->qdelay_timestamp;
+
+				if (tmval.tv_nsec / 1000 > item->mdelay_timestamp)
+					media_delay = tmval.tv_nsec / 1000 -
+						item->mdelay_timestamp;
+				else
+					media_delay = tmval.tv_nsec / 1000 +
+					1000000 - item->mdelay_timestamp;
+#else
 				do_gettimeofday(&tmval);
 
 				if (tmval.tv_usec > item->qdelay_timestamp)
@@ -776,6 +886,7 @@ int bes2600_queue_remove(struct bes2600_queue *queue, u32 packetID)
 				else
 					media_delay = tmval.tv_usec +
 					1000000 - item->mdelay_timestamp;
+#endif
 				hw_priv->tsm_info.sum_media_delay +=
 							media_delay;
 				hw_priv->tsm_info.sum_pkt_q_delay += queue_delay;
@@ -796,10 +907,24 @@ int bes2600_queue_remove(struct bes2600_queue *queue, u32 packetID)
 		 */
 		list_move(&item->head, &queue->free_pool);
 
-		if (unlikely(queue->overfull) &&
-		    (queue->num_queued <= ((stats->hw_priv->vif0_throttle + stats->hw_priv->vif1_throttle + 2) / 2))) {
-			queue->overfull = false;
-			__bes2600_queue_unlock(queue);
+		if (if_id == 0)
+			throttle = stats->hw_priv->vif0_throttle - (num_present_cpus() - 1);
+		else if (if_id == 1)
+			throttle = stats->hw_priv->vif1_throttle - (num_present_cpus() - 1);
+		else if (if_id == 2)
+			throttle = 2;
+		else
+			bes2600_warn(BES2600_DBG_TXRX, "%s: unexpected if_id = %d\n", __func__, if_id);
+
+		priv = __cw12xx_hwpriv_to_vifpriv(stats->hw_priv, if_id);
+
+		if (priv && unlikely(queue->vif_overfull[if_id]) &&
+		 queue->num_queued_vif[if_id] < (throttle + 1)/2) {
+			wdev = ieee80211_vif_to_wdev(priv->vif);
+			if (wdev->netdev && !ieee80211_queue_stopped(stats->hw_priv->hw, queue->queue_id)) {
+				queue->vif_overfull[if_id] = false;
+				netif_wake_subqueue(wdev->netdev, queue->queue_id);
+			}
 		}
 	}
 	spin_unlock_bh(&queue->lock);
@@ -824,10 +949,25 @@ int bes2600_queue_get_skb(struct bes2600_queue *queue, u32 packetID,
 	int ret = 0;
 	u8 queue_generation, queue_id, item_generation, item_id, if_id, link_id;
 	struct bes2600_queue_item *item;
+	struct bes2600_queue_item *record_item = NULL, *temp_record_item = NULL;
 
 	bes2600_queue_parse_id(packetID, &queue_generation, &queue_id,
 				&item_generation, &item_id, &if_id, &link_id);
 
+	spin_lock(&queue->stats->hw_priv->tx_loop.pending_record_lock);
+	if (!list_empty(&queue->stats->hw_priv->tx_loop.pending_record_list)) {
+		list_for_each_entry_safe(record_item, temp_record_item, &queue->stats->hw_priv->tx_loop.pending_record_list, head) {
+			if (record_item->packetID == packetID) {
+				list_del(&record_item->head);
+				dev_kfree_skb(record_item->skb);
+				kfree(record_item);
+				spin_unlock(&queue->stats->hw_priv->tx_loop.pending_record_lock);
+				return -EINVAL;
+			}
+		}
+	}
+	spin_unlock(&queue->stats->hw_priv->tx_loop.pending_record_lock);
+
 	item = &queue->pool[item_id];
 
 	spin_lock_bh(&queue->lock);
@@ -835,6 +975,7 @@ int bes2600_queue_get_skb(struct bes2600_queue *queue, u32 packetID,
 	/* TODO:COMBO: Add check for interface ID here */
 	if (unlikely(queue_generation != queue->generation)) {
 		bes2600_info(BES2600_DBG_TXRX, "%s, Queue Generation is not equal\n", __func__);
+		WARN_ON(1);
 		ret = -EINVAL;
 	} else if (unlikely(item_id >= (unsigned) queue->capacity)) {
 		WARN_ON(1);
@@ -922,10 +1063,23 @@ void bes2600_queue_iterate_pending_packet(struct bes2600_queue *queue,
 {
 	struct bes2600_queue_item *item = NULL;
 
-	if(list_empty(&queue->pending))
+	if (list_empty(&queue->pending))
 		return;
 
 	list_for_each_entry(item, &queue->pending, head) {
 		iterate_cb(queue->stats->hw_priv, item->skb);
 	}
+}
+
+void bes2600_queue_iterate_record_pending_packet(struct bes2600_common	*hw_priv,
+	void (*iterate_cb)(struct bes2600_common *hw_priv, struct sk_buff *skb))
+{
+	struct bes2600_queue_item *item = NULL;
+	if (list_empty(&hw_priv->tx_loop.pending_record_list)) {
+		return;
+	}
+
+	list_for_each_entry(item, &hw_priv->tx_loop.pending_record_list, head) {
+		iterate_cb(hw_priv, item->skb);
+	}
 }
\ No newline at end of file
diff --git a/drivers/staging/bes2600/queue.h b/drivers/staging/bes2600/queue.h
index 803ceacff178..f0a40a404c47 100644
--- a/drivers/staging/bes2600/queue.h
+++ b/drivers/staging/bes2600/queue.h
@@ -41,7 +41,7 @@ struct bes2600_queue {
 	struct list_head	pending;
 	int			tx_locked_cnt;
 	int			*link_map_cache[CW12XX_MAX_VIFS];
-	bool			overfull;
+	bool			vif_overfull[CW12XX_MAX_VIFS];
 	spinlock_t		lock;
 	u8			queue_id;
 	u8			generation;
@@ -169,5 +169,6 @@ int bes2600_sw_retry_requeue(struct bes2600_common *hw_priv,
 	struct bes2600_queue *queue, u32 packetID, bool check);
 void bes2600_queue_iterate_pending_packet(struct bes2600_queue *queue,
 	void (*iterate_cb)(struct bes2600_common *hw_priv, struct sk_buff *skb));
-
+void bes2600_queue_iterate_record_pending_packet(struct bes2600_common	*hw_priv,
+	void (*iterate_cb)(struct bes2600_common *hw_priv, struct sk_buff *skb));
 #endif /* BES2600_QUEUE_H_INCLUDED */
diff --git a/drivers/staging/bes2600/scan.c b/drivers/staging/bes2600/scan.c
index e0e13b3e5a0f..84a5373dc147 100644
--- a/drivers/staging/bes2600/scan.c
+++ b/drivers/staging/bes2600/scan.c
@@ -87,8 +87,8 @@ static int bes2600_disable_filtering(struct bes2600_vif *priv)
 			priv->if_id);
 
 	/* Beacon Filter Disable */
-	bf_control.enabled = 0;
-	bf_control.bcn_count = 1;
+	bf_control.enabled = __cpu_to_le32(0);
+	bf_control.bcn_count = __cpu_to_le32(1);
 	if (!ret)
 		ret = wsm_beacon_filter_control(hw_priv, &bf_control,
 					priv->if_id);
@@ -651,8 +651,8 @@ void bes2600_scan_work(struct work_struct *work)
 		if (scan.band == NL80211_BAND_2GHZ) {
 			coex_calc_wifi_scan_time(&minChannelTime, &maxChannelTime);
 		} else {
-			minChannelTime = 90;
-			maxChannelTime = 90;
+			minChannelTime = 100;
+			maxChannelTime = 100;
 		}
 #endif
 
@@ -1078,7 +1078,7 @@ void bes2600_probe_work(struct work_struct *work)
 		return;
 	}
 
-	if (bes2600_queue_get_skb(queue,	hw_priv->pending_frame_id,
+	if (bes2600_queue_get_skb(queue, hw_priv->pending_frame_id,
 			&frame.skb, &txpriv)) {
 		up(&hw_priv->scan.lock);
 		up(&hw_priv->conf_lock);
diff --git a/drivers/staging/bes2600/sta.c b/drivers/staging/bes2600/sta.c
index eed1c85fc67c..4fa7e4ad9999 100644
--- a/drivers/staging/bes2600/sta.c
+++ b/drivers/staging/bes2600/sta.c
@@ -38,7 +38,7 @@
 #include "epta_request.h"
 #include "epta_coex.h"
 
-#ifdef PLAT_ALLWINNER_R329
+#if defined(PLAT_ALLWINNER_R329) || defined(STANDARD_FACTORY_EFUSE_FLAG)
 #include "bes2600_factory.h"
 #endif
 
@@ -132,7 +132,7 @@ static inline void __bes2600_bf_configure(struct bes2600_vif *priv)
 					WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT |
 					WSM_BEACON_FILTER_IE_HAS_APPEARED;
 
-	priv->bf_control.enabled = WSM_BEACON_FILTER_ENABLE;
+	priv->bf_control.enabled = __cpu_to_le32(WSM_BEACON_FILTER_ENABLE);
 }
 
 /* ******************************************************************** */
@@ -236,8 +236,20 @@ void bes2600_stop(struct ieee80211_hw *dev)
 	spin_unlock(&hw_priv->event_queue_lock);
 	__bes2600_free_event_queue(&list);
 
-	for (i = 0; i < 4; i++)
-		bes2600_queue_clear(&hw_priv->tx_queue[i], CW12XX_ALL_IFS);
+	spin_lock(&hw_priv->vif_list_lock);
+	bes2600_for_each_vif(hw_priv, priv, i) {
+		if (!priv)
+			continue;
+		if (!(hw_priv->if_id_slot & BIT(priv->if_id)))
+			return;
+		/* protect tx confirm flow */
+		spin_lock(&priv->vif_lock);
+		for (i = 0; i < 4; i++)
+			bes2600_queue_clear(&hw_priv->tx_queue[i], i);
+		spin_unlock(&priv->vif_lock);
+	}
+	spin_unlock(&hw_priv->vif_list_lock);
+	
 
 	/* HACK! */
 	if (atomic_xchg(&hw_priv->tx_lock, 1) != 1)
@@ -424,6 +436,9 @@ void bes2600_remove_interface(struct ieee80211_hw *dev,
 			bes2600_info(BES2600_DBG_STA, "AP REMOVE 11BG %d\n",hw_priv->vif0_throttle);
 		}
 		bes2600_pwr_clear_busy_event(hw_priv, BES2600_JOIN_STATUS_AP);
+#ifdef BES2600_TX_RX_OPT
+		bes2600_txrx_opt_timer_restore();
+#endif
 		break;
 	case BES2600_JOIN_STATUS_MONITOR:
 		bes2600_disable_listening(priv);
@@ -600,12 +615,12 @@ void bes2600_update_filtering(struct bes2600_vif *priv)
 	struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
 	bool bssid_filtering = !priv->rx_filter.bssid;
 	static struct wsm_beacon_filter_control bf_disabled = {
-		.enabled = 0,
-		.bcn_count = 1,
+		.enabled = __cpu_to_le32(0),
+		.bcn_count = __cpu_to_le32(1),
 	};
 	bool ap_mode = 0;
 	static struct wsm_beacon_filter_table bf_table_auto = {
-		.numOfIEs = __cpu_to_le32(2),
+		.numOfIEs = __cpu_to_le32(1),
 		.entry[0].ieId = WLAN_EID_VENDOR_SPECIFIC,
 		.entry[0].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED |
 					WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT |
@@ -613,18 +628,14 @@ void bes2600_update_filtering(struct bes2600_vif *priv)
 		.entry[0].oui[0] = 0x50,
 		.entry[0].oui[1] = 0x6F,
 		.entry[0].oui[2] = 0x9A,
-
-		.entry[1].ieId = WLAN_EID_HT_OPERATION,
-		.entry[1].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED |
-					WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT |
-					WSM_BEACON_FILTER_IE_HAS_APPEARED,
 	};
 	static struct wsm_beacon_filter_control bf_auto = {
-		.enabled = WSM_BEACON_FILTER_ENABLE |
-			WSM_BEACON_FILTER_AUTO_ERP,
-		.bcn_count = 1,
+		.enabled = __cpu_to_le32(WSM_BEACON_FILTER_ENABLE |
+			WSM_BEACON_FILTER_AUTO_ERP | WSM_BEACON_FILTER_AUTO_HT),
+		// .bcn_count = __cpu_to_le32(priv->bf_control.bcn_count);
 	};
-	bf_auto.bcn_count = priv->bf_control.bcn_count;
+	// bf_table_auto.numOfIEs = 0; /* No filtering to do - so discarding */
+	bf_auto.bcn_count = __cpu_to_le32(priv->bf_control.bcn_count);
 
 	if (priv->join_status == BES2600_JOIN_STATUS_PASSIVE)
 		return;
@@ -783,8 +794,8 @@ void bes2600_configure_filter(struct ieee80211_hw *hw,
 		priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS |
 				FIF_PROBE_REQ)) ? 1 : 0;
 		priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0;
-		priv->bf_control.bcn_count = (*total_flags &
-				(FIF_BCN_PRBRESP_PROMISC | FIF_PROBE_REQ)) ? 1 : 0;
+		priv->bf_control.bcn_count = __cpu_to_le32((*total_flags &
+				(FIF_BCN_PRBRESP_PROMISC | FIF_PROBE_REQ)) ? 1 : 0);
 #if 0
 		if (priv->listening ^ listening) {
 			priv->listening = listening;
@@ -800,7 +811,7 @@ void bes2600_configure_filter(struct ieee80211_hw *hw,
 }
 
 int bes2600_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
-		u16 queue, const struct ieee80211_tx_queue_params *params)
+		unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params)
 {
 	struct bes2600_common *hw_priv = dev->priv;
 	struct bes2600_vif *priv = cw12xx_get_vif_from_ieee80211(vif);
@@ -829,9 +840,9 @@ int bes2600_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
 			goto out;
 		}
 
-                WSM_EDCA_SET(&priv->edca, queue, params->aifs,
-                                params->cw_min, params->cw_max, params->txop, 0xc8,
-                                params->uapsd);
+		WSM_EDCA_SET(&priv->edca, queue, params->aifs,
+						params->cw_min, params->cw_max, params->txop, 0xc8,
+						params->uapsd);
 		ret = wsm_set_edca_params(hw_priv, &priv->edca, priv->if_id);
 		if (ret) {
 			ret = -EINVAL;
@@ -1183,9 +1194,12 @@ int __bes2600_flush(struct bes2600_common *hw_priv, bool drop, int if_id)
 		 * Temporary workaround: 2s
 		 */
 		if (drop) {
+			/* protect tx confirm flow */
+			spin_lock(&priv->vif_lock);
 			for (i = 0; i < 4; ++i)
 				bes2600_queue_clear(&hw_priv->tx_queue[i],
 					if_id);
+			spin_unlock(&priv->vif_lock);
 		} else {
 			ret = wait_event_timeout(
 				hw_priv->tx_queue_stats.wait_link_id_empty,
@@ -1224,6 +1238,7 @@ void bes2600_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	struct bes2600_vif *priv = NULL;
 	struct bes2600_common *hw_priv = hw->priv;
 	unsigned int ret = 0;
+	int hw_bufs_used = 0;
 	int i;
 
 	/* get queue status */
@@ -1231,6 +1246,7 @@ void bes2600_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		priv = cw12xx_get_vif_from_ieee80211(vif);
 		ret |= !bes2600_queue_stats_is_empty(
 				&hw_priv->tx_queue_stats, -1, priv->if_id);
+		hw_bufs_used = hw_priv->hw_bufs_used_vif[priv->if_id];
 	} else {
 		bes2600_for_each_vif(hw_priv, priv, i) {
 			if (!priv)
@@ -1239,11 +1255,12 @@ void bes2600_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 				return;
 			ret |= !bes2600_queue_stats_is_empty(
 				&hw_priv->tx_queue_stats, -1, priv->if_id);
+			hw_bufs_used = hw_priv->hw_bufs_used;
 		}
 	}
 
 	/* no need to do the next work if queue was already clear */
-	if(ret == 0) {
+	if((ret == 0) && (hw_bufs_used == 0)) {
 		bes2600_info(BES2600_DBG_STA, "no need to flush\n");
 		return;
 	}
@@ -1385,6 +1402,10 @@ void bes2600_event_handler(struct work_struct *work)
 				break;
 			case WSM_EVENT_BSS_LOST:
 			{
+				if (bes2600_chrdev_wakeup_by_event_get() == WAKEUP_EVENT_WSME) {
+					bes2600_chrdev_wifi_update_wakeup_reason(WAKEUP_REASON_WIFI_BSSLOST, 0);
+					bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_NONE);
+				}
 				spin_lock(&priv->bss_loss_lock);
 				if (priv->bss_loss_status > BES2600_BSS_LOSS_NONE) {
 					spin_unlock(&priv->bss_loss_lock);
@@ -1498,11 +1519,22 @@ void bes2600_event_handler(struct work_struct *work)
 				break;
 			}
 		case WSM_EVENT_WAKEUP_EVENT:
-			bes2600_info(BES2600_DBG_STA, "wifi wakeup, Reason:%u\n", event->evt.eventData);
-			bes2600_chrdev_wifi_update_wakeup_reason(event->evt.eventData);
+			{
+				if (bes2600_chrdev_wakeup_by_event_get() == WAKEUP_EVENT_WSME) {
+					u16 src_port, reason;
+					reason = event->evt.eventData & 0xFFFF;
+					src_port = event->evt.eventData >> 16;
+					src_port = __be16_to_cpu(src_port);
+					bes2600_info(BES2600_DBG_STA, "wifi wakeup, reason: %u, src_port: %u\n", reason, src_port);
+					bes2600_chrdev_wifi_update_wakeup_reason(reason, src_port);
+					bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_NONE);
+				}
+			}
+
 			break;
 		}
 	}
+	bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_NONE);
 	up(&hw_priv->conf_lock);
 	__bes2600_free_event_queue(&list);
 }
@@ -1529,7 +1561,7 @@ void bes2600_bss_loss_work(struct work_struct *work)
 
 	spin_lock(&priv->bss_loss_lock);
 #ifdef BSS_LOSS_CHECK
-	if (!priv->vif->bss_conf.assoc) {
+	if (!priv->vif->cfg.assoc) {
 		priv->bss_loss_status = BES2600_BSS_LOSS_NONE;
 		spin_unlock(&priv->bss_loss_lock);
 		bl_ck_cnt = 0;
@@ -1545,7 +1577,8 @@ void bes2600_bss_loss_work(struct work_struct *work)
 		bl_ck_cnt = 0;
 		bl_cfm_cnt = 0;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
-		skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
+		// skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
+		skb = ieee80211_nullfunc_get(priv->hw, priv->vif, -1, false);
 #else
 		skb = ieee80211_nullfunc_get(priv->hw, priv->vif);
 #endif
@@ -1575,7 +1608,8 @@ void bes2600_bss_loss_work(struct work_struct *work)
 			spin_unlock(&priv->bss_loss_lock);
 			priv->bss_loss_status = BES2600_BSS_LOSS_CHECKING;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
-			skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
+			// skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
+			skb = ieee80211_nullfunc_get(priv->hw, priv->vif, -1, false);
 #else
 			skb = ieee80211_nullfunc_get(priv->hw, priv->vif);
 #endif
@@ -1611,7 +1645,8 @@ void bes2600_bss_loss_work(struct work_struct *work)
 			spin_unlock(&priv->bss_loss_lock);
 			priv->bss_loss_status = BES2600_BSS_LOSS_CHECKING;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
-			skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
+			// skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
+			skb = ieee80211_nullfunc_get(priv->hw, priv->vif, -1, false);
 #else
 			skb = ieee80211_nullfunc_get(priv->hw, priv->vif);
 #endif
@@ -1661,9 +1696,14 @@ void bes2600_connection_loss_work(struct work_struct *work)
 	struct bes2600_vif *priv =
 		container_of(work, struct bes2600_vif,
 				connection_loss_work.work);
+	struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
+
 	bes2600_info(BES2600_DBG_STA, "[CQM] Reporting connection loss.\n");
 	bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_BSS_LOST);
-	ieee80211_connection_loss(priv->vif);
+	if(bes2600_suspend_status_get(hw_priv)) {
+		bes2600_pending_unjoin_set(hw_priv, priv->if_id);
+	} else
+		ieee80211_connection_loss(priv->vif);
 #ifdef WIFI_BT_COEXIST_EPTA_ENABLE
 	// set disconnected in BSS_CHANGED_ASSOC
 	// bwifi_change_current_status(hw_priv, BWIFI_STATUS_DISCONNECTED);
@@ -2295,6 +2335,7 @@ void bes2600_join_work(struct work_struct *work)
 #else
 			wsm_set_template_frame(hw_priv, &probe_tmp, priv->if_id);
 #endif
+			dev_kfree_skb(probe_tmp.skb);
 		}
 
 		if (wsm_join(hw_priv, &join, priv->if_id)) {
@@ -2390,7 +2431,7 @@ void bes2600_unjoin_work(struct work_struct *work)
 		cancel_work_sync(&priv->set_beacon_wakeup_period_work);
 		memset(&priv->join_bssid[0], 0, sizeof(priv->join_bssid));
 #ifdef BES2600_TX_RX_OPT
-		txrx_opt_timer_exit(hw_priv);
+		txrx_opt_timer_exit(priv);
 #endif
 		bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_PS_ACTIVE);
 		bes2600_pwr_clear_ap_lp_bad_mark(hw_priv);
@@ -2838,11 +2879,15 @@ void bes2600_rem_chan_timeout(struct work_struct *work)
 
 void bes2600_dynamic_opt_txrx_work(struct work_struct *work)
 {
+	bool multivif_connected = false;
 	struct bes2600_common *hw_priv =
 		container_of(work, struct bes2600_common, dynamic_opt_txrx_work);
-	struct bes2600_vif *priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, 0);
-	bes2600_dynamic_opt_rxtx(hw_priv,priv, 0);
-	bes2600_dbg(BES2600_DBG_STA, "bes2600_dynamic_opt_txrx_work called\n");
+	struct bes2600_vif *priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, 1);
+
+	if (priv != NULL && priv->join_status > BES2600_JOIN_STATUS_MONITOR) {
+		multivif_connected = true;
+	}
+	bes2600_txrx_opt_multivif_connected_handler(hw_priv, multivif_connected);
 }
 
 
@@ -2980,7 +3025,7 @@ static int bes2600_set_ipv6addrfilter(struct ieee80211_hw *hw,
 	ipv6_info = (struct ipv6_addr_info *)&data[2];
 
 	/* Computing sizeof Mac addr filter */
-	ipaddrfiltersize =  sizeof(*ipv6_filter) + \
+	ipaddrfiltersize =  sizeof(struct wsm_ipv6_filter_header) + \
 			(no_of_ip_addr * sizeof(struct wsm_ip6_addr_info));
 
 
@@ -2989,8 +3034,8 @@ static int bes2600_set_ipv6addrfilter(struct ieee80211_hw *hw,
 		ret = -ENOMEM;
 		goto exit_p;
 	}
-	ipv6_filter->action_mode = action_mode;
-	ipv6_filter->numfilter = no_of_ip_addr;
+	ipv6_filter->hdr.action_mode = action_mode;
+	ipv6_filter->hdr.numfilter = no_of_ip_addr;
 
 	for (i = 0; i < no_of_ip_addr; i++) {
 		ipv6_filter->ipv6filter[i].address_mode = \
@@ -3025,8 +3070,10 @@ void bes2600_set_data_filter(struct ieee80211_hw *hw,
 			   void *data, int len)
 {
 	int ret = 0;
-	//struct bes2600_vif *priv = cw12xx_get_vif_from_ieee80211(vif);
 	int filter_id;
+#ifdef IPV6_FILTERING
+	struct bes2600_vif *priv = cw12xx_get_vif_from_ieee80211(vif);
+#endif /*IPV6_FILTERING*/
 
 	if (!data) {
 		ret = -EINVAL;
@@ -4344,8 +4391,8 @@ static int net_device_en_ip_offload(struct ieee80211_hw *hw, struct ieee80211_vi
 }
 #endif /* CONFIG_BES2600_KEEP_ALIVE */
 
-#ifdef PLAT_ALLWINNER_R329
-static int bes2600_factory_cali_to_flash(struct ieee80211_hw *hw)
+#if defined(PLAT_ALLWINNER_R329) || defined(STANDARD_FACTORY_EFUSE_FLAG)
+static int bes2600_factory_cali_to_mcu(struct ieee80211_hw *hw, enum bes2600_rf_cmd_type cmd_type)
 {
 	struct bes2600_common *hw_priv = hw->priv;
 	u8 *factory_data = NULL;
@@ -4367,8 +4414,8 @@ static int bes2600_factory_cali_to_flash(struct ieee80211_hw *hw)
 	} else {
 		bes2600_factory_data_check(factory_data);
 		factory_little_endian_cvrt(factory_data);
-		ret = wsm_save_factory_txt_to_flash(hw_priv, factory_data, 0);
-		bes2600_err_with_cond(ret, BES2600_DBG_DOWNLOAD, "save factory data to flash failed.\n");
+		ret = wsm_save_factory_txt_to_mcu(hw_priv, factory_data, 0, cmd_type);
+		bes2600_err_with_cond(ret, BES2600_DBG_DOWNLOAD, "save factory data to mcu failed.\n");
 	}
 	bes2600_factory_free_file_buffer(file_buffer);
 	bes2600_factory_unlock();
@@ -4377,7 +4424,16 @@ static int bes2600_factory_cali_to_flash(struct ieee80211_hw *hw)
 		return bes2600_testmode_reply(hw->wiphy, &ret, sizeof(int));
 
 	return ret;
+}
+#endif
 
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+static int bes2600_set_select_efuse_flag_to_txt(struct ieee80211_hw *hw,
+		       void *data, int len)
+{
+	struct bes_select_calib_t *test_p = (struct bes_select_calib_t *)data;
+	int ret = bes2600_select_efuse_flag_write(test_p->select_efuse_flag);
+    return bes2600_testmode_reply(hw->wiphy, &ret, sizeof(int));
 }
 #endif
 
@@ -4490,9 +4546,23 @@ int bes2600_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, voi
 		break;
 	case BES_MSG_SAVE_CALI_TXT_TO_FLASH:
 #ifdef PLAT_ALLWINNER_R329
-		ret = bes2600_factory_cali_to_flash(hw);
+		ret = bes2600_factory_cali_to_mcu(hw, BES2600_RF_CMD_CALI_TXT_TO_FLASH);
+#else
+		ret = -EPERM;
+#endif
+		break;
+	case BES_MSG_SAVE_CALI_TXT_TO_EFUSE:
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+		ret = bes2600_factory_cali_to_mcu(hw, BES2600_RF_CMD_CALI_TXT_TO_EFUSE);
 #else
 		ret = -EPERM;
+#endif
+		break;
+	case BES_MSG_SET_SELECT_EFUSE_FLAG:
+#ifdef STANDARD_FACTORY_EFUSE_FLAG
+		ret = bes2600_set_select_efuse_flag_to_txt(hw, nla_data(data_p), nla_len(data_p));
+#else
+		ret = EPERM;
 #endif
 		break;
 	case BES_MSG_VENDOR_RF_CMD:
diff --git a/drivers/staging/bes2600/sta.h b/drivers/staging/bes2600/sta.h
index f97e8fc1bb21..229d1305f38f 100644
--- a/drivers/staging/bes2600/sta.h
+++ b/drivers/staging/bes2600/sta.h
@@ -36,7 +36,7 @@ void bes2600_configure_filter(struct ieee80211_hw *dev,
 			     unsigned int *total_flags,
 			     u64 multicast);
 int bes2600_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
-		u16 queue, const struct ieee80211_tx_queue_params *params);
+		unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params);
 int bes2600_get_stats(struct ieee80211_hw *dev,
 		     struct ieee80211_low_level_stats *stats);
 /* Not more a part of interface?
diff --git a/drivers/staging/bes2600/tx_loop.c b/drivers/staging/bes2600/tx_loop.c
index dbd5c37c6b9d..69eef9f4c14f 100644
--- a/drivers/staging/bes2600/tx_loop.c
+++ b/drivers/staging/bes2600/tx_loop.c
@@ -27,6 +27,8 @@ void bes2600_tx_loop_init(struct bes2600_common *hw_priv)
         hw_priv->tx_loop.enabled = false;
         hw_priv->tx_loop.start_lmac_seq = 0;
         hw_priv->tx_loop.start_mcu_seq = 0;
+        INIT_LIST_HEAD(&hw_priv->tx_loop.pending_record_list);
+        spin_lock_init(&hw_priv->tx_loop.pending_record_lock);
         spin_lock_init(&hw_priv->tx_loop.tx_loop_lock);
         skb_queue_head_init(&hw_priv->tx_loop.rx_queue);
 }
@@ -108,6 +110,9 @@ void bes2600_tx_loop_set_enable(struct bes2600_common *hw_priv)
                 bes2600_queue_iterate_pending_packet(&hw_priv->tx_queue[i],
 				                bes2600_tx_loop_item_pending_item);
         }
+	spin_lock(&hw_priv->tx_loop.pending_record_lock);
+        bes2600_queue_iterate_record_pending_packet(hw_priv, bes2600_tx_loop_item_pending_item);
+	spin_unlock(&hw_priv->tx_loop.pending_record_lock);
 
         if (atomic_read(&hw_priv->bh_rx) > 0)
 		wake_up(&hw_priv->bh_wq);
diff --git a/drivers/staging/bes2600/tx_loop.h b/drivers/staging/bes2600/tx_loop.h
index 7294025d8eca..f7325c9fae0f 100644
--- a/drivers/staging/bes2600/tx_loop.h
+++ b/drivers/staging/bes2600/tx_loop.h
@@ -21,6 +21,8 @@ struct bes2600_tx_loop
         u8 start_mcu_seq;
         struct sk_buff_head rx_queue;
         u8 *wsm_cmd_ptr;
+        struct list_head pending_record_list;
+        spinlock_t pending_record_lock;
 };
 
 void bes2600_tx_loop_init(struct bes2600_common *hw_priv);
diff --git a/drivers/staging/bes2600/txrx.c b/drivers/staging/bes2600/txrx.c
index d9202bce7116..ce700bdcaf72 100644
--- a/drivers/staging/bes2600/txrx.c
+++ b/drivers/staging/bes2600/txrx.c
@@ -10,6 +10,7 @@
  */
 
 #include <net/mac80211.h>
+#include <net/sock.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
@@ -90,28 +91,23 @@ static void tx_policy_build(const struct bes2600_common *hw_priv,
 	BUG_ON(rates[0].idx < 0);
 	memset(policy, 0, sizeof(*policy));
 
-	/* minstrel is buggy a little bit, so distille
-	 * incoming rates first. */
-	/* Sort rates in descending order. */
+	/*
+	 * Calculate the count of rate list.
+	 * Don't change the order of rate list, it will cause tp debounce at medium attenuation
+	 * For some test, you may want to rate stable, you can use fix rate.
+	 * The way of setting fix rate is writting /sys/kernel/debug/ieee80211/phy0/rc/fixed_rate_idx
+	 * Note: if you want to use the function of fix rate, you need to make sure CONFIG_MAC80211_DEBUGFS is y
+	 */
+
 	for (i = 0; i < count; i++) {
 		if (rates[i].idx < 0) {
 			count = i;
 			break;
 		}
-		for (j= 0; j < count; j++) {
-			if (rates[j].idx < 0) {
-				continue;
-			}
-
-			if (rates[j].idx < rates[j + 1].idx) {
-				struct ieee80211_tx_rate tmp = rates[j];
-				rates[j] = rates[j + 1];
-				rates[j + 1] = tmp;
-			}
-		}
 	}
+
 	/* enhance throughput, more tx retry rate */
-#ifdef BES2600_TX_RX_OPT
+#if defined(BES2600_TX_RX_OPT) && defined(BES2600_TX_MORE_RETRY)
 	if (rates[0].flags & IEEE80211_TX_RC_MCS) {
 		static int min_rate_index = 1; //min rate index  is mcs1
 		static u8 last_rate_tx_cnt = 7;
@@ -1073,7 +1069,7 @@ void bes2600_tx(struct ieee80211_hw *dev,
 	int ret;
 	struct bes2600_vif *priv;
 	struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data;
-        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 
 	if (!skb->data)
 		BUG_ON(1);
@@ -1320,13 +1316,23 @@ void bes2600_tx_confirm_cb(struct bes2600_common *hw_priv,
 	} else if ((hw_priv->start_stop_tsm.start) &&
 		(arg->status == WSM_STATUS_SUCCESS)) {
 		if (queue_id == hw_priv->tsm_info.ac) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+			struct timespec64 tmval;
+			ktime_get_real_ts64(&tmval);
+#else
 			struct timeval tmval;
 			do_gettimeofday(&tmval);
+#endif
 			pkt_delay = hw_priv->start_stop_tsm.packetization_delay;
 			if (hw_priv->tsm_info.sta_roamed &&
 			    !hw_priv->tsm_info.use_rx_roaming) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+				hw_priv->tsm_info.roam_delay = tmval.tv_nsec / 1000 -
+				hw_priv->tsm_info.txconf_timestamp_vo;
+#else
 				hw_priv->tsm_info.roam_delay = tmval.tv_usec -
 				hw_priv->tsm_info.txconf_timestamp_vo;
+#endif
 				if (hw_priv->tsm_info.roam_delay > pkt_delay)
 					hw_priv->tsm_info.roam_delay -= pkt_delay;
 				bes2600_info(BES2600_DBG_TEST_MODE, "[TX] txConf"
@@ -1334,7 +1340,11 @@ void bes2600_tx_confirm_cb(struct bes2600_common *hw_priv,
 				hw_priv->tsm_info.roam_delay);
 				hw_priv->tsm_info.sta_roamed = 0;
 			}
-			hw_priv->tsm_info.txconf_timestamp_vo = tmval.tv_usec;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+			hw_priv->tsm_info.rx_timestamp_vo = tmval.tv_nsec / 1000;
+#else
+			hw_priv->tsm_info.rx_timestamp_vo = tmval.tv_usec;
+#endif
 		}
 	}
 	spin_unlock_bh(&hw_priv->tsm_lock);
@@ -1422,7 +1432,6 @@ void bes2600_tx_confirm_cb(struct bes2600_common *hw_priv,
 			if (tx_count)
 				++tx_count;
 		}
-		spin_unlock(&priv->vif_lock);
 
 		for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) {
 			if (tx->status.rates[i].count >= tx_count) {
@@ -1440,6 +1449,7 @@ void bes2600_tx_confirm_cb(struct bes2600_common *hw_priv,
 		}
 #ifdef KEY_FRAME_SW_RETRY
 		if (bes2600_bh_sw_process(hw_priv, arg) == 0) {
+			spin_unlock(&priv->vif_lock);
 			return;
 		}
 #endif
@@ -1449,6 +1459,7 @@ void bes2600_tx_confirm_cb(struct bes2600_common *hw_priv,
 #else
 		bes2600_queue_remove(queue, arg->packetID);
 #endif /*CONFIG_BES2600_TESTMODE*/
+		spin_unlock(&priv->vif_lock);
 	}else {
 		spin_unlock(&priv->vif_lock);
 		return;
@@ -1499,8 +1510,11 @@ void bes2600_skb_dtor(struct bes2600_common *hw_priv,
 		tx_policy_put(hw_priv, txpriv->rate_id);
 	}
 	if (likely(!bes2600_is_itp(hw_priv))) {
+		if (priv) {
+			/* The interface may be already removed */
+			bes2600_tx_status(priv, skb);
+		}
 		ieee80211_tx_status(hw_priv->hw, skb);
-		bes2600_tx_status(priv, skb);
 	}
 
 }
@@ -1600,18 +1614,30 @@ void bes2600_rx_cb(struct bes2600_vif *priv,
 	struct bes2600_link_entry *entry = NULL;
 	bool early_data = false;
 	size_t hdrlen = 0;
+	u64 tsf;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
+	do {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
+		struct timespec ts;
+		ts = ktime_to_timespec(ktime_get_boottime());
+		tsf = (u64)ts.tv_sec * 1000000000 + ts.tv_nsec;
+#else
+		struct timespec64 ts;
+		ts = ktime_to_timespec64(ktime_get_boottime());
+		tsf = (u64)ts.tv_sec * 1000000000 + ts.tv_nsec;
+#endif
+		hdr->boottime_ns = tsf;
+	} while (0);
+#endif
 
 	hdr->flag = 0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
-	hdr->boottime_ns = ktime_get_boot_ns();
-#endif
 	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) {
 		/* STA is stopped. */
 		goto drop;
 	}
 
 	/* wakeup device based on frame type */
-	if (!is_multicast_ether_addr(ieee80211_get_DA(frame))) {
+	if (!is_multicast_ether_addr(ieee80211_get_DA(frame)) && ieee80211_is_data(frame->frame_control)) {
 		/* for unicast, wakeup device directly */
 		bes2600_pwr_set_busy_event_with_timeout_async(
 	 			hw_priv, BES_PWR_LOCK_ON_RX, BES_PWR_EVENT_RX_TIMEOUT);
@@ -1628,17 +1654,31 @@ void bes2600_rx_cb(struct bes2600_vif *priv,
 	if (hw_priv->start_stop_tsm.start) {
 		unsigned queue_id = skb_get_queue_mapping(skb);
 		if (queue_id == 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+			struct timespec64 tmval;
+			ktime_get_real_ts64(&tmval);
+#else
 			struct timeval tmval;
 			do_gettimeofday(&tmval);
+#endif
 			if (hw_priv->tsm_info.sta_roamed &&
-			    hw_priv->tsm_info.use_rx_roaming) {
+				hw_priv->tsm_info.use_rx_roaming) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+				hw_priv->tsm_info.roam_delay = tmval.tv_nsec / 1000 -
+					hw_priv->tsm_info.rx_timestamp_vo;
+#else
 				hw_priv->tsm_info.roam_delay = tmval.tv_usec -
 					hw_priv->tsm_info.rx_timestamp_vo;
+#endif
 				bes2600_dbg(BES2600_DBG_TEST_MODE, "[RX] RxInd Roaming:"
 				"roam_delay = %u\n", hw_priv->tsm_info.roam_delay);
 				hw_priv->tsm_info.sta_roamed = 0;
 			}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+			hw_priv->tsm_info.rx_timestamp_vo = tmval.tv_nsec / 1000;
+#else
 			hw_priv->tsm_info.rx_timestamp_vo = tmval.tv_usec;
+#endif
 		}
 	}
 	spin_unlock_bh(&hw_priv->tsm_lock);
diff --git a/drivers/staging/bes2600/txrx_opt.c b/drivers/staging/bes2600/txrx_opt.c
index 15f6abbb666f..edc1691ce25b 100644
--- a/drivers/staging/bes2600/txrx_opt.c
+++ b/drivers/staging/bes2600/txrx_opt.c
@@ -27,6 +27,7 @@
 #include "sbus.h"
 #include "bes2600_log.h"
 #include "bes_pwr.h"
+#include "txrx_opt.h"
 
 #define TXRX_OPT_CLOSE_EDCA     0
 #define TXRX_OPT_EDCA_MAX_LEVEL 4
@@ -34,15 +35,25 @@
 #define TXRX_OPT_PEROID         500
 #define TXRX_OPT_DEBUG          1
 
-#define TXRX_HIGH_TP_THRESHOLD_2G4    30000   //unit is kbps
-#define TXRX_HIGH_TP_THRESHOLD_5G    40000    //unit is kbps
-#define TXRX_HIGH_TP_DELTA_TIME_2G4   8       //unit ms
-#define TXRX_HIGH_TP_DELTA_TIME_5G   6       //unit ms
+#define TXRX_HIGH_TP_THRESHOLD_2G4    	30000   // unit is kbps
+#define TXRX_HIGH_TP_THRESHOLD_5G    	40000   // unit is kbps
+#define TXRX_HIGH_TP_DELTA_TIME_2G4   	8       // unit ms
+#define TXRX_HIGH_TP_DELTA_TIME_5G   	6       // unit ms
+
+#define TXRX_RTS_PROT_TRIG_THRESH		80		// percent * 100
+#define TXRX_RTS_PROT_DURATION			10		// unit second
+
+#define TXRX_RTS_PROT_OPEN(x)			(x = 512)
+#define TXRX_RTS_PROT_CLOSE(x)			(x = 2437)
+#define TXRX_RTS_PROT_OPENED(x)			(x < 1536)
 
 static uint32_t tx_delta_time_arr[4][TX_AVG_TIME_COUNT];
 static uint32_t tx_queue_arr[4] = {0};
 static uint32_t tx_delta_time_total = 0;
 static uint32_t tx_delta_time_total_cnt = 0;
+static u8 cur_pwr_tbl = 1;
+static u16 cur_rts_thres = 2437;
+static unsigned long last_rts_set_time = -1;
 
 void bes2600_add_tx_delta_time(uint32_t tx_delta_time)
 {
@@ -185,8 +196,9 @@ int bes2600_set_high_edca_params(struct bes2600_common *hw_priv, struct bes2600_
 	if (lev == level)
 		return 0;
 
-	memcpy(&arg, &(priv->edca), sizeof(struct wsm_edca_params));
+	lev = level;
 
+	memcpy(&arg, &(priv->edca), sizeof(struct wsm_edca_params));
 
 	if (level == 0) {
 		bes2600_set_default_params(hw_priv, priv);
@@ -245,6 +257,26 @@ void bes2600_set_dynamic_agc(struct bes2600_common *hw_priv, struct bes2600_vif
 {
 // todo set agc alg 
 }
+
+int bes2600_update_pwr_table(struct bes2600_common *hw_priv,
+			      struct bes2600_vif *priv,
+			      u8 pwr_tbl_idx)
+{
+	int ret = 0;
+	static u8 cur_pwr_tbl_idx = 0xff;
+
+	if (cur_pwr_tbl_idx != pwr_tbl_idx) {
+		cur_pwr_tbl_idx = pwr_tbl_idx;
+		ret = WARN_ON(wsm_write_mib(hw_priv,
+					    WSM_MIB_ID_EXT_PWR_TBL_UPDATE,
+					    (u8 *)&cur_pwr_tbl_idx,
+					    sizeof(cur_pwr_tbl_idx),
+					    priv->if_id));
+		bes2600_info(BES2600_DBG_TXRX_OPT, "%s pwr_tbl_idx=%d\n\r", __func__, pwr_tbl_idx);
+	}
+	return ret;
+}
+
 int bes2600_get_tx_av_max_delta_time(void)
 {
 	int max_avg = 0;
@@ -278,8 +310,6 @@ void bes2600_dynamic_opt_rxtx(struct bes2600_common *hw_priv, struct bes2600_vif
 	static u32 tx_bps = 0, rx_bps = 0;
 	u32 total_kbps = 0;
 	static int level;
-	int rts_value = 2347;
-	int short_gi = 0;
 
 	/* calculate real time throughput */
 	if (hw_priv == NULL || priv == NULL) {
@@ -295,6 +325,8 @@ void bes2600_dynamic_opt_rxtx(struct bes2600_common *hw_priv, struct bes2600_vif
 	/*  if tx/rx < 100k/s, close*/
 	if (total_kbps < 100) {
 		level = 0;
+		last_rts_set_time = -1;
+		TXRX_RTS_PROT_CLOSE(cur_rts_thres);
 		goto txrx_opt_clear;
 	}
 
@@ -305,16 +337,18 @@ void bes2600_dynamic_opt_rxtx(struct bes2600_common *hw_priv, struct bes2600_vif
 	rx_cnt = (priv->dot11ReceivedFragmentCount - l_rx_cnt);
 	( (tx_cnt + tx_retry) > 0 ) ? (succPro = tx_cnt * 100 / (tx_cnt + tx_retry)) : (succPro = 0);
 
-	if (succPro != 0) {
-		/* hw value 21 is mcs7, dynamic set short GI */
-		if (priv->hw_value == 21 && succPro > 90)
-			short_gi = 1;
-		else
-			short_gi = 0;
-
-		/* dynamic set RTS/CTS */
-		if (succPro  < 80)
-			rts_value = 512;
+	bes2600_dbg(BES2600_DBG_TXRX_OPT, "%s, tx_cnt:%d prob:%d\n", __func__, tx_cnt, succPro);
+
+	/* set rts/cts protection dynamically */
+	if (tx_cnt > 50 && succPro != 0) {
+		if (succPro > TXRX_RTS_PROT_TRIG_THRESH && 
+			TXRX_RTS_PROT_OPENED(cur_rts_thres) &&
+		    time_after(jiffies, last_rts_set_time + TXRX_RTS_PROT_DURATION * HZ)) {
+			TXRX_RTS_PROT_CLOSE(cur_rts_thres);
+		} else if (succPro <= TXRX_RTS_PROT_TRIG_THRESH){
+			TXRX_RTS_PROT_OPEN(cur_rts_thres);
+			last_rts_set_time = jiffies;
+		}
 	}
 
 	/* dynamic set edca param */
@@ -348,14 +382,21 @@ void bes2600_dynamic_opt_rxtx(struct bes2600_common *hw_priv, struct bes2600_vif
 
 		}
 	}
+
+	/* dynamic set power table */
+	if (rssi <= BES2600_TX_RSSI_LOW)
+		cur_pwr_tbl = 2;	// use high power table
+	else if(rssi >= BES2600_TX_RSSI_HIGH)
+		cur_pwr_tbl = 1;	// use standard power table
+
 #if TXRX_OPT_CLOSE_EDCA
 	level = 0;
 #endif
 	if (level > TXRX_OPT_EDCA_MAX_LEVEL)
 		level = TXRX_OPT_EDCA_MAX_LEVEL;
 
-	bes2600_dbg(BES2600_DBG_TXRX_OPT, "txrx_opt: tx(cnt=%d retry=%d psr=%d tx_fail=%d (wsm rts=%d shortgi=%d level=%d) tx=%dk/s)\n\r",
-	       tx_cnt, tx_retry, succPro, tx_fail, rts_value, short_gi, level, tx_bps / 128);
+	bes2600_dbg(BES2600_DBG_TXRX_OPT, "txrx_opt: tx(cnt=%d retry=%d psr=%d tx_fail=%d (wsm level=%d) tx=%dk/s)\n\r",
+	       tx_cnt, tx_retry, succPro, tx_fail, level, tx_bps / 128);
 	bes2600_dbg(BES2600_DBG_TXRX_OPT, "txrx_opt: rx(cnt=%d  rx=%dk/s) total=%dk/s\n\r", rx_cnt, rx_bps / 128, total_kbps);
 	bes2600_dbg(BES2600_DBG_TXRX_OPT, "txrx_opt: tx_delta_time=%d [%d %d %d %d] hw_value=%d ht=%d maxtxcnt=%d\n\r",
 	       bes2600_get_tx_delta_time(), bes2600_get_tx_ac_delta_time(0), bes2600_get_tx_ac_delta_time(1),
@@ -367,10 +408,10 @@ void bes2600_dynamic_opt_rxtx(struct bes2600_common *hw_priv, struct bes2600_vif
 	bes2600_set_cca_method(hw_priv, priv, 0);
 	/* dynamic set agc */
 	bes2600_set_dynamic_agc(hw_priv, priv, 0);
+	bes2600_update_pwr_table(hw_priv, priv, cur_pwr_tbl);
 txrx_opt_clear:
-	bes2600_set_rts_threshold(priv->hw, rts_value);
-	bes2600_enable_tx_shortgi(hw_priv, priv, short_gi);
 	bes2600_set_high_edca_params(hw_priv, priv, level);
+	bes2600_set_rts_threshold(hw_priv->hw, cur_rts_thres);
 	bes2600_clear_tx_delta_time();
 	bes2600_clear_tx_ac_delta_time(0);
 	bes2600_clear_tx_ac_delta_time(1);
@@ -387,6 +428,21 @@ txrx_opt_clear:
 
 static struct bes2600_common *txrx_hw_priv = NULL;
 
+static bool bes2600_is_sta_connected(void)
+{
+	if (txrx_hw_priv == NULL)
+		return false;
+	else
+		return true;
+}
+
+void bes2600_txrx_opt_timer_restore(void)
+{
+	if (bes2600_is_sta_connected()) {
+		mod_timer(&txrx_hw_priv->txrx_opt_timer, jiffies + msecs_to_jiffies(TXRX_OPT_PEROID));
+	}
+}
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
 static void txrx_opt_timer_callback(struct timer_list* data)
 #else
@@ -395,7 +451,6 @@ static void txrx_opt_timer_callback(unsigned long data)
 {
 	bes2600_dbg(BES2600_DBG_TXRX, "####Timer callback function Called time = %lu\n", jiffies);
 	queue_work(txrx_hw_priv->workqueue, &txrx_hw_priv->dynamic_opt_txrx_work);
-	mod_timer(&txrx_hw_priv->txrx_opt_timer, jiffies + msecs_to_jiffies(TXRX_OPT_PEROID));
 }
 
 static void txrx_opt_timer_start(struct bes2600_common *hw_priv)
@@ -410,12 +465,39 @@ static void txrx_opt_timer_stop(struct bes2600_common *hw_priv)
 
 int bes2600_set_txrx_opt_default_param(struct bes2600_common * hw_priv)
 {
-	MIB_TXRX_OPT_PARAM g_txrx_param = {2, (PROCTECT_MODE_RTS_CTS | PROCTECT_MODE_RTS_CTS_RETRY), 2002};
+	MIB_TXRX_OPT_PARAM g_txrx_param = {2, (PROCTECT_MODE_RTS_CTS | PROCTECT_MODE_RTS_CTS_RETRY), 3000};
 	struct bes2600_vif *priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, 0);
+	struct ieee80211_sta *sta = NULL;
+
 	if (priv == NULL)
 		return 0;
+
+	/* reset states */
+	cur_pwr_tbl = 1;
+	TXRX_RTS_PROT_CLOSE(cur_rts_thres);
+	last_rts_set_time = -1;
 	memcpy(&hw_priv->txrx_opt_param, &g_txrx_param, sizeof(MIB_TXRX_OPT_PARAM));
+
+	/* reset device states */
 	bes2600_set_txrx_opt_param(hw_priv, priv, &hw_priv->txrx_opt_param);
+	bes2600_set_rts_threshold(hw_priv->hw, cur_rts_thres);	// close rts/cts
+	bes2600_update_pwr_table(hw_priv, priv, cur_pwr_tbl);	// use standard pwr table
+
+	if (priv->join_status == BES2600_JOIN_STATUS_STA) {
+		sta = ieee80211_find_sta(priv->vif, priv->vif->bss_conf.bssid);
+		if (sta->deflink.ht_cap.ht_supported &&
+		    ((priv->vif->bss_conf.chandef.width == NL80211_CHAN_WIDTH_20 && 
+			 sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ||
+			(priv->vif->bss_conf.chandef.width == NL80211_CHAN_WIDTH_40 && 
+			 sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40))) {
+			bes2600_info(BES2600_DBG_TXRX, "open short gi tx\n");
+			bes2600_enable_tx_shortgi(hw_priv, priv, 1);
+		} else {
+			bes2600_info(BES2600_DBG_TXRX, "close short gi tx\n");
+			bes2600_enable_tx_shortgi(hw_priv, priv, 0);
+		}
+	}
+
 	return 0;
 }
 
@@ -425,14 +507,35 @@ int bes2600_set_txrx_opt_unjoin_param(struct bes2600_common * hw_priv)
 	struct bes2600_vif *priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, 0);
 	if (priv == NULL)
 		return 0;
+
+	/* reset states */
+	cur_pwr_tbl = 1;
+	bes2600_update_pwr_table(hw_priv, priv, cur_pwr_tbl);
 	memcpy(&hw_priv->txrx_opt_param, &g_txrx_param, sizeof(MIB_TXRX_OPT_PARAM));
 	bes2600_set_txrx_opt_param(hw_priv, priv, &hw_priv->txrx_opt_param);
 	return 0;
 }
 
-int txrx_opt_timer_init(struct bes2600_common *hw_priv)
+void bes2600_txrx_opt_multivif_connected_handler(struct bes2600_common *hw_priv, bool multivif_connected)
 {
+	struct bes2600_vif *priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, 0);
+
+	if (multivif_connected) {
+		bes2600_set_txrx_opt_default_param(hw_priv);
+	} else {
+		bes2600_dbg(BES2600_DBG_STA, "%s, rssi:%d\n", __func__, priv->signal);
+		bes2600_dynamic_opt_rxtx(hw_priv, priv, priv->signal);
+		mod_timer(&hw_priv->txrx_opt_timer, jiffies + msecs_to_jiffies(TXRX_OPT_PEROID));
+	}
+}
+
+int txrx_opt_timer_init(struct bes2600_vif *priv)
+{
+	struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
 	bes2600_info(BES2600_DBG_TXRX_OPT, "txrx_opt_timer_init:%p", txrx_hw_priv);
+	if (priv->if_id != 0)
+		return 0;
+
 	if (!txrx_hw_priv) {
 		txrx_hw_priv = hw_priv;
 		bes2600_info(BES2600_DBG_TXRX, "####Timer init hw_priv = %p\n", txrx_hw_priv);
@@ -452,16 +555,21 @@ int txrx_opt_timer_init(struct bes2600_common *hw_priv)
 	return 0;
 }
 
-void txrx_opt_timer_exit(struct bes2600_common *hw_priv)
+void txrx_opt_timer_exit(struct bes2600_vif *priv)
 {
+	struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
 	bes2600_info(BES2600_DBG_TXRX_OPT, "txrx_opt_timer_exit");
 
-	del_timer_sync(&hw_priv->txrx_opt_timer);
-	cancel_work_sync(&hw_priv->dynamic_opt_txrx_work);
-	bes2600_pwr_unregister_en_lp_cb(hw_priv, txrx_opt_timer_stop);
-	bes2600_pwr_unregister_exit_lp_cb(hw_priv, txrx_opt_timer_start);
-	txrx_hw_priv = NULL;
-	bes2600_set_txrx_opt_unjoin_param(hw_priv);
+	if (priv->if_id == 0) {
+		del_timer_sync(&hw_priv->txrx_opt_timer);
+		cancel_work_sync(&hw_priv->dynamic_opt_txrx_work);
+		bes2600_pwr_unregister_en_lp_cb(hw_priv, txrx_opt_timer_stop);
+		bes2600_pwr_unregister_exit_lp_cb(hw_priv, txrx_opt_timer_start);
+		txrx_hw_priv = NULL;
+		bes2600_set_txrx_opt_unjoin_param(hw_priv);
+	} else if (priv->if_id == 1) {
+		bes2600_txrx_opt_timer_restore();
+	}
 }
 
 
diff --git a/drivers/staging/bes2600/txrx_opt.h b/drivers/staging/bes2600/txrx_opt.h
index 582ff7fb5221..93c22f4bc5e8 100644
--- a/drivers/staging/bes2600/txrx_opt.h
+++ b/drivers/staging/bes2600/txrx_opt.h
@@ -19,13 +19,20 @@
 #include <linux/list.h>
 /* open it for enhance wifi throughput */
 #define BES2600_TX_RX_OPT   1
+
+/* Threshold for powrt table switch */
+#define BES2600_TX_RSSI_LOW     -65
+#define BES2600_TX_RSSI_HIGH    -60
+
 void bes2600_add_tx_ac_delta_time(int ac, uint32_t del_time);
 void bes2600_add_tx_delta_time(uint32_t tx_time);
 void bes2600_rx_status(struct bes2600_vif *priv, struct sk_buff *skb);
 void bes2600_tx_status(struct bes2600_vif *priv, struct sk_buff *skb);
 void bes2600_dynamic_opt_rxtx(struct bes2600_common *hw_priv,struct bes2600_vif *priv, int rssi);
-int txrx_opt_timer_init(struct bes2600_common *hw_priv);
-int txrx_opt_timer_exit(struct bes2600_common *hw_priv);
+void bes2600_txrx_opt_multivif_connected_handler(struct bes2600_common *hw_priv, bool multivif_connected);
+void bes2600_txrx_opt_timer_restore(void);
+int txrx_opt_timer_init(struct bes2600_vif *priv);
+void txrx_opt_timer_exit(struct bes2600_vif *priv);
 
 #endif
 
diff --git a/drivers/staging/bes2600/wifi_testmode_cmd.c b/drivers/staging/bes2600/wifi_testmode_cmd.c
index 3b3583a6db3d..4022579444be 100644
--- a/drivers/staging/bes2600/wifi_testmode_cmd.c
+++ b/drivers/staging/bes2600/wifi_testmode_cmd.c
@@ -110,6 +110,7 @@ int bes2600_vendor_rf_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u8
 	case VENDOR_RF_NOSIGNALING_CMD:
 	case VENDOR_RF_SAVE_FREQOFFSET_CMD:
 	case VENDOR_RF_SAVE_POWERLEVEL_CMD:
+	case VENDOR_RF_GET_CALI_FROM_EFUSE:
 		sema_init(&hw_priv->vendor_rf_cmd_replay_sema, 0);
 		ret = wsm_vendor_rf_cmd(hw_priv, if_id, vendor_rf_cmd);
 
diff --git a/drivers/staging/bes2600/wsm.c b/drivers/staging/bes2600/wsm.c
index 8ba5ce0a0bb3..3dc8642129ff 100644
--- a/drivers/staging/bes2600/wsm.c
+++ b/drivers/staging/bes2600/wsm.c
@@ -314,6 +314,7 @@ int wsm_vendor_rf_test_indication(struct bes2600_common *hw_priv, struct wsm_buf
 		break;
 	case VENDOR_RF_SIGNALING_CMD:
 	case VENDOR_RF_NOSIGNALING_CMD:
+	case VENDOR_RF_GET_CALI_FROM_EFUSE:
 		bes2600_rf_cmd_msg_assembly(cmd_type, buf->data, wsm_len - sizeof(struct wsm_mcu_hdr));
 		break;
 	default:
@@ -1213,8 +1214,7 @@ nomem:
 	return -ENOMEM;
 }
 
-#ifdef PLAT_ALLWINNER_R329
-int wsm_save_factory_txt_to_flash(struct bes2600_common *hw_priv, const u8 *data, int if_id)
+int wsm_save_factory_txt_to_mcu(struct bes2600_common *hw_priv, const u8 *data, int if_id, enum bes2600_rf_cmd_type cmd_type)
 {
 	int ret, i;
 	const struct factory_t *factory_cali = (const struct factory_t *)data;
@@ -1223,8 +1223,7 @@ int wsm_save_factory_txt_to_flash(struct bes2600_common *hw_priv, const u8 *data
 	wsm_cmd_lock(hw_priv);
 
 	/* cmd type */
-	WSM_PUT32(buf, BES2600_RF_CMD_CALI_TXT_TO_FLASH);
-
+	WSM_PUT32(buf, cmd_type);
 	WSM_PUT32(buf, factory_cali->data.iQ_offset);
 	WSM_PUT16(buf, factory_cali->data.freq_cal);
 
@@ -1253,10 +1252,7 @@ int wsm_save_factory_txt_to_flash(struct bes2600_common *hw_priv, const u8 *data
 nomem:
 	wsm_cmd_unlock(hw_priv);
 	return -ENOMEM;
-
 }
-#endif
-
 /* ******************************************************************** */
 #ifdef MCAST_FWDING
 /* 3.66 */
@@ -1477,6 +1473,7 @@ static int wsm_receive_indication(struct bes2600_common *hw_priv,
 					struct sk_buff **skb_p)
 {
 	struct bes2600_vif *priv;
+	s8 pkt_signal = 0;
 
 	hw_priv->rx_timestamp = jiffies;
 	if (hw_priv->wsm_cbc.rx) {
@@ -1542,8 +1539,23 @@ static int wsm_receive_indication(struct bes2600_common *hw_priv,
 
 		/* If no RSSI subscription has been made,
 		* convert RCPI to RSSI here */
-		if (!priv->cqm_use_rssi)
+		if (!priv->cqm_use_rssi) {
+			pkt_signal = rx.rcpiRssi / 2 - 110;
 			rx.rcpiRssi = rx.rcpiRssi / 2 - 110;
+		}
+
+		if(ieee80211_is_data(hdr->frame_control)) {
+			if (priv->signal == 0) {
+				priv->signal = pkt_signal;
+				priv->signal_mul = pkt_signal * 100;
+			} else {
+				priv->signal_mul = priv->signal_mul * 80 / 100 + pkt_signal * 20;
+				priv->signal = priv->signal_mul / 100;
+			}
+
+			bes2600_dbg(BES2600_DBG_TXRX, "pkt signal:%d\n", priv->signal);
+		}
+
 
 		fctl = *(__le16 *)buf->data;
 		hdr_len = buf->data - buf->begin;
@@ -1579,7 +1591,7 @@ static int wsm_receive_indication(struct bes2600_common *hw_priv,
 							(*skb_p)->len, has_mmie, priv->pmf);
 					if (has_mmie ^ priv->pmf)
 						ignore = true;
-				} else if (ether_addr_equal(hdr->addr1, hw_priv->addresses[rx.if_id].addr)) {
+				} else if (ether_addr_equal(hdr->addr1, priv->vif->addr)) {
 					bool has_protected = ieee80211_has_protected(fctl);
 					bes2600_info(BES2600_DBG_WSM, "[WSM] RX unicast deauth: protected=%d, pmf=%d, connect_in_process=%d\n",
 							has_protected, priv->pmf, atomic_read(&priv->connect_in_process));
@@ -1600,10 +1612,19 @@ static int wsm_receive_indication(struct bes2600_common *hw_priv,
 					bes2600_info(BES2600_DBG_WSM, "[WSM] Issue unjoin command (RX).\n");
 					wsm_lock_tx_async(hw_priv);
 					if (queue_work(hw_priv->workqueue,
-								   &priv->unjoin_work) <= 0)
+								   &priv->unjoin_work) <= 0) {
 						wsm_unlock_tx(hw_priv);
+					}
+#ifdef CONFIG_PM
+					else if(bes2600_suspend_status_get(hw_priv)) {
+						bes2600_pending_unjoin_set(hw_priv, priv->if_id);
+					}
+#endif
+					if (bes2600_chrdev_wakeup_by_event_get() == WAKEUP_EVENT_PEER_DETACH)
+						bes2600_chrdev_wifi_update_wakeup_reason(WAKEUP_REASON_WIFI_DEAUTH_DISASSOC, 0);
 				}
 			}
+			bes2600_chrdev_wakeup_by_event_set(WAKEUP_EVENT_NONE);
 		}
 		hw_priv->wsm_cbc.rx(priv, &rx, skb_p);
 		if (*skb_p)
@@ -2014,7 +2035,7 @@ bool wsm_vif_flush_tx(struct bes2600_vif *priv)
 {
 	struct bes2600_common *hw_priv = priv->hw_priv;
 	unsigned long timestamp = jiffies;
-	long timeout;
+	unsigned long timeout;
 	int i;
 	int if_id = priv->if_id;
 
@@ -2045,11 +2066,17 @@ bool wsm_vif_flush_tx(struct bes2600_vif *priv)
 		if (!hw_priv->hw_bufs_used_vif[if_id])
 			return true;
 
-		timeout = timestamp + WSM_CMD_LAST_CHANCE_TIMEOUT - jiffies;
-		if (timeout < 0 || wait_event_timeout(hw_priv->bh_evt_wq,
+		/* calculate wait time */
+		timeout = timestamp + WSM_CMD_LAST_CHANCE_TIMEOUT;
+		if (timeout >= jiffies)
+			timeout -= jiffies;
+		else
+			timeout += (ULONG_MAX - jiffies);
+
+		/* wait packets on vif to be flushed */
+		if (wait_event_timeout(hw_priv->bh_evt_wq,
 				!hw_priv->hw_bufs_used_vif[if_id],
 				timeout) <= 0) {
-
 			/* Hmmm... Not good. Frame had stuck in firmware. */
 			bes2600_chrdev_wifi_force_close(hw_priv, true);
 		}
@@ -2202,9 +2229,7 @@ int wsm_handle_rx(struct bes2600_common *hw_priv, int id,
 	if (IS_DRIVER_TO_MCU_CMD(id))
 		ind_confirm_label = __le32_to_cpu(((struct wsm_mcu_hdr *)wsm)->handle_label);
 
-	if (id == 0x0C30) {
-		ret = wsm_bt_ts_request(hw_priv, &wsm_buf);
-	} else if (id == 0x404) {
+	if (id == 0x404) {
 		ret = wsm_tx_confirm(hw_priv, &wsm_buf, interface_link_id);
 #ifdef MCAST_FWDING
 #if 1
@@ -2312,10 +2337,10 @@ int wsm_handle_rx(struct bes2600_common *hw_priv, int id,
 		case 0x0C25:
 			ret = wsm_vendor_rf_cmd_confirm(hw_priv, wsm_arg, &wsm_buf);
 			break;
+#endif /* CONFIG_BES2600_TESTMODE */
 		case 0x0C27:
 			ret = wsm_driver_rf_cmd_confirm(hw_priv, wsm_arg, &wsm_buf);
 			break;
-#endif /* CONFIG_BES2600_TESTMODE */
 #ifdef BES_UNIFIED_PM
 		case 0x0424: /* wifi sleep disable */
 			break;
@@ -2408,6 +2433,9 @@ int wsm_handle_rx(struct bes2600_common *hw_priv, int id,
 			ret = wsm_vendor_rf_test_indication(hw_priv, &wsm_buf);
 			break;
 #endif /* CONFIG_BES2600_TESTMODE */
+		case 0x0C30:
+			ret = wsm_bt_ts_request(hw_priv, &wsm_buf);
+			break;
 		default:
 			break;
 		}
@@ -2712,7 +2740,7 @@ static int bes2600_get_prio_queue(struct bes2600_vif *priv,
 		edca = &priv->edca.params[i];
 		score = ((edca->aifns + edca->cwMin) << 16) +
 				(edca->cwMax - edca->cwMin) *
-				(get_random_int() & 0xFFFF);
+				(get_random_long() & 0xFFFF);
 		if (score < best && (winner < 0 || i != 3)) {
 			best = score;
 			winner = i;
@@ -3127,6 +3155,8 @@ static inline int get_interface_id_scanning(struct bes2600_common *hw_priv)
 {
 	if (hw_priv->scan.req)
 		return hw_priv->scan.if_id;
+	else if (hw_priv->scan.direct_probe == 1)
+		return hw_priv->scan.if_id;
 	else
 		return -1;
 }
diff --git a/drivers/staging/bes2600/wsm.h b/drivers/staging/bes2600/wsm.h
index 5bb5bace57ff..8e229a5428e1 100644
--- a/drivers/staging/bes2600/wsm.h
+++ b/drivers/staging/bes2600/wsm.h
@@ -379,6 +379,9 @@ struct bes2600_vif;
 #define WSM_PS_ERROR_AP_SENT_UNICAST_IN_DOZE        3
 #define WSM_PS_ERROR_AP_NO_DATA_AFTER_TIM           4
 
+/* eth filter extended flags */
+#define WSM_ETH_FILTER_EXT_DISABLE_IPV6_MATCH			BIT(0)
+
 /* WSM events */
 /* Error */
 #define WSM_EVENT_ERROR			(0)
@@ -570,6 +573,7 @@ struct bes2600_vif;
 #define WSM_MIB_ID_EXT_TCP_KEEP_ALIVE_PERIOD        (WSM_MIB_ID_EXT_BASE + 2)  /* Mib to set tcp keep alive period */
 #define WSM_MIB_ID_EXT_TX_SHORT_GI_ENABLED          (WSM_MIB_ID_EXT_BASE + 3)  /* Mib to set tx short enabled */
 #define WSM_MIB_ID_EXT_TXRX_OPT_PARAM               (WSM_MIB_ID_EXT_BASE + 4)  /* Mib to set tx/rx opt param to enhance wifi throuhput */
+#define WSM_MIB_ID_EXT_PWR_TBL_UPDATE               (WSM_MIB_ID_EXT_BASE + 5)  /* Mib to update power table */
 
 
 #ifdef IPV6_FILTERING
@@ -591,6 +595,7 @@ struct bes2600_vif;
 
 #ifdef IPV6_FILTERING
 #define WSM_FRAME_TYPE_NA               (7)
+#define WSM_MAX_IPV6_ADDR_FILTER_ELTS	(8)
 #endif /*IPV6_FILTERING*/
 
 #define WSM_FRAME_GREENFIELD		(0x80)	/* See 4.11 */
@@ -653,6 +658,9 @@ struct bes2600_vif;
 #define WSM_FILTER_PORT_TYPE_DST	(0)
 #define WSM_FILTER_PORT_TYPE_SRC	(1)
 
+#define WSM_IP_DATA_FRAME_ADDRMODE_SRC       (0x01)
+#define WSM_IP_DATA_FRAME_ADDRMODE_DEST      (0x02)
+#define WSM_IP_DATA_FRAME_ADDRMODE_TCPACK    (0x03)
 
 
 struct wsm_hdr {
@@ -1538,34 +1546,41 @@ static inline int wsm_set_beacon_filter_table(struct bes2600_common *hw_priv,
 					struct wsm_beacon_filter_table *ft,
 					int if_id)
 {
+	static __le32 numOfIEs;
 	size_t size = __le32_to_cpu(ft->numOfIEs) *
 		     sizeof(struct wsm_beacon_filter_table_entry) +
 		     sizeof(__le32);
 
+	if (numOfIEs == ft->numOfIEs && numOfIEs == 0) {
+		return 0;
+	}
+	numOfIEs = ft->numOfIEs;
 	return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_FILTER_TABLE, ft, size,
 			if_id);
 }
 
 #define WSM_BEACON_FILTER_ENABLE	BIT(0) /* Enable/disable beacon filtering */
 #define WSM_BEACON_FILTER_AUTO_ERP	BIT(1) /* If 1 FW will handle ERP IE changes internally */
+#define WSM_BEACON_FILTER_AUTO_HT	BIT(2) /* If 1 FW will handle HT OP IE changes internally */
 
 struct wsm_beacon_filter_control {
-	int enabled;
-	int bcn_count;
+	__le32 enabled;
+	__le32 bcn_count;
 };
 
 static inline int wsm_beacon_filter_control(struct bes2600_common *hw_priv,
 					struct wsm_beacon_filter_control *arg,
 					int if_id)
 {
-	struct {
-		__le32 enabled;
-		__le32 bcn_count;
-	} val;
-	val.enabled = __cpu_to_le32(arg->enabled);
-	val.bcn_count = __cpu_to_le32(arg->bcn_count);
-	return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_FILTER_ENABLE, &val,
-			     sizeof(val), if_id);
+	static __le32 enabled, bcn_count;
+
+	if (enabled == arg->enabled && bcn_count == arg->bcn_count) {
+		return 0;
+	}
+	enabled = arg->enabled;
+	bcn_count = arg->bcn_count;
+	return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_FILTER_ENABLE, arg,
+			     sizeof(struct wsm_beacon_filter_control), if_id);
 }
 
 enum wsm_power_mode {
@@ -1734,7 +1749,8 @@ static inline int wsm_set_tx_rate_retry_policy(struct bes2600_common *hw_priv,
 /* 4.32 SetEtherTypeDataFrameFilter */
 struct wsm_ether_type_filter_hdr {
 	u8 nrFilters;		/* Up to WSM_MAX_FILTER_ELEMENTS */
-	u8 reserved[3];
+	u8 extFlags;
+	u8 reserved[2];
 } __packed;
 
 struct wsm_ether_type_filter {
@@ -1932,13 +1948,28 @@ struct wsm_ip6_addr_info {
 	u8 ipv6[16];
 };
 
-/* IPV6 Addr Filter */
-struct wsm_ipv6_filter {
+struct wsm_ipv6_filter_header {
 	u8 numfilter;
 	u8 action_mode;
 	u8 Reserved[2];
-	struct wsm_ip6_addr_info ipv6filter[0];
+};
+
+/* IPV6 Addr Filter */
+struct wsm_ipv6_filter {
+	struct wsm_ipv6_filter_header hdr;
+	struct wsm_ip6_addr_info ipv6filter[WSM_MAX_IPV6_ADDR_FILTER_ELTS];
 } __packed;
+
+static inline int wsm_set_ipv6_filter(struct bes2600_common *hw_priv,
+					struct wsm_ipv6_filter_header *arg,
+					int if_id)
+{
+	size_t size = sizeof(struct wsm_ipv6_filter_header) +
+		arg->numfilter * sizeof(struct wsm_ip6_addr_info);
+
+	return wsm_write_mib(hw_priv, WSM_MIB_IP_IPV6_ADDR_FILTER,
+		arg, size, if_id);
+}
 #endif /*IPV6_FILTERING*/
 
 struct wsm_ip4_addr_info {
@@ -2157,6 +2188,7 @@ enum bes2600_rf_cmd_type {
 	BES2600_RF_CMD_CH_INFO           = 1,
 	BES2600_RF_CMD_CPU_USAGE         = 2,
 	BES2600_RF_CMD_WIFI_STATUS       = 3,
+	BES2600_RF_CMD_CALI_TXT_TO_EFUSE = 4,
 	/* add new here */
 
 	BES2600_RF_CMD_MAX,
@@ -2204,8 +2236,7 @@ int wsm_cpu_usage_cmd(struct bes2600_common *hw_priv);
 
 int wsm_wifi_status_cmd(struct bes2600_common *hw_priv, uint32_t status);
 
-#ifdef PLAT_ALLWINNER_R329
-int wsm_save_factory_txt_to_flash(struct bes2600_common *hw_priv, const u8 *data, int if_id);
+#if defined(PLAT_ALLWINNER_R329) || defined(STANDARD_FACTORY_EFUSE_FLAG)
+int wsm_save_factory_txt_to_mcu(struct bes2600_common *hw_priv, const u8 *data, int if_id, enum bes2600_rf_cmd_type cmd_type);
 #endif
-
 #endif /* BES2600_HWIO_H_INCLUDED */
-- 
2.49.0

