Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
diff --git a/MAINTAINERS b/MAINTAINERS
index 3b5fe0c..bf73503 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1568,7 +1568,6 @@
 
 BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
 M:	Brett Rudley <brudley@broadcom.com>
-M:	Henry Ptasinski <henryp@broadcom.com>
 M:	Roland Vossen <rvossen@broadcom.com>
 M:	Arend van Spriel <arend@broadcom.com>
 M:	Franky (Zhenhui) Lin <frankyl@broadcom.com>
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index ee7ea57..8faa129 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -140,23 +140,23 @@
 
 	if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
 		/* Enable WMAC AHB arbitration */
-		reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+		reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 		reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
-		__raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+		iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 
 		/* Enable global WMAC swapping */
-		reg = __raw_readl((void __iomem *) AR5K_AR2315_BYTESWAP);
+		reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
 		reg |= AR5K_AR2315_BYTESWAP_WMAC;
-		__raw_writel(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
+		iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
 	} else {
 		/* Enable WMAC DMA access (assuming 5312 or 231x*/
 		/* TODO: check other platforms */
-		reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+		reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
 		if (to_platform_device(ah->dev)->id == 0)
 			reg |= AR5K_AR5312_ENABLE_WLAN0;
 		else
 			reg |= AR5K_AR5312_ENABLE_WLAN1;
-		__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+		iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
 
 		/*
 		 * On a dual-band AR5312, the multiband radio is only
@@ -203,17 +203,17 @@
 
 	if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
 		/* Disable WMAC AHB arbitration */
-		reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+		reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 		reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
-		__raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+		iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 	} else {
 		/*Stop DMA access */
-		reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+		reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
 		if (to_platform_device(ah->dev)->id == 0)
 			reg &= ~AR5K_AR5312_ENABLE_WLAN0;
 		else
 			reg &= ~AR5K_AR5312_ENABLE_WLAN1;
-		__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+		iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
 	}
 
 	ath5k_deinit_ah(ah);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index c2b2518..6640326 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1656,12 +1656,12 @@
 
 static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
 {
-	return __raw_readl(ath5k_ahb_reg(ah, reg));
+	return ioread32(ath5k_ahb_reg(ah, reg));
 }
 
 static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
 {
-	__raw_writel(val, ath5k_ahb_reg(ah, reg));
+	iowrite32(val, ath5k_ahb_reg(ah, reg));
 }
 
 #else
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 250db40..200f165 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -473,14 +473,14 @@
 	}
 
 	/* Put BB/MAC into reset */
-	regval = __raw_readl(reg);
-	__raw_writel(regval | val, reg);
-	regval = __raw_readl(reg);
+	regval = ioread32(reg);
+	iowrite32(regval | val, reg);
+	regval = ioread32(reg);
 	usleep_range(100, 150);
 
 	/* Bring BB/MAC out of reset */
-	__raw_writel(regval & ~val, reg);
-	regval = __raw_readl(reg);
+	iowrite32(regval & ~val, reg);
+	regval = ioread32(reg);
 
 	/*
 	 * Reset configuration register (for hw byte-swap). Note that this
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index d1922d8..5370333 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2269,8 +2269,42 @@
 	return ret;
 }
 
-static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
-			    struct beacon_parameters *info, bool add)
+static int ath6kl_set_ies(struct ath6kl_vif *vif,
+			  struct cfg80211_beacon_data *info)
+{
+	struct ath6kl *ar = vif->ar;
+	int res;
+
+	if (info->beacon_ies) {
+		res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
+					       WMI_FRAME_BEACON,
+					       info->beacon_ies,
+					       info->beacon_ies_len);
+		if (res)
+			return res;
+	}
+
+	if (info->proberesp_ies) {
+		res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
+						   info->proberesp_ies_len);
+		if (res)
+			return res;
+	}
+
+	if (info->assocresp_ies) {
+		res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
+					       WMI_FRAME_ASSOC_RESP,
+					       info->assocresp_ies,
+					       info->assocresp_ies_len);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
+			   struct cfg80211_ap_settings *info)
 {
 	struct ath6kl *ar = ath6kl_priv(dev);
 	struct ath6kl_vif *vif = netdev_priv(dev);
@@ -2281,7 +2315,7 @@
 	int res;
 	int i, ret;
 
-	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
 
 	if (!ath6kl_cfg80211_ready(vif))
 		return -EIO;
@@ -2289,31 +2323,7 @@
 	if (vif->next_mode != AP_NETWORK)
 		return -EOPNOTSUPP;
 
-	if (info->beacon_ies) {
-		res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
-					       WMI_FRAME_BEACON,
-					       info->beacon_ies,
-					       info->beacon_ies_len);
-		if (res)
-			return res;
-	}
-	if (info->proberesp_ies) {
-		res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
-						   info->proberesp_ies_len);
-		if (res)
-			return res;
-	}
-	if (info->assocresp_ies) {
-		res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
-					       WMI_FRAME_ASSOC_RESP,
-					       info->assocresp_ies,
-					       info->assocresp_ies_len);
-		if (res)
-			return res;
-	}
-
-	if (!add)
-		return 0;
+	res = ath6kl_set_ies(vif, &info->beacon);
 
 	ar->ap_mode_bkey.valid = false;
 
@@ -2322,13 +2332,13 @@
 	 * info->dtim_period
 	 */
 
-	if (info->head == NULL)
+	if (info->beacon.head == NULL)
 		return -EINVAL;
-	mgmt = (struct ieee80211_mgmt *) info->head;
+	mgmt = (struct ieee80211_mgmt *) info->beacon.head;
 	ies = mgmt->u.beacon.variable;
-	if (ies > info->head + info->head_len)
+	if (ies > info->beacon.head + info->beacon.head_len)
 		return -EINVAL;
-	ies_len = info->head + info->head_len - ies;
+	ies_len = info->beacon.head + info->beacon.head_len - ies;
 
 	if (info->ssid == NULL)
 		return -EINVAL;
@@ -2436,19 +2446,21 @@
 	return 0;
 }
 
-static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
-			     struct beacon_parameters *info)
+static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
+				struct cfg80211_beacon_data *beacon)
 {
-	return ath6kl_ap_beacon(wiphy, dev, info, true);
+	struct ath6kl_vif *vif = netdev_priv(dev);
+
+	if (!ath6kl_cfg80211_ready(vif))
+		return -EIO;
+
+	if (vif->next_mode != AP_NETWORK)
+		return -EOPNOTSUPP;
+
+	return ath6kl_set_ies(vif, beacon);
 }
 
-static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
-			     struct beacon_parameters *info)
-{
-	return ath6kl_ap_beacon(wiphy, dev, info, false);
-}
-
-static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 {
 	struct ath6kl *ar = ath6kl_priv(dev);
 	struct ath6kl_vif *vif = netdev_priv(dev);
@@ -2783,9 +2795,9 @@
 	.resume = __ath6kl_cfg80211_resume,
 #endif
 	.set_channel = ath6kl_set_channel,
-	.add_beacon = ath6kl_add_beacon,
-	.set_beacon = ath6kl_set_beacon,
-	.del_beacon = ath6kl_del_beacon,
+	.start_ap = ath6kl_start_ap,
+	.change_beacon = ath6kl_change_beacon,
+	.stop_ap = ath6kl_stop_ap,
 	.del_station = ath6kl_del_station,
 	.change_station = ath6kl_change_station,
 	.remain_on_channel = ath6kl_remain_on_channel,
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index dc6be4a..595a272 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -6,6 +6,14 @@
 	def_bool y
 	depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED
 
+config ATH9K_BTCOEX_SUPPORT
+	bool "Atheros bluetooth coexistence support"
+	depends on (ATH9K || ATH9K_HTC)
+	default y
+	---help---
+	  Say Y, if you want to use the ath9k/ath9k_htc radios together with
+	  Bluetooth modules in the same system.
+
 config ATH9K
 	tristate "Atheros 802.11n wireless cards support"
 	depends on MAC80211
@@ -81,14 +89,6 @@
 	  Say Y, if you want to use the ath9k specific rate control
 	  module instead of minstrel_ht.
 
-config ATH9K_BTCOEX_SUPPORT
-	bool "Atheros ath9k bluetooth coexistence support"
-	depends on ATH9K
-	default y
-	---help---
-	  Say Y, if you want to use the ath9k radios together with
-	  Bluetooth modules in the same system.
-
 config ATH9K_HTC
        tristate "Atheros HTC based wireless cards support"
        depends on USB && MAC80211
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index da02242..27d95fe 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -3,9 +3,9 @@
 		init.o \
 		main.o \
 		recv.o \
-		xmit.o \
-		mci.o \
+		xmit.o
 
+ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
 ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
 ath9k-$(CONFIG_ATH9K_PCI) += pci.o
 ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
@@ -31,14 +31,14 @@
 		eeprom_4k.o \
 		eeprom_9287.o \
 		ani.o \
-		btcoex.o \
 		mac.o \
 		ar9002_mac.o \
 		ar9003_mac.o \
 		ar9003_eeprom.o \
-		ar9003_paprd.o \
-		ar9003_mci.o
+		ar9003_paprd.o
 
+ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
+					   ar9003_mci.o
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
 
 obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
index e8bdc75..ea4a230 100644
--- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
@@ -459,97 +459,6 @@
 	{0x0000a3e0, 0x000001ce},
 };
 
-static const u32 ar5416Bank0_9100[][2] = {
-	/* Addr      allmodes  */
-	{0x000098b0, 0x1e5795e5},
-	{0x000098e0, 0x02008020},
-};
-
-static const u32 ar5416BB_RfGain_9100[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
-	{0x00009a00, 0x00000000, 0x00000000},
-	{0x00009a04, 0x00000040, 0x00000040},
-	{0x00009a08, 0x00000080, 0x00000080},
-	{0x00009a0c, 0x000001a1, 0x00000141},
-	{0x00009a10, 0x000001e1, 0x00000181},
-	{0x00009a14, 0x00000021, 0x000001c1},
-	{0x00009a18, 0x00000061, 0x00000001},
-	{0x00009a1c, 0x00000168, 0x00000041},
-	{0x00009a20, 0x000001a8, 0x000001a8},
-	{0x00009a24, 0x000001e8, 0x000001e8},
-	{0x00009a28, 0x00000028, 0x00000028},
-	{0x00009a2c, 0x00000068, 0x00000068},
-	{0x00009a30, 0x00000189, 0x000000a8},
-	{0x00009a34, 0x000001c9, 0x00000169},
-	{0x00009a38, 0x00000009, 0x000001a9},
-	{0x00009a3c, 0x00000049, 0x000001e9},
-	{0x00009a40, 0x00000089, 0x00000029},
-	{0x00009a44, 0x00000170, 0x00000069},
-	{0x00009a48, 0x000001b0, 0x00000190},
-	{0x00009a4c, 0x000001f0, 0x000001d0},
-	{0x00009a50, 0x00000030, 0x00000010},
-	{0x00009a54, 0x00000070, 0x00000050},
-	{0x00009a58, 0x00000191, 0x00000090},
-	{0x00009a5c, 0x000001d1, 0x00000151},
-	{0x00009a60, 0x00000011, 0x00000191},
-	{0x00009a64, 0x00000051, 0x000001d1},
-	{0x00009a68, 0x00000091, 0x00000011},
-	{0x00009a6c, 0x000001b8, 0x00000051},
-	{0x00009a70, 0x000001f8, 0x00000198},
-	{0x00009a74, 0x00000038, 0x000001d8},
-	{0x00009a78, 0x00000078, 0x00000018},
-	{0x00009a7c, 0x00000199, 0x00000058},
-	{0x00009a80, 0x000001d9, 0x00000098},
-	{0x00009a84, 0x00000019, 0x00000159},
-	{0x00009a88, 0x00000059, 0x00000199},
-	{0x00009a8c, 0x00000099, 0x000001d9},
-	{0x00009a90, 0x000000d9, 0x00000019},
-	{0x00009a94, 0x000000f9, 0x00000059},
-	{0x00009a98, 0x000000f9, 0x00000099},
-	{0x00009a9c, 0x000000f9, 0x000000d9},
-	{0x00009aa0, 0x000000f9, 0x000000f9},
-	{0x00009aa4, 0x000000f9, 0x000000f9},
-	{0x00009aa8, 0x000000f9, 0x000000f9},
-	{0x00009aac, 0x000000f9, 0x000000f9},
-	{0x00009ab0, 0x000000f9, 0x000000f9},
-	{0x00009ab4, 0x000000f9, 0x000000f9},
-	{0x00009ab8, 0x000000f9, 0x000000f9},
-	{0x00009abc, 0x000000f9, 0x000000f9},
-	{0x00009ac0, 0x000000f9, 0x000000f9},
-	{0x00009ac4, 0x000000f9, 0x000000f9},
-	{0x00009ac8, 0x000000f9, 0x000000f9},
-	{0x00009acc, 0x000000f9, 0x000000f9},
-	{0x00009ad0, 0x000000f9, 0x000000f9},
-	{0x00009ad4, 0x000000f9, 0x000000f9},
-	{0x00009ad8, 0x000000f9, 0x000000f9},
-	{0x00009adc, 0x000000f9, 0x000000f9},
-	{0x00009ae0, 0x000000f9, 0x000000f9},
-	{0x00009ae4, 0x000000f9, 0x000000f9},
-	{0x00009ae8, 0x000000f9, 0x000000f9},
-	{0x00009aec, 0x000000f9, 0x000000f9},
-	{0x00009af0, 0x000000f9, 0x000000f9},
-	{0x00009af4, 0x000000f9, 0x000000f9},
-	{0x00009af8, 0x000000f9, 0x000000f9},
-	{0x00009afc, 0x000000f9, 0x000000f9},
-};
-
-static const u32 ar5416Bank1_9100[][2] = {
-	/* Addr      allmodes  */
-	{0x000098b0, 0x02108421},
-	{0x000098ec, 0x00000008},
-};
-
-static const u32 ar5416Bank2_9100[][2] = {
-	/* Addr      allmodes  */
-	{0x000098b0, 0x0e73ff17},
-	{0x000098e0, 0x00000420},
-};
-
-static const u32 ar5416Bank3_9100[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
-	{0x000098f0, 0x01400018, 0x01c00018},
-};
-
 static const u32 ar5416Bank6_9100[][3] = {
 	/* Addr      5G_HT20     5G_HT40   */
 	{0x0000989c, 0x00000000, 0x00000000},
@@ -624,13 +533,6 @@
 	{0x000098d0, 0x0000000f, 0x0010000f},
 };
 
-static const u32 ar5416Bank7_9100[][2] = {
-	/* Addr      allmodes  */
-	{0x0000989c, 0x00000500},
-	{0x0000989c, 0x00000800},
-	{0x000098cc, 0x0000000e},
-};
-
 static const u32 ar5416Addac_9100[][2] = {
 	/* Addr      allmodes  */
 	{0x0000989c, 0x00000000},
@@ -1113,178 +1015,6 @@
 	{0x0000a3e0, 0x000001ce},
 };
 
-static const u32 ar5416Bank0_9160[][2] = {
-	/* Addr      allmodes  */
-	{0x000098b0, 0x1e5795e5},
-	{0x000098e0, 0x02008020},
-};
-
-static const u32 ar5416BB_RfGain_9160[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
-	{0x00009a00, 0x00000000, 0x00000000},
-	{0x00009a04, 0x00000040, 0x00000040},
-	{0x00009a08, 0x00000080, 0x00000080},
-	{0x00009a0c, 0x000001a1, 0x00000141},
-	{0x00009a10, 0x000001e1, 0x00000181},
-	{0x00009a14, 0x00000021, 0x000001c1},
-	{0x00009a18, 0x00000061, 0x00000001},
-	{0x00009a1c, 0x00000168, 0x00000041},
-	{0x00009a20, 0x000001a8, 0x000001a8},
-	{0x00009a24, 0x000001e8, 0x000001e8},
-	{0x00009a28, 0x00000028, 0x00000028},
-	{0x00009a2c, 0x00000068, 0x00000068},
-	{0x00009a30, 0x00000189, 0x000000a8},
-	{0x00009a34, 0x000001c9, 0x00000169},
-	{0x00009a38, 0x00000009, 0x000001a9},
-	{0x00009a3c, 0x00000049, 0x000001e9},
-	{0x00009a40, 0x00000089, 0x00000029},
-	{0x00009a44, 0x00000170, 0x00000069},
-	{0x00009a48, 0x000001b0, 0x00000190},
-	{0x00009a4c, 0x000001f0, 0x000001d0},
-	{0x00009a50, 0x00000030, 0x00000010},
-	{0x00009a54, 0x00000070, 0x00000050},
-	{0x00009a58, 0x00000191, 0x00000090},
-	{0x00009a5c, 0x000001d1, 0x00000151},
-	{0x00009a60, 0x00000011, 0x00000191},
-	{0x00009a64, 0x00000051, 0x000001d1},
-	{0x00009a68, 0x00000091, 0x00000011},
-	{0x00009a6c, 0x000001b8, 0x00000051},
-	{0x00009a70, 0x000001f8, 0x00000198},
-	{0x00009a74, 0x00000038, 0x000001d8},
-	{0x00009a78, 0x00000078, 0x00000018},
-	{0x00009a7c, 0x00000199, 0x00000058},
-	{0x00009a80, 0x000001d9, 0x00000098},
-	{0x00009a84, 0x00000019, 0x00000159},
-	{0x00009a88, 0x00000059, 0x00000199},
-	{0x00009a8c, 0x00000099, 0x000001d9},
-	{0x00009a90, 0x000000d9, 0x00000019},
-	{0x00009a94, 0x000000f9, 0x00000059},
-	{0x00009a98, 0x000000f9, 0x00000099},
-	{0x00009a9c, 0x000000f9, 0x000000d9},
-	{0x00009aa0, 0x000000f9, 0x000000f9},
-	{0x00009aa4, 0x000000f9, 0x000000f9},
-	{0x00009aa8, 0x000000f9, 0x000000f9},
-	{0x00009aac, 0x000000f9, 0x000000f9},
-	{0x00009ab0, 0x000000f9, 0x000000f9},
-	{0x00009ab4, 0x000000f9, 0x000000f9},
-	{0x00009ab8, 0x000000f9, 0x000000f9},
-	{0x00009abc, 0x000000f9, 0x000000f9},
-	{0x00009ac0, 0x000000f9, 0x000000f9},
-	{0x00009ac4, 0x000000f9, 0x000000f9},
-	{0x00009ac8, 0x000000f9, 0x000000f9},
-	{0x00009acc, 0x000000f9, 0x000000f9},
-	{0x00009ad0, 0x000000f9, 0x000000f9},
-	{0x00009ad4, 0x000000f9, 0x000000f9},
-	{0x00009ad8, 0x000000f9, 0x000000f9},
-	{0x00009adc, 0x000000f9, 0x000000f9},
-	{0x00009ae0, 0x000000f9, 0x000000f9},
-	{0x00009ae4, 0x000000f9, 0x000000f9},
-	{0x00009ae8, 0x000000f9, 0x000000f9},
-	{0x00009aec, 0x000000f9, 0x000000f9},
-	{0x00009af0, 0x000000f9, 0x000000f9},
-	{0x00009af4, 0x000000f9, 0x000000f9},
-	{0x00009af8, 0x000000f9, 0x000000f9},
-	{0x00009afc, 0x000000f9, 0x000000f9},
-};
-
-static const u32 ar5416Bank1_9160[][2] = {
-	/* Addr      allmodes  */
-	{0x000098b0, 0x02108421},
-	{0x000098ec, 0x00000008},
-};
-
-static const u32 ar5416Bank2_9160[][2] = {
-	/* Addr      allmodes  */
-	{0x000098b0, 0x0e73ff17},
-	{0x000098e0, 0x00000420},
-};
-
-static const u32 ar5416Bank3_9160[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
-	{0x000098f0, 0x01400018, 0x01c00018},
-};
-
-static const u32 ar5416Bank6_9160[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
-	{0x0000989c, 0x00000000, 0x00000000},
-	{0x0000989c, 0x00000000, 0x00000000},
-	{0x0000989c, 0x00000000, 0x00000000},
-	{0x0000989c, 0x00e00000, 0x00e00000},
-	{0x0000989c, 0x005e0000, 0x005e0000},
-	{0x0000989c, 0x00120000, 0x00120000},
-	{0x0000989c, 0x00620000, 0x00620000},
-	{0x0000989c, 0x00020000, 0x00020000},
-	{0x0000989c, 0x00ff0000, 0x00ff0000},
-	{0x0000989c, 0x00ff0000, 0x00ff0000},
-	{0x0000989c, 0x00ff0000, 0x00ff0000},
-	{0x0000989c, 0x40ff0000, 0x40ff0000},
-	{0x0000989c, 0x005f0000, 0x005f0000},
-	{0x0000989c, 0x00870000, 0x00870000},
-	{0x0000989c, 0x00f90000, 0x00f90000},
-	{0x0000989c, 0x007b0000, 0x007b0000},
-	{0x0000989c, 0x00ff0000, 0x00ff0000},
-	{0x0000989c, 0x00f50000, 0x00f50000},
-	{0x0000989c, 0x00dc0000, 0x00dc0000},
-	{0x0000989c, 0x00110000, 0x00110000},
-	{0x0000989c, 0x006100a8, 0x006100a8},
-	{0x0000989c, 0x004210a2, 0x004210a2},
-	{0x0000989c, 0x0014008f, 0x0014008f},
-	{0x0000989c, 0x00c40003, 0x00c40003},
-	{0x0000989c, 0x003000f2, 0x003000f2},
-	{0x0000989c, 0x00440016, 0x00440016},
-	{0x0000989c, 0x00410040, 0x00410040},
-	{0x0000989c, 0x0001805e, 0x0001805e},
-	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
-	{0x0000989c, 0x000000f1, 0x000000f1},
-	{0x0000989c, 0x00002081, 0x00002081},
-	{0x0000989c, 0x000000d4, 0x000000d4},
-	{0x000098d0, 0x0000000f, 0x0010000f},
-};
-
-static const u32 ar5416Bank6TPC_9160[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
-	{0x0000989c, 0x00000000, 0x00000000},
-	{0x0000989c, 0x00000000, 0x00000000},
-	{0x0000989c, 0x00000000, 0x00000000},
-	{0x0000989c, 0x00e00000, 0x00e00000},
-	{0x0000989c, 0x005e0000, 0x005e0000},
-	{0x0000989c, 0x00120000, 0x00120000},
-	{0x0000989c, 0x00620000, 0x00620000},
-	{0x0000989c, 0x00020000, 0x00020000},
-	{0x0000989c, 0x00ff0000, 0x00ff0000},
-	{0x0000989c, 0x00ff0000, 0x00ff0000},
-	{0x0000989c, 0x00ff0000, 0x00ff0000},
-	{0x0000989c, 0x40ff0000, 0x40ff0000},
-	{0x0000989c, 0x005f0000, 0x005f0000},
-	{0x0000989c, 0x00870000, 0x00870000},
-	{0x0000989c, 0x00f90000, 0x00f90000},
-	{0x0000989c, 0x007b0000, 0x007b0000},
-	{0x0000989c, 0x00ff0000, 0x00ff0000},
-	{0x0000989c, 0x00f50000, 0x00f50000},
-	{0x0000989c, 0x00dc0000, 0x00dc0000},
-	{0x0000989c, 0x00110000, 0x00110000},
-	{0x0000989c, 0x006100a8, 0x006100a8},
-	{0x0000989c, 0x00423022, 0x00423022},
-	{0x0000989c, 0x2014008f, 0x2014008f},
-	{0x0000989c, 0x00c40002, 0x00c40002},
-	{0x0000989c, 0x003000f2, 0x003000f2},
-	{0x0000989c, 0x00440016, 0x00440016},
-	{0x0000989c, 0x00410040, 0x00410040},
-	{0x0000989c, 0x0001805e, 0x0001805e},
-	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
-	{0x0000989c, 0x000000e1, 0x000000e1},
-	{0x0000989c, 0x00007080, 0x00007080},
-	{0x0000989c, 0x000000d4, 0x000000d4},
-	{0x000098d0, 0x0000000f, 0x0010000f},
-};
-
-static const u32 ar5416Bank7_9160[][2] = {
-	/* Addr      allmodes  */
-	{0x0000989c, 0x00000500},
-	{0x0000989c, 0x00000800},
-	{0x000098cc, 0x0000000e},
-};
-
 static const u32 ar5416Addac_9160[][2] = {
 	/* Addr      allmodes  */
 	{0x0000989c, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index d190411..e3f2689 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -35,11 +35,11 @@
 		INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271,
 			       ARRAY_SIZE(ar9271Common_9271), 2);
 		INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271,
-			       ar9271Common_normal_cck_fir_coeff_9271,
-			       ARRAY_SIZE(ar9271Common_normal_cck_fir_coeff_9271), 2);
+			       ar9287Common_normal_cck_fir_coeff_9287_1_1,
+			       ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_9287_1_1), 2);
 		INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271,
-			       ar9271Common_japan_2484_cck_fir_coeff_9271,
-			       ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2);
+			       ar9287Common_japan_2484_cck_fir_coeff_9287_1_1,
+			       ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_9287_1_1), 2);
 		INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only,
 			       ar9271Modes_9271_1_0_only,
 			       ARRAY_SIZE(ar9271Modes_9271_1_0_only), 5);
@@ -54,53 +54,31 @@
 		return;
 	}
 
+	if (ah->config.pcie_clock_req)
+		INIT_INI_ARRAY(&ah->iniPcieSerdes,
+			   ar9280PciePhy_clkreq_off_L1_9280,
+			   ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2);
+	else
+		INIT_INI_ARRAY(&ah->iniPcieSerdes,
+			   ar9280PciePhy_clkreq_always_on_L1_9280,
+			   ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
+
 	if (AR_SREV_9287_11_OR_LATER(ah)) {
 		INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
 				ARRAY_SIZE(ar9287Modes_9287_1_1), 5);
 		INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
 				ARRAY_SIZE(ar9287Common_9287_1_1), 2);
-		if (ah->config.pcie_clock_req)
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			ar9287PciePhy_clkreq_off_L1_9287_1_1,
-			ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
-		else
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
-			ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
-					2);
 	} else if (AR_SREV_9285_12_OR_LATER(ah)) {
-
-
 		INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
 			       ARRAY_SIZE(ar9285Modes_9285_1_2), 5);
 		INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
 			       ARRAY_SIZE(ar9285Common_9285_1_2), 2);
-
-		if (ah->config.pcie_clock_req) {
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			ar9285PciePhy_clkreq_off_L1_9285_1_2,
-			ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
-		} else {
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
-			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
-				  2);
-		}
 	} else if (AR_SREV_9280_20_OR_LATER(ah)) {
 		INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
 			       ARRAY_SIZE(ar9280Modes_9280_2), 5);
 		INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
 			       ARRAY_SIZE(ar9280Common_9280_2), 2);
 
-		if (ah->config.pcie_clock_req) {
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			       ar9280PciePhy_clkreq_off_L1_9280,
-			       ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2);
-		} else {
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			       ar9280PciePhy_clkreq_always_on_L1_9280,
-			       ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
-		}
 		INIT_INI_ARRAY(&ah->iniModesAdditional,
 			       ar9280Modes_fast_clock_9280_2,
 			       ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
@@ -109,22 +87,6 @@
 			       ARRAY_SIZE(ar5416Modes_9160), 5);
 		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160,
 			       ARRAY_SIZE(ar5416Common_9160), 2);
-		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160,
-			       ARRAY_SIZE(ar5416Bank0_9160), 2);
-		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160,
-			       ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
-		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160,
-			       ARRAY_SIZE(ar5416Bank1_9160), 2);
-		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160,
-			       ARRAY_SIZE(ar5416Bank2_9160), 2);
-		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160,
-			       ARRAY_SIZE(ar5416Bank3_9160), 3);
-		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160,
-			       ARRAY_SIZE(ar5416Bank6_9160), 3);
-		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160,
-			       ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
-		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160,
-			       ARRAY_SIZE(ar5416Bank7_9160), 2);
 		if (AR_SREV_9160_11(ah)) {
 			INIT_INI_ARRAY(&ah->iniAddac,
 				       ar5416Addac_9160_1_1,
@@ -138,22 +100,8 @@
 			       ARRAY_SIZE(ar5416Modes_9100), 5);
 		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100,
 			       ARRAY_SIZE(ar5416Common_9100), 2);
-		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100,
-			       ARRAY_SIZE(ar5416Bank0_9100), 2);
-		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100,
-			       ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
-		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100,
-			       ARRAY_SIZE(ar5416Bank1_9100), 2);
-		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100,
-			       ARRAY_SIZE(ar5416Bank2_9100), 2);
-		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100,
-			       ARRAY_SIZE(ar5416Bank3_9100), 3);
 		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100,
 			       ARRAY_SIZE(ar5416Bank6_9100), 3);
-		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
-			       ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
-		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100,
-			       ARRAY_SIZE(ar5416Bank7_9100), 2);
 		INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100,
 			       ARRAY_SIZE(ar5416Addac_9100), 2);
 	} else {
@@ -161,24 +109,37 @@
 			       ARRAY_SIZE(ar5416Modes), 5);
 		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common,
 			       ARRAY_SIZE(ar5416Common), 2);
-		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
-			       ARRAY_SIZE(ar5416Bank0), 2);
+		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
+			       ARRAY_SIZE(ar5416Bank6TPC), 3);
+		INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
+			       ARRAY_SIZE(ar5416Addac), 2);
+	}
+
+	if (!AR_SREV_9280_20_OR_LATER(ah)) {
+		/* Common for AR5416, AR913x, AR9160 */
 		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain,
 			       ARRAY_SIZE(ar5416BB_RfGain), 3);
+
+		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
+			       ARRAY_SIZE(ar5416Bank0), 2);
 		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1,
 			       ARRAY_SIZE(ar5416Bank1), 2);
 		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2,
 			       ARRAY_SIZE(ar5416Bank2), 2);
 		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3,
 			       ARRAY_SIZE(ar5416Bank3), 3);
-		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
-			       ARRAY_SIZE(ar5416Bank6), 3);
-		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
-			       ARRAY_SIZE(ar5416Bank6TPC), 3);
 		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7,
 			       ARRAY_SIZE(ar5416Bank7), 2);
-		INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
-			       ARRAY_SIZE(ar5416Addac), 2);
+
+		/* Common for AR5416, AR9160 */
+		if (!AR_SREV_9100(ah))
+			INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
+				       ARRAY_SIZE(ar5416Bank6), 3);
+
+		/* Common for AR913x, AR9160 */
+		if (!AR_SREV_5416(ah))
+			INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
+				       ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
 	}
 
 	/* iniAddac needs to be modified for these chips */
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
index 863db32..d571c32 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
@@ -925,34 +925,6 @@
 	{0x00004044, 0x00000000},
 };
 
-static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
-	/* Addr      allmodes  */
-	{0x00004040, 0x9248fd00},
-	{0x00004040, 0x24924924},
-	{0x00004040, 0xa8000019},
-	{0x00004040, 0x13160820},
-	{0x00004040, 0xe5980560},
-	{0x00004040, 0xc01dcffd},
-	{0x00004040, 0x1aaabe41},
-	{0x00004040, 0xbe105554},
-	{0x00004040, 0x00043007},
-	{0x00004044, 0x00000000},
-};
-
-static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = {
-	/* Addr      allmodes  */
-	{0x00004040, 0x9248fd00},
-	{0x00004040, 0x24924924},
-	{0x00004040, 0xa8000019},
-	{0x00004040, 0x13160820},
-	{0x00004040, 0xe5980560},
-	{0x00004040, 0xc01dcffc},
-	{0x00004040, 0x1aaabe41},
-	{0x00004040, 0xbe105554},
-	{0x00004040, 0x00043007},
-	{0x00004044, 0x00000000},
-};
-
 static const u32 ar9285Modes_9285_1_2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
@@ -1743,34 +1715,6 @@
 	{0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
 };
 
-static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
-	/* Addr      allmodes  */
-	{0x00004040, 0x9248fd00},
-	{0x00004040, 0x24924924},
-	{0x00004040, 0xa8000019},
-	{0x00004040, 0x13160820},
-	{0x00004040, 0xe5980560},
-	{0x00004040, 0xc01dcffd},
-	{0x00004040, 0x1aaabe41},
-	{0x00004040, 0xbe105554},
-	{0x00004040, 0x00043007},
-	{0x00004044, 0x00000000},
-};
-
-static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
-	/* Addr      allmodes  */
-	{0x00004040, 0x9248fd00},
-	{0x00004040, 0x24924924},
-	{0x00004040, 0xa8000019},
-	{0x00004040, 0x13160820},
-	{0x00004040, 0xe5980560},
-	{0x00004040, 0xc01dcffc},
-	{0x00004040, 0x1aaabe41},
-	{0x00004040, 0xbe105554},
-	{0x00004040, 0x00043007},
-	{0x00004044, 0x00000000},
-};
-
 static const u32 ar9287Modes_9287_1_1[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160},
@@ -2512,34 +2456,6 @@
 	{0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067},
 };
 
-static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
-	/* Addr      allmodes  */
-	{0x00004040, 0x9248fd00},
-	{0x00004040, 0x24924924},
-	{0x00004040, 0xa8000019},
-	{0x00004040, 0x13160820},
-	{0x00004040, 0xe5980560},
-	{0x00004040, 0xc01dcffd},
-	{0x00004040, 0x1aaabe41},
-	{0x00004040, 0xbe105554},
-	{0x00004040, 0x00043007},
-	{0x00004044, 0x00000000},
-};
-
-static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
-	/* Addr      allmodes  */
-	{0x00004040, 0x9248fd00},
-	{0x00004040, 0x24924924},
-	{0x00004040, 0xa8000019},
-	{0x00004040, 0x13160820},
-	{0x00004040, 0xe5980560},
-	{0x00004040, 0xc01dcffc},
-	{0x00004040, 0x1aaabe41},
-	{0x00004040, 0xbe105554},
-	{0x00004040, 0x00043007},
-	{0x00004044, 0x00000000},
-};
-
 static const u32 ar9271Modes_9271[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
@@ -3176,20 +3092,6 @@
 	{0x0000d384, 0xf3307ff0},
 };
 
-static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a1f4, 0x00fffeff},
-	{0x0000a1f8, 0x00f5f9ff},
-	{0x0000a1fc, 0xb79f6427},
-};
-
-static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a1f4, 0x00000000},
-	{0x0000a1f8, 0xefff0301},
-	{0x0000a1fc, 0xca9228ee},
-};
-
 static const u32 ar9271Modes_9271_1_0_only[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 8e70f0b..63089cc 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -925,7 +925,6 @@
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_cal_data *caldata = ah->caldata;
-	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 	bool txiqcal_done = false, txclcal_done = false;
 	bool is_reusable = true, status = true;
 	bool run_rtt_cal = false, run_agc_cal;
@@ -998,30 +997,8 @@
 	} else if (caldata && !caldata->done_txiqcal_once)
 		run_agc_cal = true;
 
-	if (mci && IS_CHAN_2GHZ(chan) &&
-	    (mci_hw->bt_state  == MCI_BT_AWAKE) &&
-	    run_agc_cal &&
-	    !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
-
-		u32 pld[4] = {0, 0, 0, 0};
-
-		/* send CAL_REQ only when BT is AWAKE. */
-		ath_dbg(common, MCI, "MCI send WLAN_CAL_REQ 0x%x\n",
-			mci_hw->wlan_cal_seq);
-		MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
-		pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
-		ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
-
-		/* Wait BT_CAL_GRANT for 50ms */
-		ath_dbg(common, MCI, "MCI wait for BT_CAL_GRANT\n");
-
-		if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000))
-			ath_dbg(common, MCI, "MCI got BT_CAL_GRANT\n");
-		else {
-			is_reusable = false;
-			ath_dbg(common, MCI, "\nMCI BT is not responding\n");
-		}
-	}
+	if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+		ar9003_mci_init_cal_req(ah, &is_reusable);
 
 	txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
 	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
@@ -1041,19 +1018,8 @@
 				       0, AH_WAIT_TIMEOUT);
 	}
 
-	if (mci && IS_CHAN_2GHZ(chan) &&
-	    (mci_hw->bt_state  == MCI_BT_AWAKE)	&&
-	    run_agc_cal	&&
-	    !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
-
-		u32 pld[4] = {0, 0, 0, 0};
-
-		ath_dbg(common, MCI, "MCI Send WLAN_CAL_DONE 0x%x\n",
-			mci_hw->wlan_cal_done);
-		MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
-		pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
-		ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
-	}
+	if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+		ar9003_mci_init_cal_done(ah);
 
 	if (rtt && !run_rtt_cal) {
 		agc_ctrl |= agc_supp_cals;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 9fbcbdd..6bb4db0 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3603,10 +3603,6 @@
 	u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
 
 	if (AR_SREV_9462(ah)) {
-		if (AR_SREV_9462_10(ah)) {
-			value &= ~AR_SWITCH_TABLE_COM_SPDT;
-			value |= 0x00100000;
-		}
 		REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
 				AR_SWITCH_TABLE_COM_AR9462_ALL, value);
 	} else
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index fb937ba..7b4aa00 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -22,7 +22,6 @@
 #include "ar9330_1p1_initvals.h"
 #include "ar9330_1p2_initvals.h"
 #include "ar9580_1p0_initvals.h"
-#include "ar9462_1p0_initvals.h"
 #include "ar9462_2p0_initvals.h"
 
 /* General hardware code for the AR9003 hadware family */
@@ -264,63 +263,6 @@
 				ar9485_1_1_pcie_phy_clkreq_disable_L1,
 				ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
 				2);
-	} else if (AR_SREV_9462_10(ah)) {
-		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
-		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_1p0_mac_core,
-				ARRAY_SIZE(ar9462_1p0_mac_core), 2);
-		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
-				ar9462_1p0_mac_postamble,
-				ARRAY_SIZE(ar9462_1p0_mac_postamble),
-				5);
-
-		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
-		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
-				ar9462_1p0_baseband_core,
-				ARRAY_SIZE(ar9462_1p0_baseband_core),
-				2);
-		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
-				ar9462_1p0_baseband_postamble,
-				ARRAY_SIZE(ar9462_1p0_baseband_postamble), 5);
-
-		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
-		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
-				ar9462_1p0_radio_core,
-				ARRAY_SIZE(ar9462_1p0_radio_core), 2);
-		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
-				ar9462_1p0_radio_postamble,
-				ARRAY_SIZE(ar9462_1p0_radio_postamble), 5);
-
-		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
-				ar9462_1p0_soc_preamble,
-				ARRAY_SIZE(ar9462_1p0_soc_preamble), 2);
-		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
-		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
-				ar9462_1p0_soc_postamble,
-				ARRAY_SIZE(ar9462_1p0_soc_postamble), 5);
-
-		INIT_INI_ARRAY(&ah->iniModesRxGain,
-				ar9462_common_rx_gain_table_1p0,
-				ARRAY_SIZE(ar9462_common_rx_gain_table_1p0), 2);
-
-		/* Awake -> Sleep Setting */
-		INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			ar9462_pcie_phy_clkreq_disable_L1_1p0,
-			ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0),
-			2);
-
-		/* Sleep -> Awake Setting */
-		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
-			ar9462_pcie_phy_clkreq_disable_L1_1p0,
-			ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0),
-			2);
-
-		INIT_INI_ARRAY(&ah->iniModesAdditional,
-				ar9462_modes_fast_clock_1p0,
-				ARRAY_SIZE(ar9462_modes_fast_clock_1p0), 3);
-		INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
-				AR9462_BB_CTX_COEFJ(1p0),
-				ARRAY_SIZE(AR9462_BB_CTX_COEFJ(1p0)), 2);
-
 	} else if (AR_SREV_9462_20(ah)) {
 
 		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -537,11 +479,6 @@
 			ar9580_1p0_lowest_ob_db_tx_gain_table,
 			ARRAY_SIZE(ar9580_1p0_lowest_ob_db_tx_gain_table),
 			5);
-	else if (AR_SREV_9462_10(ah))
-		INIT_INI_ARRAY(&ah->iniModesTxGain,
-			ar9462_modes_low_ob_db_tx_gain_table_1p0,
-			ARRAY_SIZE(ar9462_modes_low_ob_db_tx_gain_table_1p0),
-			5);
 	else if (AR_SREV_9462_20(ah))
 		INIT_INI_ARRAY(&ah->iniModesTxGain,
 			ar9462_modes_low_ob_db_tx_gain_table_2p0,
@@ -581,11 +518,6 @@
 			ar9580_1p0_high_ob_db_tx_gain_table,
 			ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table),
 			5);
-	else if (AR_SREV_9462_10(ah))
-		INIT_INI_ARRAY(&ah->iniModesTxGain,
-			ar9462_modes_high_ob_db_tx_gain_table_1p0,
-			ARRAY_SIZE(ar9462_modes_high_ob_db_tx_gain_table_1p0),
-			5);
 	else if (AR_SREV_9462_20(ah))
 		INIT_INI_ARRAY(&ah->iniModesTxGain,
 			ar9462_modes_high_ob_db_tx_gain_table_2p0,
@@ -712,11 +644,6 @@
 				ar9580_1p0_rx_gain_table,
 				ARRAY_SIZE(ar9580_1p0_rx_gain_table),
 				2);
-	else if (AR_SREV_9462_10(ah))
-		INIT_INI_ARRAY(&ah->iniModesRxGain,
-				ar9462_common_rx_gain_table_1p0,
-				ARRAY_SIZE(ar9462_common_rx_gain_table_1p0),
-				2);
 	else if (AR_SREV_9462_20(ah))
 		INIT_INI_ARRAY(&ah->iniModesRxGain,
 				ar9462_common_rx_gain_table_2p0,
@@ -751,11 +678,6 @@
 			ar9485Common_wo_xlna_rx_gain_1_1,
 			ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
 			2);
-	else if (AR_SREV_9462_10(ah))
-		INIT_INI_ARRAY(&ah->iniModesRxGain,
-			ar9462_common_wo_xlna_rx_gain_table_1p0,
-			ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_1p0),
-			2);
 	else if (AR_SREV_9462_20(ah))
 		INIT_INI_ARRAY(&ah->iniModesRxGain,
 			ar9462_common_wo_xlna_rx_gain_table_2p0,
@@ -775,14 +697,10 @@
 
 static void ar9003_rx_gain_table_mode2(struct ath_hw *ah)
 {
-	if (AR_SREV_9462_10(ah))
+	if (AR_SREV_9462_20(ah))
 		INIT_INI_ARRAY(&ah->iniModesRxGain,
-			ar9462_common_mixed_rx_gain_table_1p0,
-			ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_1p0), 2);
-	else if (AR_SREV_9462_20(ah))
-		INIT_INI_ARRAY(&ah->iniModesRxGain,
-			ar9462_common_mixed_rx_gain_table_2p0,
-			ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2);
+			       ar9462_common_mixed_rx_gain_table_2p0,
+			       ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2);
 }
 
 static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 09b8c9d..8d1bca0 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -16,6 +16,7 @@
 #include <linux/export.h>
 #include "hw.h"
 #include "ar9003_mac.h"
+#include "ar9003_mci.h"
 
 static void ar9003_hw_rx_enable(struct ath_hw *hw)
 {
@@ -28,11 +29,14 @@
 	struct ar9003_txc *ads = ds;
 	int checksum = 0;
 	u32 val, ctl12, ctl17;
+	u8 desc_len;
+
+	desc_len = (AR_SREV_9462(ah) ? 0x18 : 0x17);
 
 	val = (ATHEROS_VENDOR_ID << AR_DescId_S) |
 	      (1 << AR_TxRxDesc_S) |
 	      (1 << AR_CtrlStat_S) |
-	      (i->qcu << AR_TxQcuNum_S) | 0x17;
+	      (i->qcu << AR_TxQcuNum_S) | desc_len;
 
 	checksum += val;
 	ACCESS_ONCE(ads->info) = val;
@@ -81,6 +85,7 @@
 	ads->ctl20 = 0;
 	ads->ctl21 = 0;
 	ads->ctl22 = 0;
+	ads->ctl23 = 0;
 
 	ctl17 = SM(i->keytype, AR_EncrType);
 	if (!i->is_first) {
@@ -176,7 +181,6 @@
 	u32 mask2 = 0;
 	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 sync_cause = 0, async_cause;
 
 	async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
@@ -298,32 +302,8 @@
 			ar9003_hw_bb_watchdog_read(ah);
 	}
 
-	if (async_cause & AR_INTR_ASYNC_MASK_MCI) {
-		u32 raw_intr, rx_msg_intr;
-
-		rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
-		raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
-
-		if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef))
-			ath_dbg(common, MCI,
-				"MCI gets 0xdeadbeef during MCI int processing new raw_intr=0x%08x, new rx_msg_raw=0x%08x, raw_intr=0x%08x, rx_msg_raw=0x%08x\n",
-				raw_intr, rx_msg_intr, mci->raw_intr,
-				mci->rx_msg_intr);
-		else {
-			mci->rx_msg_intr |= rx_msg_intr;
-			mci->raw_intr |= raw_intr;
-			*masked |= ATH9K_INT_MCI;
-
-			if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
-				mci->cont_status =
-					REG_READ(ah, AR_MCI_CONT_STATUS);
-
-			REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
-			REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
-			ath_dbg(common, MCI, "AR_INTR_SYNC_MCI\n");
-
-		}
-	}
+	if (async_cause & AR_INTR_ASYNC_MASK_MCI)
+		ar9003_mci_get_isr(ah, masked);
 
 	if (sync_cause) {
 		if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
@@ -530,7 +510,11 @@
 		 */
 		if (rxsp->status11 & AR_CRCErr)
 			rxs->rs_status |= ATH9K_RXERR_CRC;
-		else if (rxsp->status11 & AR_PHYErr) {
+		else if (rxsp->status11 & AR_DecryptCRCErr)
+			rxs->rs_status |= ATH9K_RXERR_DECRYPT;
+		else if (rxsp->status11 & AR_MichaelErr)
+			rxs->rs_status |= ATH9K_RXERR_MIC;
+		if (rxsp->status11 & AR_PHYErr) {
 			phyerr = MS(rxsp->status11, AR_PHYErrCode);
 			/*
 			 * If we reach a point here where AR_PostDelimCRCErr is
@@ -552,11 +536,7 @@
 				rxs->rs_status |= ATH9K_RXERR_PHY;
 				rxs->rs_phyerr = phyerr;
 			}
-
-		} else if (rxsp->status11 & AR_DecryptCRCErr)
-			rxs->rs_status |= ATH9K_RXERR_DECRYPT;
-		else if (rxsp->status11 & AR_MichaelErr)
-			rxs->rs_status |= ATH9K_RXERR_MIC;
+		};
 	}
 
 	if (rxsp->status11 & AR_KeyMiss)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
index e203b51..cbf60b0 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
@@ -92,7 +92,8 @@
 	u32 ctl20;  /* DMA control 20 */
 	u32 ctl21;  /* DMA control 21 */
 	u32 ctl22;  /* DMA control 22 */
-	u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */
+	u32 ctl23;  /* DMA control 23 */
+	u32 pad[8]; /* pad to cache line (128 bytes/32 dwords) */
 } __packed __aligned(4);
 
 struct ar9003_txs {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index 709520c..3cac293 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -16,14 +16,12 @@
 
 #include <linux/export.h>
 #include "hw.h"
+#include "hw-ops.h"
 #include "ar9003_phy.h"
 #include "ar9003_mci.h"
 
 static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah)
 {
-	if (!AR_SREV_9462_20(ah))
-		return;
-
 	REG_RMW_FIELD(ah, AR_MCI_COMMAND2,
 		      AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1);
 	udelay(1);
@@ -37,13 +35,10 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 
 	while (time_out) {
-
 		if (REG_READ(ah, address) & bit_position) {
-
 			REG_WRITE(ah, address, bit_position);
 
 			if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
-
 				if (bit_position &
 				    AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
 					ar9003_mci_reset_req_wakeup(ah);
@@ -81,25 +76,19 @@
 	return time_out;
 }
 
-void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done)
+static void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done)
 {
 	u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00};
 
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
 	ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16,
 				wait_done, false);
 	udelay(5);
 }
 
-void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done)
+static void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done)
 {
 	u32 payload = 0x00000000;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
 	ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1,
 				wait_done, false);
 }
@@ -111,11 +100,8 @@
 	udelay(5);
 }
 
-void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done)
+static void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done)
 {
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
 	ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP,
 				NULL, 0, wait_done, false);
 }
@@ -138,30 +124,27 @@
 static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
 					       bool wait_done)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 payload[4] = {0, 0, 0, 0};
 
 	if (!mci->bt_version_known &&
-			(mci->bt_state != MCI_BT_SLEEP)) {
-		ath_dbg(common, MCI, "MCI Send Coex version query\n");
+	    (mci->bt_state != MCI_BT_SLEEP)) {
 		MCI_GPM_SET_TYPE_OPCODE(payload,
-				MCI_GPM_COEX_AGENT, MCI_GPM_COEX_VERSION_QUERY);
+					MCI_GPM_COEX_AGENT,
+					MCI_GPM_COEX_VERSION_QUERY);
 		ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-				wait_done, true);
+					wait_done, true);
 	}
 }
 
 static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
-						     bool wait_done)
+						  bool wait_done)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 payload[4] = {0, 0, 0, 0};
 
-	ath_dbg(common, MCI, "MCI Send Coex version response\n");
 	MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
-			MCI_GPM_COEX_VERSION_RESPONSE);
+				MCI_GPM_COEX_VERSION_RESPONSE);
 	*(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) =
 		mci->wlan_ver_major;
 	*(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) =
@@ -170,15 +153,16 @@
 }
 
 static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
-						  bool wait_done)
+					       bool wait_done)
 {
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 *payload = &mci->wlan_channels[0];
 
 	if ((mci->wlan_channels_update == true) &&
-			(mci->bt_state != MCI_BT_SLEEP)) {
+	    (mci->bt_state != MCI_BT_SLEEP)) {
 		MCI_GPM_SET_TYPE_OPCODE(payload,
-		MCI_GPM_COEX_AGENT, MCI_GPM_COEX_WLAN_CHANNELS);
+					MCI_GPM_COEX_AGENT,
+					MCI_GPM_COEX_WLAN_CHANNELS);
 		ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
 					wait_done, true);
 		MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
@@ -188,7 +172,6 @@
 static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
 						bool wait_done, u8 query_type)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 payload[4] = {0, 0, 0, 0};
 	bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
@@ -196,25 +179,19 @@
 
 	if (mci->bt_state != MCI_BT_SLEEP) {
 
-		ath_dbg(common, MCI, "MCI Send Coex BT Status Query 0x%02X\n",
-			query_type);
-
-		MCI_GPM_SET_TYPE_OPCODE(payload,
-				MCI_GPM_COEX_AGENT, MCI_GPM_COEX_STATUS_QUERY);
+		MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+					MCI_GPM_COEX_STATUS_QUERY);
 
 		*(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
+
 		/*
 		 * If bt_status_query message is  not sent successfully,
 		 * then need_flush_btinfo should be set again.
 		 */
 		if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
 					     wait_done, true)) {
-			if (query_btinfo) {
+			if (query_btinfo)
 				mci->need_flush_btinfo = true;
-
-				ath_dbg(common, MCI,
-					"MCI send bt_status_query fail, set flush flag again\n");
-			}
 		}
 
 		if (query_btinfo)
@@ -222,21 +199,14 @@
 	}
 }
 
-void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
-				      bool wait_done)
+static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
+					     bool wait_done)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 payload[4] = {0, 0, 0, 0};
 
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
-	ath_dbg(common, MCI, "MCI Send Coex %s BT GPM\n",
-		(halt) ? "halt" : "unhalt");
-
-	MCI_GPM_SET_TYPE_OPCODE(payload,
-				MCI_GPM_COEX_AGENT, MCI_GPM_COEX_HALT_BT_GPM);
+	MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+				MCI_GPM_COEX_HALT_BT_GPM);
 
 	if (halt) {
 		mci->query_bt = true;
@@ -252,7 +222,6 @@
 	ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
 }
 
-
 static void ar9003_mci_prep_interface(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -269,30 +238,14 @@
 	REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
 		  REG_READ(ah, AR_MCI_INTERRUPT_RAW));
 
-	/* Remote Reset */
-	ath_dbg(common, MCI, "MCI Reset sequence start\n");
-	ath_dbg(common, MCI, "MCI send REMOTE_RESET\n");
 	ar9003_mci_remote_reset(ah, true);
-
-	/*
-	 * This delay is required for the reset delay worst case value 255 in
-	 * MCI_COMMAND2 register
-	 */
-
-	if (AR_SREV_9462_10(ah))
-		udelay(252);
-
-	ath_dbg(common, MCI, "MCI Send REQ_WAKE to remoter(BT)\n");
 	ar9003_mci_send_req_wake(ah, true);
 
 	if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-				AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
+				  AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
 
-		ath_dbg(common, MCI, "MCI SYS_WAKING from remote(BT)\n");
 		mci->bt_state = MCI_BT_AWAKE;
 
-		if (AR_SREV_9462_10(ah))
-			udelay(10);
 		/*
 		 * we don't need to send more remote_reset at this moment.
 		 * If BT receive first remote_reset, then BT HW will
@@ -309,11 +262,6 @@
 		 * Similarly, if in any case, WLAN can receive BT's sys_waking,
 		 * that means WLAN's RX is also fine.
 		 */
-
-		/* Send SYS_WAKING to BT */
-
-		ath_dbg(common, MCI, "MCI send SW SYS_WAKING to remote BT\n");
-
 		ar9003_mci_send_sys_waking(ah, true);
 		udelay(10);
 
@@ -321,7 +269,6 @@
 		 * Set BT priority interrupt value to be 0xff to
 		 * avoid having too many BT PRIORITY interrupts.
 		 */
-
 		REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
 		REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
 		REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
@@ -339,77 +286,70 @@
 		REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
 			  AR_MCI_INTERRUPT_BT_PRI);
 
-		if (AR_SREV_9462_10(ah) || mci->is_2g) {
-			/* Send LNA_TRANS */
-			ath_dbg(common, MCI, "MCI send LNA_TRANS to BT\n");
+		if (mci->is_2g) {
 			ar9003_mci_send_lna_transfer(ah, true);
 			udelay(5);
 		}
 
-		if (AR_SREV_9462_10(ah) || (mci->is_2g &&
-					    !mci->update_2g5g)) {
+		if ((mci->is_2g && !mci->update_2g5g)) {
 			if (ar9003_mci_wait_for_interrupt(ah,
-				AR_MCI_INTERRUPT_RX_MSG_RAW,
-				AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
-				mci_timeout))
+					  AR_MCI_INTERRUPT_RX_MSG_RAW,
+					  AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
+					  mci_timeout))
 				ath_dbg(common, MCI,
 					"MCI WLAN has control over the LNA & BT obeys it\n");
 			else
 				ath_dbg(common, MCI,
 					"MCI BT didn't respond to LNA_TRANS\n");
 		}
-
-		if (AR_SREV_9462_10(ah)) {
-			/* Send another remote_reset to deassert BT clk_req. */
-			ath_dbg(common, MCI,
-				"MCI another remote_reset to deassert clk_req\n");
-			ar9003_mci_remote_reset(ah, true);
-			udelay(252);
-		}
 	}
 
 	/* Clear the extra redundant SYS_WAKING from BT */
 	if ((mci->bt_state == MCI_BT_AWAKE) &&
 		(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
 				AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
-		(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-				AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
-
-			REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-				  AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING);
-			REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-				  AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
+	    (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+			    AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
+		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+			  AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING);
+		REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+			  AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
 	}
 
 	REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
 }
 
-void ar9003_mci_disable_interrupt(struct ath_hw *ah)
+void ar9003_mci_set_full_sleep(struct ath_hw *ah)
 {
-	if (!ATH9K_HW_CAP_MCI)
-		return;
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
+	if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
+	    (mci->bt_state != MCI_BT_SLEEP) &&
+	    !mci->halted_bt_gpm) {
+		ar9003_mci_send_coex_halt_bt_gpm(ah, true, true);
+	}
+
+	mci->ready = false;
+	REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+}
+
+static void ar9003_mci_disable_interrupt(struct ath_hw *ah)
+{
 	REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
 	REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
 }
 
-void ar9003_mci_enable_interrupt(struct ath_hw *ah)
+static void ar9003_mci_enable_interrupt(struct ath_hw *ah)
 {
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
 	REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT);
 	REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
 		  AR_MCI_INTERRUPT_RX_MSG_DEFAULT);
 }
 
-bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints)
+static bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints)
 {
 	u32 intr;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return false;
-
 	intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
 	return ((intr & ints) == ints);
 }
@@ -419,9 +359,6 @@
 {
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
 	*raw_intr = mci->raw_intr;
 	*rx_msg_intr = mci->rx_msg_intr;
 
@@ -431,13 +368,35 @@
 }
 EXPORT_SYMBOL(ar9003_mci_get_interrupt);
 
-void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)
+void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	u32 raw_intr, rx_msg_intr;
+
+	rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
+	raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
+
+	if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) {
+		ath_dbg(common, MCI,
+			"MCI gets 0xdeadbeef during int processing\n");
+	} else {
+		mci->rx_msg_intr |= rx_msg_intr;
+		mci->raw_intr |= raw_intr;
+		*masked |= ATH9K_INT_MCI;
+
+		if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
+			mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS);
+
+		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
+		REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
+	}
+}
+
+static void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)
 {
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
 	if (!mci->update_2g5g &&
 	    (mci->is_2g != is_2g))
 		mci->update_2g5g = true;
@@ -447,7 +406,6 @@
 
 static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 *payload;
 	u32 recv_type, offset;
@@ -460,10 +418,8 @@
 	payload = (u32 *)(mci->gpm_buf + offset);
 	recv_type = MCI_GPM_TYPE(payload);
 
-	if (recv_type == MCI_GPM_RSVD_PATTERN) {
-		ath_dbg(common, MCI, "MCI Skip RSVD GPM\n");
+	if (recv_type == MCI_GPM_RSVD_PATTERN)
 		return false;
-	}
 
 	return true;
 }
@@ -471,42 +427,31 @@
 static void ar9003_mci_observation_set_up(struct ath_hw *ah)
 {
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-	if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {
 
-		ath9k_hw_cfg_output(ah, 3,
-					AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
+	if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {
+		ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
 		ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK);
 		ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
 		ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
-
 	} else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) {
-
 		ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX);
 		ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX);
 		ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
 		ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
 		ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-
 	} else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) {
-
 		ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
 		ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
 		ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
 		ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
-
 	} else
 		return;
 
 	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
 
-	if (AR_SREV_9462_20_OR_LATER(ah)) {
-		REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
-			      AR_GLB_DS_JTAG_DISABLE, 1);
-		REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
-			      AR_GLB_WLAN_UART_INTF_EN, 0);
-		REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL,
-			    ATH_MCI_CONFIG_MCI_OBS_GPIO);
-	}
+	REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_DS_JTAG_DISABLE, 1);
+	REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_WLAN_UART_INTF_EN, 0);
+	REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, ATH_MCI_CONFIG_MCI_OBS_GPIO);
 
 	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0);
 	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1);
@@ -520,13 +465,12 @@
 }
 
 static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done,
-						u8 opcode, u32 bt_flags)
+					  u8 opcode, u32 bt_flags)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	u32 pld[4] = {0, 0, 0, 0};
 
-	MCI_GPM_SET_TYPE_OPCODE(pld,
-			MCI_GPM_COEX_AGENT, MCI_GPM_COEX_BT_UPDATE_FLAGS);
+	MCI_GPM_SET_TYPE_OPCODE(pld, MCI_GPM_COEX_AGENT,
+				MCI_GPM_COEX_BT_UPDATE_FLAGS);
 
 	*(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP)  = opcode;
 	*(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF;
@@ -534,502 +478,50 @@
 	*(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF;
 	*(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF;
 
-	ath_dbg(common, MCI,
-		"MCI BT_MCI_FLAGS: Send Coex BT Update Flags %s 0x%08x\n",
-		opcode == MCI_GPM_COEX_BT_FLAGS_READ ? "READ" :
-		opcode == MCI_GPM_COEX_BT_FLAGS_SET ? "SET" : "CLEAR",
-		bt_flags);
-
 	return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16,
-							wait_done, true);
+				       wait_done, true);
 }
 
-void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
-		      bool is_full_sleep)
+static void ar9003_mci_sync_bt_state(struct ath_hw *ah)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-	u32 regval, thresh;
-
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
-	ath_dbg(common, MCI, "MCI full_sleep = %d, is_2g = %d\n",
-		is_full_sleep, is_2g);
-
-	/*
-	 * GPM buffer and scheduling message buffer are not allocated
-	 */
-
-	if (!mci->gpm_addr && !mci->sched_addr) {
-		ath_dbg(common, MCI,
-			"MCI GPM and schedule buffers are not allocated\n");
-		return;
-	}
-
-	if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {
-		ath_dbg(common, MCI, "MCI it's deadbeef, quit mci_reset\n");
-		return;
-	}
-
-	/* Program MCI DMA related registers */
-	REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr);
-	REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len);
-	REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr);
-
-	/*
-	* To avoid MCI state machine be affected by incoming remote MCI msgs,
-	* MCI mode will be enabled later, right before reset the MCI TX and RX.
-	*/
-
-	regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
-		 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
-		 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
-		 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
-		 SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
-		 SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |
-		 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |
-		 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |
-		 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-
-	if (is_2g && (AR_SREV_9462_20(ah)) &&
-		!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
-
-		regval |= SM(1, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-		ath_dbg(common, MCI, "MCI sched one step look ahead\n");
-
-		if (!(mci->config &
-		      ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
-
-			thresh = MS(mci->config,
-				    ATH_MCI_CONFIG_AGGR_THRESH);
-			thresh &= 7;
-			regval |= SM(1,
-				     AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN);
-			regval |= SM(thresh, AR_BTCOEX_CTRL_AGGR_THRESH);
-
-			REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
-				      AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
-			REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
-				      AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
-
-		} else
-			ath_dbg(common, MCI, "MCI sched aggr thresh: off\n");
-	} else
-		ath_dbg(common, MCI, "MCI SCHED one step look ahead off\n");
-
-	if (AR_SREV_9462_10(ah))
-		regval |= SM(1, AR_BTCOEX_CTRL_SPDT_ENABLE_10);
-
-	REG_WRITE(ah, AR_BTCOEX_CTRL, regval);
-
-	if (AR_SREV_9462_20(ah)) {
-		REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
-			    AR_BTCOEX_CTRL_SPDT_ENABLE);
-		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,
-			      AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);
-	}
-
-	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1);
-	REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
-
-	thresh = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);
-	REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, thresh);
-	REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);
-
-	/* Resetting the Rx and Tx paths of MCI */
-	regval = REG_READ(ah, AR_MCI_COMMAND2);
-	regval |= SM(1, AR_MCI_COMMAND2_RESET_TX);
-	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
-
-	udelay(1);
-
-	regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX);
-	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
-
-	if (is_full_sleep) {
-		ar9003_mci_mute_bt(ah);
-		udelay(100);
-	}
-
-	regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
-	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
-	udelay(1);
-	regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
-	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
-
-	ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
-	REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
-		  (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
-		   SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM)));
-
-	REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
-			AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-
-	if (AR_SREV_9462_20_OR_LATER(ah))
-		ar9003_mci_observation_set_up(ah);
-
-	mci->ready = true;
-	ar9003_mci_prep_interface(ah);
-
-	if (en_int)
-		ar9003_mci_enable_interrupt(ah);
-}
-
-void ar9003_mci_mute_bt(struct ath_hw *ah)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
-	/* disable all MCI messages */
-	REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
-	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
-	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
-	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
-	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
-	REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-
-	/* wait pending HW messages to flush out */
-	udelay(10);
-
-	/*
-	 * Send LNA_TAKE and SYS_SLEEPING when
-	 * 1. reset not after resuming from full sleep
-	 * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment
-	 */
-
-	ath_dbg(common, MCI, "MCI Send LNA take\n");
-	ar9003_mci_send_lna_take(ah, true);
-
-	udelay(5);
-
-	ath_dbg(common, MCI, "MCI Send sys sleeping\n");
-	ar9003_mci_send_sys_sleeping(ah, true);
-}
-
-void ar9003_mci_sync_bt_state(struct ath_hw *ah)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 cur_bt_state;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
 	cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
 
-	if (mci->bt_state != cur_bt_state) {
-		ath_dbg(common, MCI,
-			"MCI BT state mismatches. old: %d, new: %d\n",
-			mci->bt_state, cur_bt_state);
+	if (mci->bt_state != cur_bt_state)
 		mci->bt_state = cur_bt_state;
-	}
 
 	if (mci->bt_state != MCI_BT_SLEEP) {
 
 		ar9003_mci_send_coex_version_query(ah, true);
 		ar9003_mci_send_coex_wlan_channels(ah, true);
 
-		if (mci->unhalt_bt_gpm == true) {
-			ath_dbg(common, MCI, "MCI unhalt BT GPM\n");
+		if (mci->unhalt_bt_gpm == true)
 			ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
-		}
 	}
 }
 
-static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
+void ar9003_mci_check_bt(struct ath_hw *ah)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-	u32 new_flags, to_set, to_clear;
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 
-	if (AR_SREV_9462_20(ah) &&
-	    mci->update_2g5g &&
-	    (mci->bt_state != MCI_BT_SLEEP)) {
-
-		if (mci->is_2g) {
-			new_flags = MCI_2G_FLAGS;
-			to_clear = MCI_2G_FLAGS_CLEAR_MASK;
-			to_set = MCI_2G_FLAGS_SET_MASK;
-		} else {
-			new_flags = MCI_5G_FLAGS;
-			to_clear = MCI_5G_FLAGS_CLEAR_MASK;
-			to_set = MCI_5G_FLAGS_SET_MASK;
-		}
-
-		ath_dbg(common, MCI,
-			"MCI BT_MCI_FLAGS: %s 0x%08x clr=0x%08x, set=0x%08x\n",
-		mci->is_2g ? "2G" : "5G", new_flags, to_clear, to_set);
-
-		if (to_clear)
-			ar9003_mci_send_coex_bt_flags(ah, wait_done,
-					MCI_GPM_COEX_BT_FLAGS_CLEAR, to_clear);
-
-		if (to_set)
-			ar9003_mci_send_coex_bt_flags(ah, wait_done,
-					MCI_GPM_COEX_BT_FLAGS_SET, to_set);
-	}
-
-	if (AR_SREV_9462_10(ah) && (mci->bt_state != MCI_BT_SLEEP))
-		mci->update_2g5g = false;
-}
-
-static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
-					u32 *payload, bool queue)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-	u8 type, opcode;
-
-	if (queue) {
-
-		if (payload)
-			ath_dbg(common, MCI,
-				"MCI ERROR: Send fail: %02x: %02x %02x %02x\n",
-				header,
-				*(((u8 *)payload) + 4),
-				*(((u8 *)payload) + 5),
-				*(((u8 *)payload) + 6));
-		else
-			ath_dbg(common, MCI, "MCI ERROR: Send fail: %02x\n",
-				header);
-	}
-
-	/* check if the message is to be queued */
-	if (header != MCI_GPM)
+	if (!mci_hw->ready)
 		return;
 
-	type = MCI_GPM_TYPE(payload);
-	opcode = MCI_GPM_OPCODE(payload);
+	/*
+	 * check BT state again to make
+	 * sure it's not changed.
+	 */
+	ar9003_mci_sync_bt_state(ah);
+	ar9003_mci_2g5g_switch(ah, true);
 
-	if (type != MCI_GPM_COEX_AGENT)
-		return;
-
-	switch (opcode) {
-	case MCI_GPM_COEX_BT_UPDATE_FLAGS:
-
-		if (AR_SREV_9462_10(ah))
-			break;
-
-		if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) ==
-				MCI_GPM_COEX_BT_FLAGS_READ)
-			break;
-
-		mci->update_2g5g = queue;
-
-		if (queue)
-			ath_dbg(common, MCI,
-				"MCI BT_MCI_FLAGS: 2G5G status <queued> %s\n",
-				mci->is_2g ? "2G" : "5G");
-		else
-			ath_dbg(common, MCI,
-				"MCI BT_MCI_FLAGS: 2G5G status <sent> %s\n",
-				mci->is_2g ? "2G" : "5G");
-
-		break;
-
-	case MCI_GPM_COEX_WLAN_CHANNELS:
-
-		mci->wlan_channels_update = queue;
-		if (queue)
-			ath_dbg(common, MCI, "MCI WLAN channel map <queued>\n");
-		else
-			ath_dbg(common, MCI, "MCI WLAN channel map <sent>\n");
-		break;
-
-	case MCI_GPM_COEX_HALT_BT_GPM:
-
-		if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
-				MCI_GPM_COEX_BT_GPM_UNHALT) {
-
-			mci->unhalt_bt_gpm = queue;
-
-			if (queue)
-				ath_dbg(common, MCI,
-					"MCI UNHALT BT GPM <queued>\n");
-			else {
-				mci->halted_bt_gpm = false;
-				ath_dbg(common, MCI,
-					"MCI UNHALT BT GPM <sent>\n");
-			}
-		}
-
-		if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
-				MCI_GPM_COEX_BT_GPM_HALT) {
-
-			mci->halted_bt_gpm = !queue;
-
-			if (queue)
-				ath_dbg(common, MCI,
-					"MCI HALT BT GPM <not sent>\n");
-			else
-				ath_dbg(common, MCI,
-					"MCI UNHALT BT GPM <sent>\n");
-		}
-
-		break;
-	default:
-		break;
+	if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
+	    (mci_hw->query_bt == true)) {
+		mci_hw->need_flush_btinfo = true;
 	}
 }
 
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
-	if (mci->update_2g5g) {
-		if (mci->is_2g) {
-
-			ar9003_mci_send_2g5g_status(ah, true);
-			ath_dbg(common, MCI, "MCI Send LNA trans\n");
-			ar9003_mci_send_lna_transfer(ah, true);
-			udelay(5);
-
-			REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
-				    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-
-			if (AR_SREV_9462_20(ah)) {
-				REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
-					    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
-				if (!(mci->config &
-				      ATH_MCI_CONFIG_DISABLE_OSLA)) {
-					REG_SET_BIT(ah, AR_BTCOEX_CTRL,
-					AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-				}
-			}
-		} else {
-			ath_dbg(common, MCI, "MCI Send LNA take\n");
-			ar9003_mci_send_lna_take(ah, true);
-			udelay(5);
-
-			REG_SET_BIT(ah, AR_MCI_TX_CTRL,
-				    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-
-			if (AR_SREV_9462_20(ah)) {
-				REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
-					    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
-				REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
-					AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-			}
-
-			ar9003_mci_send_2g5g_status(ah, true);
-		}
-	}
-}
-
-bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
-			     u32 *payload, u8 len, bool wait_done,
-			     bool check_bt)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-	bool msg_sent = false;
-	u32 regval;
-	u32 saved_mci_int_en;
-	int i;
-
-	if (!ATH9K_HW_CAP_MCI)
-		return false;
-
-	saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
-	regval = REG_READ(ah, AR_BTCOEX_CTRL);
-
-	if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) {
-
-		ath_dbg(common, MCI,
-			"MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n",
-			header,
-			(ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0);
-
-		ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
-		return false;
-
-	} else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) {
-
-		ath_dbg(common, MCI,
-			"MCI Don't send message 0x%x. BT is in sleep state\n",
-			header);
-
-		ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
-		return false;
-	}
-
-	if (wait_done)
-		REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
-
-	/* Need to clear SW_MSG_DONE raw bit before wait */
-
-	REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-		  (AR_MCI_INTERRUPT_SW_MSG_DONE |
-		   AR_MCI_INTERRUPT_MSG_FAIL_MASK));
-
-	if (payload) {
-		for (i = 0; (i * 4) < len; i++)
-			REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4),
-				  *(payload + i));
-	}
-
-	REG_WRITE(ah, AR_MCI_COMMAND0,
-		  (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP),
-		      AR_MCI_COMMAND0_DISABLE_TIMESTAMP) |
-		   SM(len, AR_MCI_COMMAND0_LEN) |
-		   SM(header, AR_MCI_COMMAND0_HEADER)));
-
-	if (wait_done &&
-	    !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW,
-					AR_MCI_INTERRUPT_SW_MSG_DONE, 500)))
-		ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
-	else {
-		ar9003_mci_queue_unsent_gpm(ah, header, payload, false);
-		msg_sent = true;
-	}
-
-	if (wait_done)
-		REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
-
-	return msg_sent;
-}
-EXPORT_SYMBOL(ar9003_mci_send_message);
-
-void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
-		      u16 len, u32 sched_addr)
-{
-	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-	void *sched_buf = (void *)((char *) gpm_buf + (sched_addr - gpm_addr));
-
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
-	mci->gpm_addr = gpm_addr;
-	mci->gpm_buf = gpm_buf;
-	mci->gpm_len = len;
-	mci->sched_addr = sched_addr;
-	mci->sched_buf = sched_buf;
-
-	ar9003_mci_reset(ah, true, true, true);
-}
-EXPORT_SYMBOL(ar9003_mci_setup);
-
-void ar9003_mci_cleanup(struct ath_hw *ah)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
-	/* Turn off MCI and Jupiter mode. */
-	REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00);
-	ath_dbg(common, MCI, "MCI ar9003_mci_cleanup\n");
-	ar9003_mci_disable_interrupt(ah);
-}
-EXPORT_SYMBOL(ar9003_mci_cleanup);
-
 static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type,
 					 u8 gpm_opcode, u32 *p_gpm)
 {
@@ -1077,8 +569,8 @@
 	}
 }
 
-u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
-			    u8 gpm_opcode, int time_out)
+static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
+				   u8 gpm_opcode, int time_out)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
@@ -1087,9 +579,6 @@
 	u8 recv_type = 0, recv_opcode = 0;
 	bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE);
 
-	if (!ATH9K_HW_CAP_MCI)
-		return 0;
-
 	more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE;
 
 	while (time_out > 0) {
@@ -1107,8 +596,8 @@
 		if (!time_out)
 			break;
 
-		offset = ar9003_mci_state(ah,
-				MCI_STATE_NEXT_GPM_OFFSET, &more_data);
+		offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
+					  &more_data);
 
 		if (offset == MCI_GPM_INVALID)
 			continue;
@@ -1118,24 +607,17 @@
 		recv_opcode = MCI_GPM_OPCODE(p_gpm);
 
 		if (MCI_GPM_IS_CAL_TYPE(recv_type)) {
-
 			if (recv_type == gpm_type) {
-
 				if ((gpm_type == MCI_GPM_BT_CAL_DONE) &&
 				    !b_is_bt_cal_done) {
 					gpm_type = MCI_GPM_BT_CAL_GRANT;
-					ath_dbg(common, MCI,
-						"MCI Recv BT_CAL_DONE wait BT_CAL_GRANT\n");
 					continue;
 				}
-
 				break;
 			}
-		} else if ((recv_type == gpm_type) &&
-			   (recv_opcode == gpm_opcode))
+		} else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) {
 			break;
-
-		/* not expected message */
+		}
 
 		/*
 		 * check if it's cal_grant
@@ -1156,45 +638,31 @@
 			u32 payload[4] = {0, 0, 0, 0};
 
 			gpm_type = MCI_GPM_BT_CAL_DONE;
-			ath_dbg(common, MCI,
-				"MCI Rcv BT_CAL_REQ, send WLAN_CAL_GRANT\n");
-
 			MCI_GPM_SET_CAL_TYPE(payload,
-					MCI_GPM_WLAN_CAL_GRANT);
-
+					     MCI_GPM_WLAN_CAL_GRANT);
 			ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
 						false, false);
-
-			ath_dbg(common, MCI, "MCI now wait for BT_CAL_DONE\n");
-
 			continue;
 		} else {
 			ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n",
 				*(p_gpm + 1));
 			mismatch++;
 			ar9003_mci_process_gpm_extra(ah, recv_type,
-					recv_opcode, p_gpm);
+						     recv_opcode, p_gpm);
 		}
 	}
+
 	if (p_gpm) {
 		MCI_GPM_RECYCLE(p_gpm);
 		p_gpm = NULL;
 	}
 
-	if (time_out <= 0) {
+	if (time_out <= 0)
 		time_out = 0;
-		ath_dbg(common, MCI,
-			"MCI GPM received timeout, mismatch = %d\n", mismatch);
-	} else
-		ath_dbg(common, MCI, "MCI Receive GPM type=0x%x, code=0x%x\n",
-			gpm_type, gpm_opcode);
 
 	while (more_data == MCI_GPM_MORE) {
-
-		ath_dbg(common, MCI, "MCI discard remaining GPM\n");
 		offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
 					  &more_data);
-
 		if (offset == MCI_GPM_INVALID)
 			break;
 
@@ -1212,6 +680,499 @@
 	return time_out;
 }
 
+bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+	u32 payload[4] = {0, 0, 0, 0};
+
+	ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
+
+	if (mci_hw->bt_state != MCI_BT_CAL_START)
+		return false;
+
+	mci_hw->bt_state = MCI_BT_CAL;
+
+	/*
+	 * MCI FIX: disable mci interrupt here. This is to avoid
+	 * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
+	 * lead to mci_intr reentry.
+	 */
+	ar9003_mci_disable_interrupt(ah);
+
+	MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
+	ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
+				16, true, false);
+
+	/* Wait BT calibration to be completed for 25ms */
+
+	if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
+				    0, 25000))
+		ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n");
+	else
+		ath_dbg(common, MCI,
+			"MCI BT_CAL_DONE not received\n");
+
+	mci_hw->bt_state = MCI_BT_AWAKE;
+	/* MCI FIX: enable mci interrupt here */
+	ar9003_mci_enable_interrupt(ah);
+
+	return true;
+}
+
+int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+			 struct ath9k_hw_cal_data *caldata)
+{
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+
+	if (!mci_hw->ready)
+		return 0;
+
+	if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))
+		goto exit;
+
+	if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
+	    ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
+
+		/*
+		 * BT is sleeping. Check if BT wakes up during
+		 * WLAN calibration. If BT wakes up during
+		 * WLAN calibration, need to go through all
+		 * message exchanges again and recal.
+		 */
+		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+			  AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
+			  AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
+
+		ar9003_mci_remote_reset(ah, true);
+		ar9003_mci_send_sys_waking(ah, true);
+		udelay(1);
+
+		if (IS_CHAN_2GHZ(chan))
+			ar9003_mci_send_lna_transfer(ah, true);
+
+		mci_hw->bt_state = MCI_BT_AWAKE;
+
+		if (caldata) {
+			caldata->done_txiqcal_once = false;
+			caldata->done_txclcal_once = false;
+			caldata->rtt_hist.num_readings = 0;
+		}
+
+		if (!ath9k_hw_init_cal(ah, chan))
+			return -EIO;
+
+	}
+exit:
+	ar9003_mci_enable_interrupt(ah);
+	return 0;
+}
+
+static void ar9003_mci_mute_bt(struct ath_hw *ah)
+{
+	/* disable all MCI messages */
+	REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
+	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
+	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
+	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
+	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
+	REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+
+	/* wait pending HW messages to flush out */
+	udelay(10);
+
+	/*
+	 * Send LNA_TAKE and SYS_SLEEPING when
+	 * 1. reset not after resuming from full sleep
+	 * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment
+	 */
+	ar9003_mci_send_lna_take(ah, true);
+
+	udelay(5);
+
+	ar9003_mci_send_sys_sleeping(ah, true);
+}
+
+static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)
+{
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	u32 thresh;
+
+	if (enable) {
+		REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+			      AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
+		REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+			      AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
+
+		if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
+			thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
+			REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+				      AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
+			REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+				      AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
+		} else {
+			REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+				      AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
+		}
+
+		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+			      AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
+	} else {
+		REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
+			    AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+	}
+}
+
+void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+		      bool is_full_sleep)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	u32 regval;
+
+	ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n",
+		is_full_sleep, is_2g);
+
+	if (!mci->gpm_addr && !mci->sched_addr) {
+		ath_dbg(common, MCI,
+			"MCI GPM and schedule buffers are not allocated\n");
+		return;
+	}
+
+	if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {
+		ath_dbg(common, MCI, "BTCOEX control register is dead\n");
+		return;
+	}
+
+	/* Program MCI DMA related registers */
+	REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr);
+	REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len);
+	REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr);
+
+	/*
+	* To avoid MCI state machine be affected by incoming remote MCI msgs,
+	* MCI mode will be enabled later, right before reset the MCI TX and RX.
+	*/
+
+	regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
+		 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
+		 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
+		 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
+		 SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
+		 SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |
+		 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |
+		 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |
+		 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+
+	REG_WRITE(ah, AR_BTCOEX_CTRL, regval);
+
+	if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
+		ar9003_mci_osla_setup(ah, true);
+	else
+		ar9003_mci_osla_setup(ah, false);
+
+	REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+		    AR_BTCOEX_CTRL_SPDT_ENABLE);
+	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,
+		      AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);
+
+	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1);
+	REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
+
+	regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);
+	REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval);
+	REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);
+
+	/* Resetting the Rx and Tx paths of MCI */
+	regval = REG_READ(ah, AR_MCI_COMMAND2);
+	regval |= SM(1, AR_MCI_COMMAND2_RESET_TX);
+	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+	udelay(1);
+
+	regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX);
+	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+	if (is_full_sleep) {
+		ar9003_mci_mute_bt(ah);
+		udelay(100);
+	}
+
+	regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
+	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+	udelay(1);
+	regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
+	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+	ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+
+	REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
+		  (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
+		   SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM)));
+
+	REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+		    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+
+	ar9003_mci_observation_set_up(ah);
+
+	mci->ready = true;
+	ar9003_mci_prep_interface(ah);
+
+	if (en_int)
+		ar9003_mci_enable_interrupt(ah);
+}
+
+void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
+{
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+
+	ar9003_mci_disable_interrupt(ah);
+
+	if (mci_hw->ready && !save_fullsleep) {
+		ar9003_mci_mute_bt(ah);
+		udelay(20);
+		REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
+	}
+
+	mci_hw->bt_state = MCI_BT_SLEEP;
+	mci_hw->ready = false;
+}
+
+static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
+{
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	u32 new_flags, to_set, to_clear;
+
+	if (mci->update_2g5g && (mci->bt_state != MCI_BT_SLEEP)) {
+		if (mci->is_2g) {
+			new_flags = MCI_2G_FLAGS;
+			to_clear = MCI_2G_FLAGS_CLEAR_MASK;
+			to_set = MCI_2G_FLAGS_SET_MASK;
+		} else {
+			new_flags = MCI_5G_FLAGS;
+			to_clear = MCI_5G_FLAGS_CLEAR_MASK;
+			to_set = MCI_5G_FLAGS_SET_MASK;
+		}
+
+		if (to_clear)
+			ar9003_mci_send_coex_bt_flags(ah, wait_done,
+					      MCI_GPM_COEX_BT_FLAGS_CLEAR,
+					      to_clear);
+		if (to_set)
+			ar9003_mci_send_coex_bt_flags(ah, wait_done,
+					      MCI_GPM_COEX_BT_FLAGS_SET,
+					      to_set);
+	}
+}
+
+static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
+					u32 *payload, bool queue)
+{
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	u8 type, opcode;
+
+	/* check if the message is to be queued */
+	if (header != MCI_GPM)
+		return;
+
+	type = MCI_GPM_TYPE(payload);
+	opcode = MCI_GPM_OPCODE(payload);
+
+	if (type != MCI_GPM_COEX_AGENT)
+		return;
+
+	switch (opcode) {
+	case MCI_GPM_COEX_BT_UPDATE_FLAGS:
+		if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) ==
+		    MCI_GPM_COEX_BT_FLAGS_READ)
+			break;
+
+		mci->update_2g5g = queue;
+
+		break;
+	case MCI_GPM_COEX_WLAN_CHANNELS:
+		mci->wlan_channels_update = queue;
+		break;
+	case MCI_GPM_COEX_HALT_BT_GPM:
+		if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
+		    MCI_GPM_COEX_BT_GPM_UNHALT) {
+			mci->unhalt_bt_gpm = queue;
+
+			if (!queue)
+				mci->halted_bt_gpm = false;
+		}
+
+		if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
+				MCI_GPM_COEX_BT_GPM_HALT) {
+
+			mci->halted_bt_gpm = !queue;
+		}
+
+		break;
+	default:
+		break;
+	}
+}
+
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
+{
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+	if (mci->update_2g5g) {
+		if (mci->is_2g) {
+			ar9003_mci_send_2g5g_status(ah, true);
+			ar9003_mci_send_lna_transfer(ah, true);
+			udelay(5);
+
+			REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+				    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+			REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
+				    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+
+			if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
+				REG_SET_BIT(ah, AR_BTCOEX_CTRL,
+					    AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+			}
+		} else {
+			ar9003_mci_send_lna_take(ah, true);
+			udelay(5);
+
+			REG_SET_BIT(ah, AR_MCI_TX_CTRL,
+				    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+			REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+				    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+			REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
+				    AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+
+			ar9003_mci_send_2g5g_status(ah, true);
+		}
+	}
+}
+
+bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
+			     u32 *payload, u8 len, bool wait_done,
+			     bool check_bt)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	bool msg_sent = false;
+	u32 regval;
+	u32 saved_mci_int_en;
+	int i;
+
+	saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
+	regval = REG_READ(ah, AR_BTCOEX_CTRL);
+
+	if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) {
+		ath_dbg(common, MCI,
+			"MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n",
+			header, (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0);
+		ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
+		return false;
+	} else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) {
+		ath_dbg(common, MCI,
+			"MCI Don't send message 0x%x. BT is in sleep state\n",
+			header);
+		ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
+		return false;
+	}
+
+	if (wait_done)
+		REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
+
+	/* Need to clear SW_MSG_DONE raw bit before wait */
+
+	REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+		  (AR_MCI_INTERRUPT_SW_MSG_DONE |
+		   AR_MCI_INTERRUPT_MSG_FAIL_MASK));
+
+	if (payload) {
+		for (i = 0; (i * 4) < len; i++)
+			REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4),
+				  *(payload + i));
+	}
+
+	REG_WRITE(ah, AR_MCI_COMMAND0,
+		  (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP),
+		      AR_MCI_COMMAND0_DISABLE_TIMESTAMP) |
+		   SM(len, AR_MCI_COMMAND0_LEN) |
+		   SM(header, AR_MCI_COMMAND0_HEADER)));
+
+	if (wait_done &&
+	    !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW,
+					    AR_MCI_INTERRUPT_SW_MSG_DONE, 500)))
+		ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
+	else {
+		ar9003_mci_queue_unsent_gpm(ah, header, payload, false);
+		msg_sent = true;
+	}
+
+	if (wait_done)
+		REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
+
+	return msg_sent;
+}
+EXPORT_SYMBOL(ar9003_mci_send_message);
+
+void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+	u32 pld[4] = {0, 0, 0, 0};
+
+	if ((mci_hw->bt_state != MCI_BT_AWAKE) ||
+	    (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))
+		return;
+
+	MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
+	pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
+
+	ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
+
+	if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
+		ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n");
+	} else {
+		is_reusable = false;
+		ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n");
+	}
+}
+
+void ar9003_mci_init_cal_done(struct ath_hw *ah)
+{
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+	u32 pld[4] = {0, 0, 0, 0};
+
+	if ((mci_hw->bt_state != MCI_BT_AWAKE) ||
+	    (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))
+		return;
+
+	MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
+	pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
+	ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
+}
+
+void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
+		      u16 len, u32 sched_addr)
+{
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+	mci->gpm_addr = gpm_addr;
+	mci->gpm_buf = gpm_buf;
+	mci->gpm_len = len;
+	mci->sched_addr = sched_addr;
+
+	ar9003_mci_reset(ah, true, true, true);
+}
+EXPORT_SYMBOL(ar9003_mci_setup);
+
+void ar9003_mci_cleanup(struct ath_hw *ah)
+{
+	/* Turn off MCI and Jupiter mode. */
+	REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00);
+	ar9003_mci_disable_interrupt(ah);
+}
+EXPORT_SYMBOL(ar9003_mci_cleanup);
+
 u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -1219,13 +1180,9 @@
 	u32 value = 0, more_gpm = 0, gpm_ptr;
 	u8 query_type;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return 0;
-
 	switch (state_type) {
 	case MCI_STATE_ENABLE:
 		if (mci->ready) {
-
 			value = REG_READ(ah, AR_BTCOEX_CTRL);
 
 			if ((value == 0xdeadbeef) || (value == 0xffffffff))
@@ -1235,7 +1192,6 @@
 		break;
 	case MCI_STATE_INIT_GPM_OFFSET:
 		value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
-		ath_dbg(common, MCI, "MCI GPM initial WRITE_PTR=%d\n", value);
 		mci->gpm_idx = value;
 		break;
 	case MCI_STATE_NEXT_GPM_OFFSET:
@@ -1258,32 +1214,21 @@
 		if (value == 0)
 			value = mci->gpm_len - 1;
 		else if (value >= mci->gpm_len) {
-			if (value != 0xFFFF) {
+			if (value != 0xFFFF)
 				value = 0;
-				ath_dbg(common, MCI,
-					"MCI GPM offset out of range\n");
-			}
-		} else
+		} else {
 			value--;
+		}
 
 		if (value == 0xFFFF) {
 			value = MCI_GPM_INVALID;
 			more_gpm = MCI_GPM_NOMORE;
-			ath_dbg(common, MCI,
-				"MCI GPM ptr invalid @ptr=%d, offset=%d, more=GPM_NOMORE\n",
-				gpm_ptr, value);
 		} else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
-
 			if (gpm_ptr == mci->gpm_idx) {
 				value = MCI_GPM_INVALID;
 				more_gpm = MCI_GPM_NOMORE;
-
-				ath_dbg(common, MCI,
-					"MCI GPM message not available @ptr=%d, @offset=%d, more=GPM_NOMORE\n",
-					gpm_ptr, value);
 			} else {
 				for (;;) {
-
 					u32 temp_index;
 
 					/* skip reserved GPM if any */
@@ -1300,13 +1245,8 @@
 					    mci->gpm_len)
 						mci->gpm_idx = 0;
 
-					ath_dbg(common, MCI,
-						"MCI GPM message got ptr=%d, @offset=%d, more=%d\n",
-						gpm_ptr, temp_index,
-						(more_gpm == MCI_GPM_MORE));
-
 					if (ar9003_mci_is_gpm_valid(ah,
-								temp_index)) {
+								    temp_index)) {
 						value = temp_index;
 						break;
 					}
@@ -1331,79 +1271,59 @@
 		/* Make it in bytes */
 		value <<= 4;
 		break;
-
 	case MCI_STATE_REMOTE_SLEEP:
 		value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
 			   AR_MCI_RX_REMOTE_SLEEP) ?
 			MCI_BT_SLEEP : MCI_BT_AWAKE;
 		break;
-
 	case MCI_STATE_CONT_RSSI_POWER:
 		value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
-			break;
-
+		break;
 	case MCI_STATE_CONT_PRIORITY:
 		value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
 		break;
-
 	case MCI_STATE_CONT_TXRX:
 		value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
 		break;
-
 	case MCI_STATE_BT:
 		value = mci->bt_state;
 		break;
-
 	case MCI_STATE_SET_BT_SLEEP:
 		mci->bt_state = MCI_BT_SLEEP;
 		break;
-
 	case MCI_STATE_SET_BT_AWAKE:
 		mci->bt_state = MCI_BT_AWAKE;
 		ar9003_mci_send_coex_version_query(ah, true);
 		ar9003_mci_send_coex_wlan_channels(ah, true);
 
-		if (mci->unhalt_bt_gpm) {
-
-			ath_dbg(common, MCI, "MCI unhalt BT GPM\n");
+		if (mci->unhalt_bt_gpm)
 			ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
-		}
 
 		ar9003_mci_2g5g_switch(ah, true);
 		break;
-
 	case MCI_STATE_SET_BT_CAL_START:
 		mci->bt_state = MCI_BT_CAL_START;
 		break;
-
 	case MCI_STATE_SET_BT_CAL:
 		mci->bt_state = MCI_BT_CAL;
 		break;
-
 	case MCI_STATE_RESET_REQ_WAKE:
 		ar9003_mci_reset_req_wakeup(ah);
 		mci->update_2g5g = true;
 
-		if ((AR_SREV_9462_20_OR_LATER(ah)) &&
-		    (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK)) {
+		if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) {
 			/* Check if we still have control of the GPIOs */
 			if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) &
-				      ATH_MCI_CONFIG_MCI_OBS_GPIO) !=
-					ATH_MCI_CONFIG_MCI_OBS_GPIO) {
-
-				ath_dbg(common, MCI,
-					"MCI reconfigure observation\n");
+			     ATH_MCI_CONFIG_MCI_OBS_GPIO) !=
+			    ATH_MCI_CONFIG_MCI_OBS_GPIO) {
 				ar9003_mci_observation_set_up(ah);
 			}
 		}
 		break;
-
 	case MCI_STATE_SEND_WLAN_COEX_VERSION:
 		ar9003_mci_send_coex_version_response(ah, true);
 		break;
-
 	case MCI_STATE_SET_BT_COEX_VERSION:
-
 		if (!p_data)
 			ath_dbg(common, MCI,
 				"MCI Set BT Coex version with NULL data!!\n");
@@ -1415,7 +1335,6 @@
 				mci->bt_ver_major, mci->bt_ver_minor);
 		}
 		break;
-
 	case MCI_STATE_SEND_WLAN_CHANNELS:
 		if (p_data) {
 			if (((mci->wlan_channels[1] & 0xffff0000) ==
@@ -1432,19 +1351,13 @@
 		mci->wlan_channels_update = true;
 		ar9003_mci_send_coex_wlan_channels(ah, true);
 		break;
-
 	case MCI_STATE_SEND_VERSION_QUERY:
 		ar9003_mci_send_coex_version_query(ah, true);
 		break;
-
 	case MCI_STATE_SEND_STATUS_QUERY:
-		query_type = (AR_SREV_9462_10(ah)) ?
-				MCI_GPM_COEX_QUERY_BT_ALL_INFO :
-				MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
-
+		query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
 		ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
 		break;
-
 	case MCI_STATE_NEED_FLUSH_BT_INFO:
 			/*
 			 * btcoex_hw.mci.unhalt_bt_gpm means whether it's
@@ -1464,28 +1377,21 @@
 				mci->need_flush_btinfo =
 					(*p_data != 0) ? true : false;
 			break;
-
 	case MCI_STATE_RECOVER_RX:
-
-		ath_dbg(common, MCI, "MCI hw RECOVER_RX\n");
 		ar9003_mci_prep_interface(ah);
 		mci->query_bt = true;
 		mci->need_flush_btinfo = true;
 		ar9003_mci_send_coex_wlan_channels(ah, true);
 		ar9003_mci_2g5g_switch(ah, true);
 		break;
-
 	case MCI_STATE_NEED_FTP_STOMP:
 		value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
 		break;
-
 	case MCI_STATE_NEED_TUNING:
 		value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
 		break;
-
 	default:
 		break;
-
 	}
 
 	return value;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
index 798da11..4842f6c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
@@ -99,4 +99,237 @@
 					 ATH_MCI_CONFIG_MCI_OBS_BT)
 #define ATH_MCI_CONFIG_MCI_OBS_GPIO     0x0000002F
 
+enum mci_message_header {		/* length of payload */
+	MCI_LNA_CTRL     = 0x10,        /* len = 0 */
+	MCI_CONT_NACK    = 0x20,        /* len = 0 */
+	MCI_CONT_INFO    = 0x30,        /* len = 4 */
+	MCI_CONT_RST     = 0x40,        /* len = 0 */
+	MCI_SCHD_INFO    = 0x50,        /* len = 16 */
+	MCI_CPU_INT      = 0x60,        /* len = 4 */
+	MCI_SYS_WAKING   = 0x70,        /* len = 0 */
+	MCI_GPM          = 0x80,        /* len = 16 */
+	MCI_LNA_INFO     = 0x90,        /* len = 1 */
+	MCI_LNA_STATE    = 0x94,
+	MCI_LNA_TAKE     = 0x98,
+	MCI_LNA_TRANS    = 0x9c,
+	MCI_SYS_SLEEPING = 0xa0,        /* len = 0 */
+	MCI_REQ_WAKE     = 0xc0,        /* len = 0 */
+	MCI_DEBUG_16     = 0xfe,        /* len = 2 */
+	MCI_REMOTE_RESET = 0xff         /* len = 16 */
+};
+
+enum ath_mci_gpm_coex_profile_type {
+	MCI_GPM_COEX_PROFILE_UNKNOWN,
+	MCI_GPM_COEX_PROFILE_RFCOMM,
+	MCI_GPM_COEX_PROFILE_A2DP,
+	MCI_GPM_COEX_PROFILE_HID,
+	MCI_GPM_COEX_PROFILE_BNEP,
+	MCI_GPM_COEX_PROFILE_VOICE,
+	MCI_GPM_COEX_PROFILE_MAX
+};
+
+/* MCI GPM/Coex opcode/type definitions */
+enum {
+	MCI_GPM_COEX_W_GPM_PAYLOAD      = 1,
+	MCI_GPM_COEX_B_GPM_TYPE         = 4,
+	MCI_GPM_COEX_B_GPM_OPCODE       = 5,
+	/* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */
+	MCI_GPM_WLAN_CAL_W_SEQUENCE     = 2,
+
+	/* MCI_GPM_COEX_VERSION_QUERY */
+	/* MCI_GPM_COEX_VERSION_RESPONSE */
+	MCI_GPM_COEX_B_MAJOR_VERSION    = 6,
+	MCI_GPM_COEX_B_MINOR_VERSION    = 7,
+	/* MCI_GPM_COEX_STATUS_QUERY */
+	MCI_GPM_COEX_B_BT_BITMAP        = 6,
+	MCI_GPM_COEX_B_WLAN_BITMAP      = 7,
+	/* MCI_GPM_COEX_HALT_BT_GPM */
+	MCI_GPM_COEX_B_HALT_STATE       = 6,
+	/* MCI_GPM_COEX_WLAN_CHANNELS */
+	MCI_GPM_COEX_B_CHANNEL_MAP      = 6,
+	/* MCI_GPM_COEX_BT_PROFILE_INFO */
+	MCI_GPM_COEX_B_PROFILE_TYPE     = 6,
+	MCI_GPM_COEX_B_PROFILE_LINKID   = 7,
+	MCI_GPM_COEX_B_PROFILE_STATE    = 8,
+	MCI_GPM_COEX_B_PROFILE_ROLE     = 9,
+	MCI_GPM_COEX_B_PROFILE_RATE     = 10,
+	MCI_GPM_COEX_B_PROFILE_VOTYPE   = 11,
+	MCI_GPM_COEX_H_PROFILE_T        = 12,
+	MCI_GPM_COEX_B_PROFILE_W        = 14,
+	MCI_GPM_COEX_B_PROFILE_A        = 15,
+	/* MCI_GPM_COEX_BT_STATUS_UPDATE */
+	MCI_GPM_COEX_B_STATUS_TYPE      = 6,
+	MCI_GPM_COEX_B_STATUS_LINKID    = 7,
+	MCI_GPM_COEX_B_STATUS_STATE     = 8,
+	/* MCI_GPM_COEX_BT_UPDATE_FLAGS */
+	MCI_GPM_COEX_W_BT_FLAGS         = 6,
+	MCI_GPM_COEX_B_BT_FLAGS_OP      = 10
+};
+
+enum mci_gpm_subtype {
+	MCI_GPM_BT_CAL_REQ      = 0,
+	MCI_GPM_BT_CAL_GRANT    = 1,
+	MCI_GPM_BT_CAL_DONE     = 2,
+	MCI_GPM_WLAN_CAL_REQ    = 3,
+	MCI_GPM_WLAN_CAL_GRANT  = 4,
+	MCI_GPM_WLAN_CAL_DONE   = 5,
+	MCI_GPM_COEX_AGENT      = 0x0c,
+	MCI_GPM_RSVD_PATTERN    = 0xfe,
+	MCI_GPM_RSVD_PATTERN32  = 0xfefefefe,
+	MCI_GPM_BT_DEBUG        = 0xff
+};
+
+enum mci_bt_state {
+	MCI_BT_SLEEP,
+	MCI_BT_AWAKE,
+	MCI_BT_CAL_START,
+	MCI_BT_CAL
+};
+
+/* Type of state query */
+enum mci_state_type {
+	MCI_STATE_ENABLE,
+	MCI_STATE_INIT_GPM_OFFSET,
+	MCI_STATE_NEXT_GPM_OFFSET,
+	MCI_STATE_LAST_GPM_OFFSET,
+	MCI_STATE_BT,
+	MCI_STATE_SET_BT_SLEEP,
+	MCI_STATE_SET_BT_AWAKE,
+	MCI_STATE_SET_BT_CAL_START,
+	MCI_STATE_SET_BT_CAL,
+	MCI_STATE_LAST_SCHD_MSG_OFFSET,
+	MCI_STATE_REMOTE_SLEEP,
+	MCI_STATE_CONT_RSSI_POWER,
+	MCI_STATE_CONT_PRIORITY,
+	MCI_STATE_CONT_TXRX,
+	MCI_STATE_RESET_REQ_WAKE,
+	MCI_STATE_SEND_WLAN_COEX_VERSION,
+	MCI_STATE_SET_BT_COEX_VERSION,
+	MCI_STATE_SEND_WLAN_CHANNELS,
+	MCI_STATE_SEND_VERSION_QUERY,
+	MCI_STATE_SEND_STATUS_QUERY,
+	MCI_STATE_NEED_FLUSH_BT_INFO,
+	MCI_STATE_SET_CONCUR_TX_PRI,
+	MCI_STATE_RECOVER_RX,
+	MCI_STATE_NEED_FTP_STOMP,
+	MCI_STATE_NEED_TUNING,
+	MCI_STATE_DEBUG,
+	MCI_STATE_MAX
+};
+
+enum mci_gpm_coex_opcode {
+	MCI_GPM_COEX_VERSION_QUERY,
+	MCI_GPM_COEX_VERSION_RESPONSE,
+	MCI_GPM_COEX_STATUS_QUERY,
+	MCI_GPM_COEX_HALT_BT_GPM,
+	MCI_GPM_COEX_WLAN_CHANNELS,
+	MCI_GPM_COEX_BT_PROFILE_INFO,
+	MCI_GPM_COEX_BT_STATUS_UPDATE,
+	MCI_GPM_COEX_BT_UPDATE_FLAGS
+};
+
+#define MCI_GPM_NOMORE  0
+#define MCI_GPM_MORE    1
+#define MCI_GPM_INVALID 0xffffffff
+
+#define MCI_GPM_RECYCLE(_p_gpm)	do {			  \
+	*(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \
+				MCI_GPM_RSVD_PATTERN32;   \
+} while (0)
+
+#define MCI_GPM_TYPE(_p_gpm)	\
+	(*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff)
+
+#define MCI_GPM_OPCODE(_p_gpm)	\
+	(*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff)
+
+#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type)	do {			   \
+	*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\
+} while (0)
+
+#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do {		   \
+	*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff;	   \
+	*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\
+} while (0)
+
+#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE)
+
+/*
+ * Functions that are available to the MCI driver core.
+ */
+bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
+			     u32 *payload, u8 len, bool wait_done,
+			     bool check_bt);
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
+void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
+		      u16 len, u32 sched_addr);
+void ar9003_mci_cleanup(struct ath_hw *ah);
+void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
+			      u32 *rx_msg_intr);
+
+/*
+ * These functions are used by ath9k_hw.
+ */
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+
+static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
+{
+	return ah->btcoex_hw.mci.ready;
+}
+void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep);
+void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable);
+void ar9003_mci_init_cal_done(struct ath_hw *ah);
+void ar9003_mci_set_full_sleep(struct ath_hw *ah);
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_check_bt(struct ath_hw *ah);
+bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan);
+int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+			 struct ath9k_hw_cal_data *caldata);
+void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+		      bool is_full_sleep);
+void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
+
+#else
+
+static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
+{
+	return false;
+}
+static inline void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
+{
+}
+static inline void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
+{
+}
+static inline void ar9003_mci_init_cal_done(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_set_full_sleep(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
+{
+}
+static inline void ar9003_mci_check_bt(struct ath_hw *ah)
+{
+}
+static inline bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	return false;
+}
+static inline int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+				       struct ath9k_hw_cal_data *caldata)
+{
+	return 0;
+}
+static inline void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+				    bool is_full_sleep)
+{
+}
+static inline void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
+
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 2b0bfb8..70e27d2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1099,13 +1099,20 @@
 {
 	ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
 	ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
-	if (AR_SREV_9330(ah))
-		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9330_2GHZ;
-	else
-		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
+	ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
 	ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
 	ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
 	ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ;
+
+	if (AR_SREV_9330(ah))
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9330_2GHZ;
+
+	if (AR_SREV_9462(ah)) {
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9462_2GHZ;
+		ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ;
+		ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9462_5GHZ;
+	}
 }
 
 /*
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index ed64114..d834d97 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -325,13 +325,18 @@
 
 #define AR_PHY_RX_OCGAIN        (AR_AGC_BASE + 0x200)
 
-#define AR_PHY_CCA_NOM_VAL_9300_2GHZ          (AR_SREV_9462(ah) ? -127 : -110)
-#define AR_PHY_CCA_NOM_VAL_9300_5GHZ          (AR_SREV_9462(ah) ? -127 : -115)
-#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     (AR_SREV_9462(ah) ? -127 : -125)
-#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     (AR_SREV_9462(ah) ? -127 : -125)
+#define AR_PHY_CCA_NOM_VAL_9300_2GHZ          -110
+#define AR_PHY_CCA_NOM_VAL_9300_5GHZ          -115
+#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     -125
+#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     -125
 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -95
 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -100
 
+#define AR_PHY_CCA_NOM_VAL_9462_2GHZ          -127
+#define AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ     -127
+#define AR_PHY_CCA_NOM_VAL_9462_5GHZ          -127
+#define AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ     -127
+
 #define AR_PHY_CCA_NOM_VAL_9330_2GHZ          -118
 
 /*
@@ -612,16 +617,14 @@
 #define AR_PHY_AIC_CTRL_1_B0	(AR_SM_BASE + 0x4b4)
 #define AR_PHY_AIC_CTRL_2_B0	(AR_SM_BASE + 0x4b8)
 #define AR_PHY_AIC_CTRL_3_B0	(AR_SM_BASE + 0x4bc)
-#define AR_PHY_AIC_STAT_0_B0	(AR_SM_BASE + (AR_SREV_9462_10(ah) ? \
-					0x4c0 : 0x4c4))
-#define AR_PHY_AIC_STAT_1_B0	(AR_SM_BASE + (AR_SREV_9462_10(ah) ? \
-					0x4c4 : 0x4c8))
+#define AR_PHY_AIC_STAT_0_B0	(AR_SM_BASE + 0x4c4))
+#define AR_PHY_AIC_STAT_1_B0	(AR_SM_BASE + 0x4c8))
 #define AR_PHY_AIC_CTRL_4_B0	(AR_SM_BASE + 0x4c0)
 #define AR_PHY_AIC_STAT_2_B0	(AR_SM_BASE + 0x4cc)
 
 #define AR_PHY_65NM_CH0_SYNTH4      0x1608c
-#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   0x00000002
-#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S 1
+#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002)
+#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1)
 #define AR_PHY_65NM_CH0_SYNTH7      0x16098
 #define AR_PHY_65NM_CH0_BIAS1       0x160c0
 #define AR_PHY_65NM_CH0_BIAS2       0x160c4
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h
deleted file mode 100644
index 5c55ae3..0000000
--- a/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h
+++ /dev/null
@@ -1,1833 +0,0 @@
-/*
- * Copyright (c) 2010 Atheros Communications Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef INITVALS_9462_1P0_H
-#define INITVALS_9462_1P0_H
-
-/* AR9462 1.0 */
-
-static const u32 ar9462_1p0_mac_core[][2] = {
-	/* Addr      allmodes  */
-	{0x00000008, 0x00000000},
-	{0x00000030, 0x00060085},
-	{0x00000034, 0x00000005},
-	{0x00000040, 0x00000000},
-	{0x00000044, 0x00000000},
-	{0x00000048, 0x00000008},
-	{0x0000004c, 0x00000010},
-	{0x00000050, 0x00000000},
-	{0x00001040, 0x002ffc0f},
-	{0x00001044, 0x002ffc0f},
-	{0x00001048, 0x002ffc0f},
-	{0x0000104c, 0x002ffc0f},
-	{0x00001050, 0x002ffc0f},
-	{0x00001054, 0x002ffc0f},
-	{0x00001058, 0x002ffc0f},
-	{0x0000105c, 0x002ffc0f},
-	{0x00001060, 0x002ffc0f},
-	{0x00001064, 0x002ffc0f},
-	{0x000010f0, 0x00000100},
-	{0x00001270, 0x00000000},
-	{0x000012b0, 0x00000000},
-	{0x000012f0, 0x00000000},
-	{0x0000143c, 0x00000000},
-	{0x0000147c, 0x00000000},
-	{0x00001810, 0x0f000003},
-	{0x00008000, 0x00000000},
-	{0x00008004, 0x00000000},
-	{0x00008008, 0x00000000},
-	{0x0000800c, 0x00000000},
-	{0x00008018, 0x00000000},
-	{0x00008020, 0x00000000},
-	{0x00008038, 0x00000000},
-	{0x0000803c, 0x00080000},
-	{0x00008040, 0x00000000},
-	{0x00008044, 0x00000000},
-	{0x00008048, 0x00000000},
-	{0x0000804c, 0xffffffff},
-	{0x00008050, 0xffffffff},
-	{0x00008054, 0x00000000},
-	{0x00008058, 0x00000000},
-	{0x0000805c, 0x000fc78f},
-	{0x00008060, 0x0000000f},
-	{0x00008064, 0x00000000},
-	{0x00008070, 0x00000310},
-	{0x00008074, 0x00000020},
-	{0x00008078, 0x00000000},
-	{0x0000809c, 0x0000000f},
-	{0x000080a0, 0x00000000},
-	{0x000080a4, 0x02ff0000},
-	{0x000080a8, 0x0e070605},
-	{0x000080ac, 0x0000000d},
-	{0x000080b0, 0x00000000},
-	{0x000080b4, 0x00000000},
-	{0x000080b8, 0x00000000},
-	{0x000080bc, 0x00000000},
-	{0x000080c0, 0x2a800000},
-	{0x000080c4, 0x06900168},
-	{0x000080c8, 0x13881c20},
-	{0x000080cc, 0x01f40000},
-	{0x000080d0, 0x00252500},
-	{0x000080d4, 0x00a00005},
-	{0x000080d8, 0x00400002},
-	{0x000080dc, 0x00000000},
-	{0x000080e0, 0xffffffff},
-	{0x000080e4, 0x0000ffff},
-	{0x000080e8, 0x3f3f3f3f},
-	{0x000080ec, 0x00000000},
-	{0x000080f0, 0x00000000},
-	{0x000080f4, 0x00000000},
-	{0x000080fc, 0x00020000},
-	{0x00008100, 0x00000000},
-	{0x00008108, 0x00000052},
-	{0x0000810c, 0x00000000},
-	{0x00008110, 0x00000000},
-	{0x00008114, 0x000007ff},
-	{0x00008118, 0x000000aa},
-	{0x0000811c, 0x00003210},
-	{0x00008124, 0x00000000},
-	{0x00008128, 0x00000000},
-	{0x0000812c, 0x00000000},
-	{0x00008130, 0x00000000},
-	{0x00008134, 0x00000000},
-	{0x00008138, 0x00000000},
-	{0x0000813c, 0x0000ffff},
-	{0x00008144, 0xffffffff},
-	{0x00008168, 0x00000000},
-	{0x0000816c, 0x00000000},
-	{0x00008170, 0x18486e00},
-	{0x00008174, 0x33332210},
-	{0x00008178, 0x00000000},
-	{0x0000817c, 0x00020000},
-	{0x000081c4, 0x33332210},
-	{0x000081c8, 0x00000000},
-	{0x000081cc, 0x00000000},
-	{0x000081d4, 0x00000000},
-	{0x000081ec, 0x00000000},
-	{0x000081f0, 0x00000000},
-	{0x000081f4, 0x00000000},
-	{0x000081f8, 0x00000000},
-	{0x000081fc, 0x00000000},
-	{0x00008240, 0x00100000},
-	{0x00008244, 0x0010f400},
-	{0x00008248, 0x00000800},
-	{0x0000824c, 0x0001e800},
-	{0x00008250, 0x00000000},
-	{0x00008254, 0x00000000},
-	{0x00008258, 0x00000000},
-	{0x0000825c, 0x40000000},
-	{0x00008260, 0x00080922},
-	{0x00008264, 0x99c00010},
-	{0x00008268, 0xffffffff},
-	{0x0000826c, 0x0000ffff},
-	{0x00008270, 0x00000000},
-	{0x00008274, 0x40000000},
-	{0x00008278, 0x003e4180},
-	{0x0000827c, 0x00000004},
-	{0x00008284, 0x0000002c},
-	{0x00008288, 0x0000002c},
-	{0x0000828c, 0x000000ff},
-	{0x00008294, 0x00000000},
-	{0x00008298, 0x00000000},
-	{0x0000829c, 0x00000000},
-	{0x00008300, 0x00000140},
-	{0x00008314, 0x00000000},
-	{0x0000831c, 0x0000010d},
-	{0x00008328, 0x00000000},
-	{0x0000832c, 0x0000001f},
-	{0x00008330, 0x00000302},
-	{0x00008334, 0x00000700},
-	{0x00008338, 0xffff0000},
-	{0x0000833c, 0x02400000},
-	{0x00008340, 0x000107ff},
-	{0x00008344, 0xaa48105b},
-	{0x00008348, 0x008f0000},
-	{0x0000835c, 0x00000000},
-	{0x00008360, 0xffffffff},
-	{0x00008364, 0xffffffff},
-	{0x00008368, 0x00000000},
-	{0x00008370, 0x00000000},
-	{0x00008374, 0x000000ff},
-	{0x00008378, 0x00000000},
-	{0x0000837c, 0x00000000},
-	{0x00008380, 0xffffffff},
-	{0x00008384, 0xffffffff},
-	{0x00008390, 0xffffffff},
-	{0x00008394, 0xffffffff},
-	{0x00008398, 0x00000000},
-	{0x0000839c, 0x00000000},
-	{0x000083a4, 0x0000fa14},
-	{0x000083a8, 0x000f0c00},
-	{0x000083ac, 0x33332210},
-	{0x000083b0, 0x33332210},
-	{0x000083b4, 0x33332210},
-	{0x000083b8, 0x33332210},
-	{0x000083bc, 0x00000000},
-	{0x000083c0, 0x00000000},
-	{0x000083c4, 0x00000000},
-	{0x000083c8, 0x00000000},
-	{0x000083cc, 0x00000200},
-	{0x000083d0, 0x000301ff},
-};
-
-static const u32 ar9462_1p0_baseband_core_txfir_coeff_japan_2484[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a398, 0x00000000},
-	{0x0000a39c, 0x6f7f0301},
-	{0x0000a3a0, 0xca9228ee},
-};
-
-static const u32 ar9462_1p0_sys3ant[][2] = {
-	/* Addr      allmodes  */
-	{0x00063280, 0x00040807},
-	{0x00063284, 0x104ccccc},
-};
-
-static const u32 ar9462_pcie_phy_clkreq_enable_L1_1p0[][2] = {
-	/* Addr      allmodes  */
-	{0x00018c00, 0x10053e5e},
-	{0x00018c04, 0x000801d8},
-	{0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9462_1p0_mac_core_emulation[][2] = {
-	/* Addr      allmodes  */
-	{0x00000030, 0x00060085},
-	{0x00000044, 0x00000008},
-	{0x0000805c, 0xffffc7ff},
-	{0x00008344, 0xaa4a105b},
-};
-
-static const u32 ar9462_common_rx_gain_table_ar9280_2p0_1p0[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a000, 0x02000101},
-	{0x0000a004, 0x02000102},
-	{0x0000a008, 0x02000103},
-	{0x0000a00c, 0x02000104},
-	{0x0000a010, 0x02000200},
-	{0x0000a014, 0x02000201},
-	{0x0000a018, 0x02000202},
-	{0x0000a01c, 0x02000203},
-	{0x0000a020, 0x02000204},
-	{0x0000a024, 0x02000205},
-	{0x0000a028, 0x02000208},
-	{0x0000a02c, 0x02000302},
-	{0x0000a030, 0x02000303},
-	{0x0000a034, 0x02000304},
-	{0x0000a038, 0x02000400},
-	{0x0000a03c, 0x02010300},
-	{0x0000a040, 0x02010301},
-	{0x0000a044, 0x02010302},
-	{0x0000a048, 0x02000500},
-	{0x0000a04c, 0x02010400},
-	{0x0000a050, 0x02020300},
-	{0x0000a054, 0x02020301},
-	{0x0000a058, 0x02020302},
-	{0x0000a05c, 0x02020303},
-	{0x0000a060, 0x02020400},
-	{0x0000a064, 0x02030300},
-	{0x0000a068, 0x02030301},
-	{0x0000a06c, 0x02030302},
-	{0x0000a070, 0x02030303},
-	{0x0000a074, 0x02030400},
-	{0x0000a078, 0x02040300},
-	{0x0000a07c, 0x02040301},
-	{0x0000a080, 0x02040302},
-	{0x0000a084, 0x02040303},
-	{0x0000a088, 0x02030500},
-	{0x0000a08c, 0x02040400},
-	{0x0000a090, 0x02050203},
-	{0x0000a094, 0x02050204},
-	{0x0000a098, 0x02050205},
-	{0x0000a09c, 0x02040500},
-	{0x0000a0a0, 0x02050301},
-	{0x0000a0a4, 0x02050302},
-	{0x0000a0a8, 0x02050303},
-	{0x0000a0ac, 0x02050400},
-	{0x0000a0b0, 0x02050401},
-	{0x0000a0b4, 0x02050402},
-	{0x0000a0b8, 0x02050403},
-	{0x0000a0bc, 0x02050500},
-	{0x0000a0c0, 0x02050501},
-	{0x0000a0c4, 0x02050502},
-	{0x0000a0c8, 0x02050503},
-	{0x0000a0cc, 0x02050504},
-	{0x0000a0d0, 0x02050600},
-	{0x0000a0d4, 0x02050601},
-	{0x0000a0d8, 0x02050602},
-	{0x0000a0dc, 0x02050603},
-	{0x0000a0e0, 0x02050604},
-	{0x0000a0e4, 0x02050700},
-	{0x0000a0e8, 0x02050701},
-	{0x0000a0ec, 0x02050702},
-	{0x0000a0f0, 0x02050703},
-	{0x0000a0f4, 0x02050704},
-	{0x0000a0f8, 0x02050705},
-	{0x0000a0fc, 0x02050708},
-	{0x0000a100, 0x02050709},
-	{0x0000a104, 0x0205070a},
-	{0x0000a108, 0x0205070b},
-	{0x0000a10c, 0x0205070c},
-	{0x0000a110, 0x0205070d},
-	{0x0000a114, 0x02050710},
-	{0x0000a118, 0x02050711},
-	{0x0000a11c, 0x02050712},
-	{0x0000a120, 0x02050713},
-	{0x0000a124, 0x02050714},
-	{0x0000a128, 0x02050715},
-	{0x0000a12c, 0x02050730},
-	{0x0000a130, 0x02050731},
-	{0x0000a134, 0x02050732},
-	{0x0000a138, 0x02050733},
-	{0x0000a13c, 0x02050734},
-	{0x0000a140, 0x02050735},
-	{0x0000a144, 0x02050750},
-	{0x0000a148, 0x02050751},
-	{0x0000a14c, 0x02050752},
-	{0x0000a150, 0x02050753},
-	{0x0000a154, 0x02050754},
-	{0x0000a158, 0x02050755},
-	{0x0000a15c, 0x02050770},
-	{0x0000a160, 0x02050771},
-	{0x0000a164, 0x02050772},
-	{0x0000a168, 0x02050773},
-	{0x0000a16c, 0x02050774},
-	{0x0000a170, 0x02050775},
-	{0x0000a174, 0x00000776},
-	{0x0000a178, 0x00000776},
-	{0x0000a17c, 0x00000776},
-	{0x0000a180, 0x00000776},
-	{0x0000a184, 0x00000776},
-	{0x0000a188, 0x00000776},
-	{0x0000a18c, 0x00000776},
-	{0x0000a190, 0x00000776},
-	{0x0000a194, 0x00000776},
-	{0x0000a198, 0x00000776},
-	{0x0000a19c, 0x00000776},
-	{0x0000a1a0, 0x00000776},
-	{0x0000a1a4, 0x00000776},
-	{0x0000a1a8, 0x00000776},
-	{0x0000a1ac, 0x00000776},
-	{0x0000a1b0, 0x00000776},
-	{0x0000a1b4, 0x00000776},
-	{0x0000a1b8, 0x00000776},
-	{0x0000a1bc, 0x00000776},
-	{0x0000a1c0, 0x00000776},
-	{0x0000a1c4, 0x00000776},
-	{0x0000a1c8, 0x00000776},
-	{0x0000a1cc, 0x00000776},
-	{0x0000a1d0, 0x00000776},
-	{0x0000a1d4, 0x00000776},
-	{0x0000a1d8, 0x00000776},
-	{0x0000a1dc, 0x00000776},
-	{0x0000a1e0, 0x00000776},
-	{0x0000a1e4, 0x00000776},
-	{0x0000a1e8, 0x00000776},
-	{0x0000a1ec, 0x00000776},
-	{0x0000a1f0, 0x00000776},
-	{0x0000a1f4, 0x00000776},
-	{0x0000a1f8, 0x00000776},
-	{0x0000a1fc, 0x00000776},
-	{0x0000b000, 0x02000101},
-	{0x0000b004, 0x02000102},
-	{0x0000b008, 0x02000103},
-	{0x0000b00c, 0x02000104},
-	{0x0000b010, 0x02000200},
-	{0x0000b014, 0x02000201},
-	{0x0000b018, 0x02000202},
-	{0x0000b01c, 0x02000203},
-	{0x0000b020, 0x02000204},
-	{0x0000b024, 0x02000205},
-	{0x0000b028, 0x02000208},
-	{0x0000b02c, 0x02000302},
-	{0x0000b030, 0x02000303},
-	{0x0000b034, 0x02000304},
-	{0x0000b038, 0x02000400},
-	{0x0000b03c, 0x02010300},
-	{0x0000b040, 0x02010301},
-	{0x0000b044, 0x02010302},
-	{0x0000b048, 0x02000500},
-	{0x0000b04c, 0x02010400},
-	{0x0000b050, 0x02020300},
-	{0x0000b054, 0x02020301},
-	{0x0000b058, 0x02020302},
-	{0x0000b05c, 0x02020303},
-	{0x0000b060, 0x02020400},
-	{0x0000b064, 0x02030300},
-	{0x0000b068, 0x02030301},
-	{0x0000b06c, 0x02030302},
-	{0x0000b070, 0x02030303},
-	{0x0000b074, 0x02030400},
-	{0x0000b078, 0x02040300},
-	{0x0000b07c, 0x02040301},
-	{0x0000b080, 0x02040302},
-	{0x0000b084, 0x02040303},
-	{0x0000b088, 0x02030500},
-	{0x0000b08c, 0x02040400},
-	{0x0000b090, 0x02050203},
-	{0x0000b094, 0x02050204},
-	{0x0000b098, 0x02050205},
-	{0x0000b09c, 0x02040500},
-	{0x0000b0a0, 0x02050301},
-	{0x0000b0a4, 0x02050302},
-	{0x0000b0a8, 0x02050303},
-	{0x0000b0ac, 0x02050400},
-	{0x0000b0b0, 0x02050401},
-	{0x0000b0b4, 0x02050402},
-	{0x0000b0b8, 0x02050403},
-	{0x0000b0bc, 0x02050500},
-	{0x0000b0c0, 0x02050501},
-	{0x0000b0c4, 0x02050502},
-	{0x0000b0c8, 0x02050503},
-	{0x0000b0cc, 0x02050504},
-	{0x0000b0d0, 0x02050600},
-	{0x0000b0d4, 0x02050601},
-	{0x0000b0d8, 0x02050602},
-	{0x0000b0dc, 0x02050603},
-	{0x0000b0e0, 0x02050604},
-	{0x0000b0e4, 0x02050700},
-	{0x0000b0e8, 0x02050701},
-	{0x0000b0ec, 0x02050702},
-	{0x0000b0f0, 0x02050703},
-	{0x0000b0f4, 0x02050704},
-	{0x0000b0f8, 0x02050705},
-	{0x0000b0fc, 0x02050708},
-	{0x0000b100, 0x02050709},
-	{0x0000b104, 0x0205070a},
-	{0x0000b108, 0x0205070b},
-	{0x0000b10c, 0x0205070c},
-	{0x0000b110, 0x0205070d},
-	{0x0000b114, 0x02050710},
-	{0x0000b118, 0x02050711},
-	{0x0000b11c, 0x02050712},
-	{0x0000b120, 0x02050713},
-	{0x0000b124, 0x02050714},
-	{0x0000b128, 0x02050715},
-	{0x0000b12c, 0x02050730},
-	{0x0000b130, 0x02050731},
-	{0x0000b134, 0x02050732},
-	{0x0000b138, 0x02050733},
-	{0x0000b13c, 0x02050734},
-	{0x0000b140, 0x02050735},
-	{0x0000b144, 0x02050750},
-	{0x0000b148, 0x02050751},
-	{0x0000b14c, 0x02050752},
-	{0x0000b150, 0x02050753},
-	{0x0000b154, 0x02050754},
-	{0x0000b158, 0x02050755},
-	{0x0000b15c, 0x02050770},
-	{0x0000b160, 0x02050771},
-	{0x0000b164, 0x02050772},
-	{0x0000b168, 0x02050773},
-	{0x0000b16c, 0x02050774},
-	{0x0000b170, 0x02050775},
-	{0x0000b174, 0x00000776},
-	{0x0000b178, 0x00000776},
-	{0x0000b17c, 0x00000776},
-	{0x0000b180, 0x00000776},
-	{0x0000b184, 0x00000776},
-	{0x0000b188, 0x00000776},
-	{0x0000b18c, 0x00000776},
-	{0x0000b190, 0x00000776},
-	{0x0000b194, 0x00000776},
-	{0x0000b198, 0x00000776},
-	{0x0000b19c, 0x00000776},
-	{0x0000b1a0, 0x00000776},
-	{0x0000b1a4, 0x00000776},
-	{0x0000b1a8, 0x00000776},
-	{0x0000b1ac, 0x00000776},
-	{0x0000b1b0, 0x00000776},
-	{0x0000b1b4, 0x00000776},
-	{0x0000b1b8, 0x00000776},
-	{0x0000b1bc, 0x00000776},
-	{0x0000b1c0, 0x00000776},
-	{0x0000b1c4, 0x00000776},
-	{0x0000b1c8, 0x00000776},
-	{0x0000b1cc, 0x00000776},
-	{0x0000b1d0, 0x00000776},
-	{0x0000b1d4, 0x00000776},
-	{0x0000b1d8, 0x00000776},
-	{0x0000b1dc, 0x00000776},
-	{0x0000b1e0, 0x00000776},
-	{0x0000b1e4, 0x00000776},
-	{0x0000b1e8, 0x00000776},
-	{0x0000b1ec, 0x00000776},
-	{0x0000b1f0, 0x00000776},
-	{0x0000b1f4, 0x00000776},
-	{0x0000b1f8, 0x00000776},
-	{0x0000b1fc, 0x00000776},
-};
-
-static const u32 ar9200_ar9280_2p0_radio_core_1p0[][2] = {
-	/* Addr      allmodes  */
-	{0x00007800, 0x00040000},
-	{0x00007804, 0xdb005012},
-	{0x00007808, 0x04924914},
-	{0x0000780c, 0x21084210},
-	{0x00007810, 0x6d801300},
-	{0x00007814, 0x0019beff},
-	{0x00007818, 0x07e41000},
-	{0x0000781c, 0x00392000},
-	{0x00007820, 0x92592480},
-	{0x00007824, 0x00040000},
-	{0x00007828, 0xdb005012},
-	{0x0000782c, 0x04924914},
-	{0x00007830, 0x21084210},
-	{0x00007834, 0x6d801300},
-	{0x00007838, 0x0019beff},
-	{0x0000783c, 0x07e40000},
-	{0x00007840, 0x00392000},
-	{0x00007844, 0x92592480},
-	{0x00007848, 0x00100000},
-	{0x0000784c, 0x773f0567},
-	{0x00007850, 0x54214514},
-	{0x00007854, 0x12035828},
-	{0x00007858, 0x92592692},
-	{0x0000785c, 0x00000000},
-	{0x00007860, 0x56400000},
-	{0x00007864, 0x0a8e370e},
-	{0x00007868, 0xc0102850},
-	{0x0000786c, 0x812d4000},
-	{0x00007870, 0x807ec400},
-	{0x00007874, 0x001b6db0},
-	{0x00007878, 0x00376b63},
-	{0x0000787c, 0x06db6db6},
-	{0x00007880, 0x006d8000},
-	{0x00007884, 0xffeffffe},
-	{0x00007888, 0xffeffffe},
-	{0x0000788c, 0x00010000},
-	{0x00007890, 0x02060aeb},
-	{0x00007894, 0x5a108000},
-};
-
-static const u32 ar9462_1p0_baseband_postamble_emulation[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221},
-	{0x00009e44, 0x005c0000, 0x005c0000, 0x005c0000, 0x005c0000},
-	{0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
-	{0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
-	{0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111},
-	{0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20},
-	{0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c},
-	{0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a},
-	{0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c},
-	{0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc},
-	{0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4},
-	{0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc},
-	{0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede},
-	{0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e},
-	{0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e},
-	{0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e},
-	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-};
-
-static const u32 ar9462_pcie_phy_pll_on_clkreq_disable_L1_1p0[][2] = {
-	/* Addr      allmodes  */
-	{0x00018c00, 0x10012e5e},
-	{0x00018c04, 0x000801d8},
-	{0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9462_common_rx_gain_table_1p0[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a000, 0x00010000},
-	{0x0000a004, 0x00030002},
-	{0x0000a008, 0x00050004},
-	{0x0000a00c, 0x00810080},
-	{0x0000a010, 0x00830082},
-	{0x0000a014, 0x01810180},
-	{0x0000a018, 0x01830182},
-	{0x0000a01c, 0x01850184},
-	{0x0000a020, 0x01890188},
-	{0x0000a024, 0x018b018a},
-	{0x0000a028, 0x018d018c},
-	{0x0000a02c, 0x01910190},
-	{0x0000a030, 0x01930192},
-	{0x0000a034, 0x01950194},
-	{0x0000a038, 0x038a0196},
-	{0x0000a03c, 0x038c038b},
-	{0x0000a040, 0x0390038d},
-	{0x0000a044, 0x03920391},
-	{0x0000a048, 0x03940393},
-	{0x0000a04c, 0x03960395},
-	{0x0000a050, 0x00000000},
-	{0x0000a054, 0x00000000},
-	{0x0000a058, 0x00000000},
-	{0x0000a05c, 0x00000000},
-	{0x0000a060, 0x00000000},
-	{0x0000a064, 0x00000000},
-	{0x0000a068, 0x00000000},
-	{0x0000a06c, 0x00000000},
-	{0x0000a070, 0x00000000},
-	{0x0000a074, 0x00000000},
-	{0x0000a078, 0x00000000},
-	{0x0000a07c, 0x00000000},
-	{0x0000a080, 0x22222229},
-	{0x0000a084, 0x1d1d1d1d},
-	{0x0000a088, 0x1d1d1d1d},
-	{0x0000a08c, 0x1d1d1d1d},
-	{0x0000a090, 0x171d1d1d},
-	{0x0000a094, 0x11111717},
-	{0x0000a098, 0x00030311},
-	{0x0000a09c, 0x00000000},
-	{0x0000a0a0, 0x00000000},
-	{0x0000a0a4, 0x00000000},
-	{0x0000a0a8, 0x00000000},
-	{0x0000a0ac, 0x00000000},
-	{0x0000a0b0, 0x00000000},
-	{0x0000a0b4, 0x00000000},
-	{0x0000a0b8, 0x00000000},
-	{0x0000a0bc, 0x00000000},
-	{0x0000a0c0, 0x001f0000},
-	{0x0000a0c4, 0x01000101},
-	{0x0000a0c8, 0x011e011f},
-	{0x0000a0cc, 0x011c011d},
-	{0x0000a0d0, 0x02030204},
-	{0x0000a0d4, 0x02010202},
-	{0x0000a0d8, 0x021f0200},
-	{0x0000a0dc, 0x0302021e},
-	{0x0000a0e0, 0x03000301},
-	{0x0000a0e4, 0x031e031f},
-	{0x0000a0e8, 0x0402031d},
-	{0x0000a0ec, 0x04000401},
-	{0x0000a0f0, 0x041e041f},
-	{0x0000a0f4, 0x0502041d},
-	{0x0000a0f8, 0x05000501},
-	{0x0000a0fc, 0x051e051f},
-	{0x0000a100, 0x06010602},
-	{0x0000a104, 0x061f0600},
-	{0x0000a108, 0x061d061e},
-	{0x0000a10c, 0x07020703},
-	{0x0000a110, 0x07000701},
-	{0x0000a114, 0x00000000},
-	{0x0000a118, 0x00000000},
-	{0x0000a11c, 0x00000000},
-	{0x0000a120, 0x00000000},
-	{0x0000a124, 0x00000000},
-	{0x0000a128, 0x00000000},
-	{0x0000a12c, 0x00000000},
-	{0x0000a130, 0x00000000},
-	{0x0000a134, 0x00000000},
-	{0x0000a138, 0x00000000},
-	{0x0000a13c, 0x00000000},
-	{0x0000a140, 0x001f0000},
-	{0x0000a144, 0x01000101},
-	{0x0000a148, 0x011e011f},
-	{0x0000a14c, 0x011c011d},
-	{0x0000a150, 0x02030204},
-	{0x0000a154, 0x02010202},
-	{0x0000a158, 0x021f0200},
-	{0x0000a15c, 0x0302021e},
-	{0x0000a160, 0x03000301},
-	{0x0000a164, 0x031e031f},
-	{0x0000a168, 0x0402031d},
-	{0x0000a16c, 0x04000401},
-	{0x0000a170, 0x041e041f},
-	{0x0000a174, 0x0502041d},
-	{0x0000a178, 0x05000501},
-	{0x0000a17c, 0x051e051f},
-	{0x0000a180, 0x06010602},
-	{0x0000a184, 0x061f0600},
-	{0x0000a188, 0x061d061e},
-	{0x0000a18c, 0x07020703},
-	{0x0000a190, 0x07000701},
-	{0x0000a194, 0x00000000},
-	{0x0000a198, 0x00000000},
-	{0x0000a19c, 0x00000000},
-	{0x0000a1a0, 0x00000000},
-	{0x0000a1a4, 0x00000000},
-	{0x0000a1a8, 0x00000000},
-	{0x0000a1ac, 0x00000000},
-	{0x0000a1b0, 0x00000000},
-	{0x0000a1b4, 0x00000000},
-	{0x0000a1b8, 0x00000000},
-	{0x0000a1bc, 0x00000000},
-	{0x0000a1c0, 0x00000000},
-	{0x0000a1c4, 0x00000000},
-	{0x0000a1c8, 0x00000000},
-	{0x0000a1cc, 0x00000000},
-	{0x0000a1d0, 0x00000000},
-	{0x0000a1d4, 0x00000000},
-	{0x0000a1d8, 0x00000000},
-	{0x0000a1dc, 0x00000000},
-	{0x0000a1e0, 0x00000000},
-	{0x0000a1e4, 0x00000000},
-	{0x0000a1e8, 0x00000000},
-	{0x0000a1ec, 0x00000000},
-	{0x0000a1f0, 0x00000396},
-	{0x0000a1f4, 0x00000396},
-	{0x0000a1f8, 0x00000396},
-	{0x0000a1fc, 0x00000196},
-	{0x0000b000, 0x00010000},
-	{0x0000b004, 0x00030002},
-	{0x0000b008, 0x00050004},
-	{0x0000b00c, 0x00810080},
-	{0x0000b010, 0x00830082},
-	{0x0000b014, 0x01810180},
-	{0x0000b018, 0x01830182},
-	{0x0000b01c, 0x01850184},
-	{0x0000b020, 0x02810280},
-	{0x0000b024, 0x02830282},
-	{0x0000b028, 0x02850284},
-	{0x0000b02c, 0x02890288},
-	{0x0000b030, 0x028b028a},
-	{0x0000b034, 0x0388028c},
-	{0x0000b038, 0x038a0389},
-	{0x0000b03c, 0x038c038b},
-	{0x0000b040, 0x0390038d},
-	{0x0000b044, 0x03920391},
-	{0x0000b048, 0x03940393},
-	{0x0000b04c, 0x03960395},
-	{0x0000b050, 0x00000000},
-	{0x0000b054, 0x00000000},
-	{0x0000b058, 0x00000000},
-	{0x0000b05c, 0x00000000},
-	{0x0000b060, 0x00000000},
-	{0x0000b064, 0x00000000},
-	{0x0000b068, 0x00000000},
-	{0x0000b06c, 0x00000000},
-	{0x0000b070, 0x00000000},
-	{0x0000b074, 0x00000000},
-	{0x0000b078, 0x00000000},
-	{0x0000b07c, 0x00000000},
-	{0x0000b080, 0x2a2d2f32},
-	{0x0000b084, 0x21232328},
-	{0x0000b088, 0x19191c1e},
-	{0x0000b08c, 0x12141417},
-	{0x0000b090, 0x07070e0e},
-	{0x0000b094, 0x03030305},
-	{0x0000b098, 0x00000003},
-	{0x0000b09c, 0x00000000},
-	{0x0000b0a0, 0x00000000},
-	{0x0000b0a4, 0x00000000},
-	{0x0000b0a8, 0x00000000},
-	{0x0000b0ac, 0x00000000},
-	{0x0000b0b0, 0x00000000},
-	{0x0000b0b4, 0x00000000},
-	{0x0000b0b8, 0x00000000},
-	{0x0000b0bc, 0x00000000},
-	{0x0000b0c0, 0x003f0020},
-	{0x0000b0c4, 0x00400041},
-	{0x0000b0c8, 0x0140005f},
-	{0x0000b0cc, 0x0160015f},
-	{0x0000b0d0, 0x017e017f},
-	{0x0000b0d4, 0x02410242},
-	{0x0000b0d8, 0x025f0240},
-	{0x0000b0dc, 0x027f0260},
-	{0x0000b0e0, 0x0341027e},
-	{0x0000b0e4, 0x035f0340},
-	{0x0000b0e8, 0x037f0360},
-	{0x0000b0ec, 0x04400441},
-	{0x0000b0f0, 0x0460045f},
-	{0x0000b0f4, 0x0541047f},
-	{0x0000b0f8, 0x055f0540},
-	{0x0000b0fc, 0x057f0560},
-	{0x0000b100, 0x06400641},
-	{0x0000b104, 0x0660065f},
-	{0x0000b108, 0x067e067f},
-	{0x0000b10c, 0x07410742},
-	{0x0000b110, 0x075f0740},
-	{0x0000b114, 0x077f0760},
-	{0x0000b118, 0x07800781},
-	{0x0000b11c, 0x07a0079f},
-	{0x0000b120, 0x07c107bf},
-	{0x0000b124, 0x000007c0},
-	{0x0000b128, 0x00000000},
-	{0x0000b12c, 0x00000000},
-	{0x0000b130, 0x00000000},
-	{0x0000b134, 0x00000000},
-	{0x0000b138, 0x00000000},
-	{0x0000b13c, 0x00000000},
-	{0x0000b140, 0x003f0020},
-	{0x0000b144, 0x00400041},
-	{0x0000b148, 0x0140005f},
-	{0x0000b14c, 0x0160015f},
-	{0x0000b150, 0x017e017f},
-	{0x0000b154, 0x02410242},
-	{0x0000b158, 0x025f0240},
-	{0x0000b15c, 0x027f0260},
-	{0x0000b160, 0x0341027e},
-	{0x0000b164, 0x035f0340},
-	{0x0000b168, 0x037f0360},
-	{0x0000b16c, 0x04400441},
-	{0x0000b170, 0x0460045f},
-	{0x0000b174, 0x0541047f},
-	{0x0000b178, 0x055f0540},
-	{0x0000b17c, 0x057f0560},
-	{0x0000b180, 0x06400641},
-	{0x0000b184, 0x0660065f},
-	{0x0000b188, 0x067e067f},
-	{0x0000b18c, 0x07410742},
-	{0x0000b190, 0x075f0740},
-	{0x0000b194, 0x077f0760},
-	{0x0000b198, 0x07800781},
-	{0x0000b19c, 0x07a0079f},
-	{0x0000b1a0, 0x07c107bf},
-	{0x0000b1a4, 0x000007c0},
-	{0x0000b1a8, 0x00000000},
-	{0x0000b1ac, 0x00000000},
-	{0x0000b1b0, 0x00000000},
-	{0x0000b1b4, 0x00000000},
-	{0x0000b1b8, 0x00000000},
-	{0x0000b1bc, 0x00000000},
-	{0x0000b1c0, 0x00000000},
-	{0x0000b1c4, 0x00000000},
-	{0x0000b1c8, 0x00000000},
-	{0x0000b1cc, 0x00000000},
-	{0x0000b1d0, 0x00000000},
-	{0x0000b1d4, 0x00000000},
-	{0x0000b1d8, 0x00000000},
-	{0x0000b1dc, 0x00000000},
-	{0x0000b1e0, 0x00000000},
-	{0x0000b1e4, 0x00000000},
-	{0x0000b1e8, 0x00000000},
-	{0x0000b1ec, 0x00000000},
-	{0x0000b1f0, 0x00000396},
-	{0x0000b1f4, 0x00000396},
-	{0x0000b1f8, 0x00000396},
-	{0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_modes_high_ob_db_tx_gain_table_1p0[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-	{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-	{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-	{0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-	{0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-	{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-	{0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-	{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-	{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-	{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-	{0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-	{0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-	{0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-	{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-	{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
-	{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-	{0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-	{0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-	{0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
-	{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
-	{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
-	{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
-	{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-	{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
-	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
-	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
-	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
-	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
-	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
-	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
-	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-	{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-	{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-	{0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060},
-	{0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-	{0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000},
-};
-
-static const u32 ar9462_common_wo_xlna_rx_gain_table_1p0[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a000, 0x00010000},
-	{0x0000a004, 0x00030002},
-	{0x0000a008, 0x00050004},
-	{0x0000a00c, 0x00810080},
-	{0x0000a010, 0x00830082},
-	{0x0000a014, 0x01810180},
-	{0x0000a018, 0x01830182},
-	{0x0000a01c, 0x01850184},
-	{0x0000a020, 0x01890188},
-	{0x0000a024, 0x018b018a},
-	{0x0000a028, 0x018d018c},
-	{0x0000a02c, 0x03820190},
-	{0x0000a030, 0x03840383},
-	{0x0000a034, 0x03880385},
-	{0x0000a038, 0x038a0389},
-	{0x0000a03c, 0x038c038b},
-	{0x0000a040, 0x0390038d},
-	{0x0000a044, 0x03920391},
-	{0x0000a048, 0x03940393},
-	{0x0000a04c, 0x03960395},
-	{0x0000a050, 0x00000000},
-	{0x0000a054, 0x00000000},
-	{0x0000a058, 0x00000000},
-	{0x0000a05c, 0x00000000},
-	{0x0000a060, 0x00000000},
-	{0x0000a064, 0x00000000},
-	{0x0000a068, 0x00000000},
-	{0x0000a06c, 0x00000000},
-	{0x0000a070, 0x00000000},
-	{0x0000a074, 0x00000000},
-	{0x0000a078, 0x00000000},
-	{0x0000a07c, 0x00000000},
-	{0x0000a080, 0x29292929},
-	{0x0000a084, 0x29292929},
-	{0x0000a088, 0x29292929},
-	{0x0000a08c, 0x29292929},
-	{0x0000a090, 0x22292929},
-	{0x0000a094, 0x1d1d2222},
-	{0x0000a098, 0x0c111117},
-	{0x0000a09c, 0x00030303},
-	{0x0000a0a0, 0x00000000},
-	{0x0000a0a4, 0x00000000},
-	{0x0000a0a8, 0x00000000},
-	{0x0000a0ac, 0x00000000},
-	{0x0000a0b0, 0x00000000},
-	{0x0000a0b4, 0x00000000},
-	{0x0000a0b8, 0x00000000},
-	{0x0000a0bc, 0x00000000},
-	{0x0000a0c0, 0x001f0000},
-	{0x0000a0c4, 0x01000101},
-	{0x0000a0c8, 0x011e011f},
-	{0x0000a0cc, 0x011c011d},
-	{0x0000a0d0, 0x02030204},
-	{0x0000a0d4, 0x02010202},
-	{0x0000a0d8, 0x021f0200},
-	{0x0000a0dc, 0x0302021e},
-	{0x0000a0e0, 0x03000301},
-	{0x0000a0e4, 0x031e031f},
-	{0x0000a0e8, 0x0402031d},
-	{0x0000a0ec, 0x04000401},
-	{0x0000a0f0, 0x041e041f},
-	{0x0000a0f4, 0x0502041d},
-	{0x0000a0f8, 0x05000501},
-	{0x0000a0fc, 0x051e051f},
-	{0x0000a100, 0x06010602},
-	{0x0000a104, 0x061f0600},
-	{0x0000a108, 0x061d061e},
-	{0x0000a10c, 0x07020703},
-	{0x0000a110, 0x07000701},
-	{0x0000a114, 0x00000000},
-	{0x0000a118, 0x00000000},
-	{0x0000a11c, 0x00000000},
-	{0x0000a120, 0x00000000},
-	{0x0000a124, 0x00000000},
-	{0x0000a128, 0x00000000},
-	{0x0000a12c, 0x00000000},
-	{0x0000a130, 0x00000000},
-	{0x0000a134, 0x00000000},
-	{0x0000a138, 0x00000000},
-	{0x0000a13c, 0x00000000},
-	{0x0000a140, 0x001f0000},
-	{0x0000a144, 0x01000101},
-	{0x0000a148, 0x011e011f},
-	{0x0000a14c, 0x011c011d},
-	{0x0000a150, 0x02030204},
-	{0x0000a154, 0x02010202},
-	{0x0000a158, 0x021f0200},
-	{0x0000a15c, 0x0302021e},
-	{0x0000a160, 0x03000301},
-	{0x0000a164, 0x031e031f},
-	{0x0000a168, 0x0402031d},
-	{0x0000a16c, 0x04000401},
-	{0x0000a170, 0x041e041f},
-	{0x0000a174, 0x0502041d},
-	{0x0000a178, 0x05000501},
-	{0x0000a17c, 0x051e051f},
-	{0x0000a180, 0x06010602},
-	{0x0000a184, 0x061f0600},
-	{0x0000a188, 0x061d061e},
-	{0x0000a18c, 0x07020703},
-	{0x0000a190, 0x07000701},
-	{0x0000a194, 0x00000000},
-	{0x0000a198, 0x00000000},
-	{0x0000a19c, 0x00000000},
-	{0x0000a1a0, 0x00000000},
-	{0x0000a1a4, 0x00000000},
-	{0x0000a1a8, 0x00000000},
-	{0x0000a1ac, 0x00000000},
-	{0x0000a1b0, 0x00000000},
-	{0x0000a1b4, 0x00000000},
-	{0x0000a1b8, 0x00000000},
-	{0x0000a1bc, 0x00000000},
-	{0x0000a1c0, 0x00000000},
-	{0x0000a1c4, 0x00000000},
-	{0x0000a1c8, 0x00000000},
-	{0x0000a1cc, 0x00000000},
-	{0x0000a1d0, 0x00000000},
-	{0x0000a1d4, 0x00000000},
-	{0x0000a1d8, 0x00000000},
-	{0x0000a1dc, 0x00000000},
-	{0x0000a1e0, 0x00000000},
-	{0x0000a1e4, 0x00000000},
-	{0x0000a1e8, 0x00000000},
-	{0x0000a1ec, 0x00000000},
-	{0x0000a1f0, 0x00000396},
-	{0x0000a1f4, 0x00000396},
-	{0x0000a1f8, 0x00000396},
-	{0x0000a1fc, 0x00000196},
-	{0x0000b000, 0x00010000},
-	{0x0000b004, 0x00030002},
-	{0x0000b008, 0x00050004},
-	{0x0000b00c, 0x00810080},
-	{0x0000b010, 0x00830082},
-	{0x0000b014, 0x01810180},
-	{0x0000b018, 0x01830182},
-	{0x0000b01c, 0x01850184},
-	{0x0000b020, 0x02810280},
-	{0x0000b024, 0x02830282},
-	{0x0000b028, 0x02850284},
-	{0x0000b02c, 0x02890288},
-	{0x0000b030, 0x028b028a},
-	{0x0000b034, 0x0388028c},
-	{0x0000b038, 0x038a0389},
-	{0x0000b03c, 0x038c038b},
-	{0x0000b040, 0x0390038d},
-	{0x0000b044, 0x03920391},
-	{0x0000b048, 0x03940393},
-	{0x0000b04c, 0x03960395},
-	{0x0000b050, 0x00000000},
-	{0x0000b054, 0x00000000},
-	{0x0000b058, 0x00000000},
-	{0x0000b05c, 0x00000000},
-	{0x0000b060, 0x00000000},
-	{0x0000b064, 0x00000000},
-	{0x0000b068, 0x00000000},
-	{0x0000b06c, 0x00000000},
-	{0x0000b070, 0x00000000},
-	{0x0000b074, 0x00000000},
-	{0x0000b078, 0x00000000},
-	{0x0000b07c, 0x00000000},
-	{0x0000b080, 0x32323232},
-	{0x0000b084, 0x2f2f3232},
-	{0x0000b088, 0x23282a2d},
-	{0x0000b08c, 0x1c1e2123},
-	{0x0000b090, 0x14171919},
-	{0x0000b094, 0x0e0e1214},
-	{0x0000b098, 0x03050707},
-	{0x0000b09c, 0x00030303},
-	{0x0000b0a0, 0x00000000},
-	{0x0000b0a4, 0x00000000},
-	{0x0000b0a8, 0x00000000},
-	{0x0000b0ac, 0x00000000},
-	{0x0000b0b0, 0x00000000},
-	{0x0000b0b4, 0x00000000},
-	{0x0000b0b8, 0x00000000},
-	{0x0000b0bc, 0x00000000},
-	{0x0000b0c0, 0x003f0020},
-	{0x0000b0c4, 0x00400041},
-	{0x0000b0c8, 0x0140005f},
-	{0x0000b0cc, 0x0160015f},
-	{0x0000b0d0, 0x017e017f},
-	{0x0000b0d4, 0x02410242},
-	{0x0000b0d8, 0x025f0240},
-	{0x0000b0dc, 0x027f0260},
-	{0x0000b0e0, 0x0341027e},
-	{0x0000b0e4, 0x035f0340},
-	{0x0000b0e8, 0x037f0360},
-	{0x0000b0ec, 0x04400441},
-	{0x0000b0f0, 0x0460045f},
-	{0x0000b0f4, 0x0541047f},
-	{0x0000b0f8, 0x055f0540},
-	{0x0000b0fc, 0x057f0560},
-	{0x0000b100, 0x06400641},
-	{0x0000b104, 0x0660065f},
-	{0x0000b108, 0x067e067f},
-	{0x0000b10c, 0x07410742},
-	{0x0000b110, 0x075f0740},
-	{0x0000b114, 0x077f0760},
-	{0x0000b118, 0x07800781},
-	{0x0000b11c, 0x07a0079f},
-	{0x0000b120, 0x07c107bf},
-	{0x0000b124, 0x000007c0},
-	{0x0000b128, 0x00000000},
-	{0x0000b12c, 0x00000000},
-	{0x0000b130, 0x00000000},
-	{0x0000b134, 0x00000000},
-	{0x0000b138, 0x00000000},
-	{0x0000b13c, 0x00000000},
-	{0x0000b140, 0x003f0020},
-	{0x0000b144, 0x00400041},
-	{0x0000b148, 0x0140005f},
-	{0x0000b14c, 0x0160015f},
-	{0x0000b150, 0x017e017f},
-	{0x0000b154, 0x02410242},
-	{0x0000b158, 0x025f0240},
-	{0x0000b15c, 0x027f0260},
-	{0x0000b160, 0x0341027e},
-	{0x0000b164, 0x035f0340},
-	{0x0000b168, 0x037f0360},
-	{0x0000b16c, 0x04400441},
-	{0x0000b170, 0x0460045f},
-	{0x0000b174, 0x0541047f},
-	{0x0000b178, 0x055f0540},
-	{0x0000b17c, 0x057f0560},
-	{0x0000b180, 0x06400641},
-	{0x0000b184, 0x0660065f},
-	{0x0000b188, 0x067e067f},
-	{0x0000b18c, 0x07410742},
-	{0x0000b190, 0x075f0740},
-	{0x0000b194, 0x077f0760},
-	{0x0000b198, 0x07800781},
-	{0x0000b19c, 0x07a0079f},
-	{0x0000b1a0, 0x07c107bf},
-	{0x0000b1a4, 0x000007c0},
-	{0x0000b1a8, 0x00000000},
-	{0x0000b1ac, 0x00000000},
-	{0x0000b1b0, 0x00000000},
-	{0x0000b1b4, 0x00000000},
-	{0x0000b1b8, 0x00000000},
-	{0x0000b1bc, 0x00000000},
-	{0x0000b1c0, 0x00000000},
-	{0x0000b1c4, 0x00000000},
-	{0x0000b1c8, 0x00000000},
-	{0x0000b1cc, 0x00000000},
-	{0x0000b1d0, 0x00000000},
-	{0x0000b1d4, 0x00000000},
-	{0x0000b1d8, 0x00000000},
-	{0x0000b1dc, 0x00000000},
-	{0x0000b1e0, 0x00000000},
-	{0x0000b1e4, 0x00000000},
-	{0x0000b1e8, 0x00000000},
-	{0x0000b1ec, 0x00000000},
-	{0x0000b1f0, 0x00000396},
-	{0x0000b1f4, 0x00000396},
-	{0x0000b1f8, 0x00000396},
-	{0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_1p0_mac_postamble[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
-
-static const u32 ar9462_1p0_mac_postamble_emulation[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8},
-	{0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017},
-};
-
-static const u32 ar9462_1p0_tx_gain_table_baseband_postamble_emulation[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5},
-	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002},
-	{0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004},
-	{0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c},
-	{0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b},
-	{0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a},
-	{0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a},
-	{0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a},
-	{0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a},
-	{0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a},
-	{0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a},
-	{0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a},
-	{0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a},
-};
-
-static const u32 ar9462_1p0_radio_postamble[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524},
-	{0x000160ac, 0xa4646c08, 0xa4646c08, 0x24646c08, 0x24646c08},
-	{0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70},
-	{0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
-	{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-	{0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
-	{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-};
-
-static const u32 ar9462_1p0_soc_postamble_emulation[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x00007010, 0x00001133, 0x00001133, 0x00001133, 0x00001133},
-};
-
-static const u32 ar9462_1p0_baseband_core[][2] = {
-	/* Addr      allmodes  */
-	{0x00009800, 0xafe68e30},
-	{0x00009804, 0xfd14e000},
-	{0x00009808, 0x9c0a9f6b},
-	{0x0000980c, 0x04900000},
-	{0x00009814, 0x9280c00a},
-	{0x00009818, 0x00000000},
-	{0x0000981c, 0x00020028},
-	{0x00009834, 0x6400a290},
-	{0x00009838, 0x0108ecff},
-	{0x0000983c, 0x0d000600},
-	{0x00009880, 0x201fff00},
-	{0x00009884, 0x00001042},
-	{0x000098a4, 0x00200400},
-	{0x000098b0, 0x32840bbe},
-	{0x000098d0, 0x004b6a8e},
-	{0x000098d4, 0x00000820},
-	{0x000098dc, 0x00000000},
-	{0x000098e4, 0x01ffffff},
-	{0x000098e8, 0x01ffffff},
-	{0x000098ec, 0x01ffffff},
-	{0x000098f0, 0x00000000},
-	{0x000098f4, 0x00000000},
-	{0x00009c04, 0xff55ff55},
-	{0x00009c08, 0x0320ff55},
-	{0x00009c0c, 0x00000000},
-	{0x00009c10, 0x00000000},
-	{0x00009c14, 0x00046384},
-	{0x00009c18, 0x05b6b440},
-	{0x00009c1c, 0x00b6b440},
-	{0x00009d00, 0xc080a333},
-	{0x00009d04, 0x40206c10},
-	{0x00009d08, 0x009c4060},
-	{0x00009d0c, 0x9883800a},
-	{0x00009d10, 0x01834061},
-	{0x00009d14, 0x00c0040b},
-	{0x00009d18, 0x00000000},
-	{0x00009e08, 0x0038230c},
-	{0x00009e24, 0x990bb514},
-	{0x00009e28, 0x0c6f0000},
-	{0x00009e30, 0x06336f77},
-	{0x00009e34, 0x6af6532f},
-	{0x00009e38, 0x0cc80c00},
-	{0x00009e40, 0x0d261820},
-	{0x00009e4c, 0x00001004},
-	{0x00009e50, 0x00ff03f1},
-	{0x00009e54, 0x64c355c7},
-	{0x00009e58, 0xfd897735},
-	{0x00009e5c, 0xe9198724},
-	{0x00009fc0, 0x803e4788},
-	{0x00009fc4, 0x0001efb5},
-	{0x00009fcc, 0x40000014},
-	{0x00009fd0, 0x01193b93},
-	{0x0000a20c, 0x00000000},
-	{0x0000a220, 0x00000000},
-	{0x0000a224, 0x00000000},
-	{0x0000a228, 0x10002310},
-	{0x0000a23c, 0x00000000},
-	{0x0000a244, 0x0c000000},
-	{0x0000a2a0, 0x00000001},
-	{0x0000a2c0, 0x00000001},
-	{0x0000a2c8, 0x00000000},
-	{0x0000a2cc, 0x18c43433},
-	{0x0000a2d4, 0x00000000},
-	{0x0000a2ec, 0x00000000},
-	{0x0000a2f0, 0x00000000},
-	{0x0000a2f4, 0x00000000},
-	{0x0000a2f8, 0x00000000},
-	{0x0000a344, 0x00000000},
-	{0x0000a34c, 0x00000000},
-	{0x0000a350, 0x0000a000},
-	{0x0000a364, 0x00000000},
-	{0x0000a370, 0x00000000},
-	{0x0000a390, 0x00000001},
-	{0x0000a394, 0x00000444},
-	{0x0000a398, 0x001f0e0f},
-	{0x0000a39c, 0x0075393f},
-	{0x0000a3a0, 0xb79f6427},
-	{0x0000a3a4, 0x00000000},
-	{0x0000a3a8, 0xaaaaaaaa},
-	{0x0000a3ac, 0x3c466478},
-	{0x0000a3c0, 0x20202020},
-	{0x0000a3c4, 0x22222220},
-	{0x0000a3c8, 0x20200020},
-	{0x0000a3cc, 0x20202020},
-	{0x0000a3d0, 0x20202020},
-	{0x0000a3d4, 0x20202020},
-	{0x0000a3d8, 0x20202020},
-	{0x0000a3dc, 0x20202020},
-	{0x0000a3e0, 0x20202020},
-	{0x0000a3e4, 0x20202020},
-	{0x0000a3e8, 0x20202020},
-	{0x0000a3ec, 0x20202020},
-	{0x0000a3f0, 0x00000000},
-	{0x0000a3f4, 0x00000006},
-	{0x0000a3f8, 0x0c9bd380},
-	{0x0000a3fc, 0x000f0f01},
-	{0x0000a400, 0x8fa91f01},
-	{0x0000a404, 0x00000000},
-	{0x0000a408, 0x0e79e5c6},
-	{0x0000a40c, 0x00820820},
-	{0x0000a414, 0x1ce739ce},
-	{0x0000a418, 0x2d001dce},
-	{0x0000a41c, 0x1ce739ce},
-	{0x0000a420, 0x000001ce},
-	{0x0000a424, 0x1ce739ce},
-	{0x0000a428, 0x000001ce},
-	{0x0000a42c, 0x1ce739ce},
-	{0x0000a430, 0x1ce739ce},
-	{0x0000a434, 0x00000000},
-	{0x0000a438, 0x00001801},
-	{0x0000a43c, 0x00100000},
-	{0x0000a440, 0x00000000},
-	{0x0000a444, 0x00000000},
-	{0x0000a448, 0x05000080},
-	{0x0000a44c, 0x00000001},
-	{0x0000a450, 0x00010000},
-	{0x0000a458, 0x00000000},
-	{0x0000a644, 0xbfad9d74},
-	{0x0000a648, 0x0048060a},
-	{0x0000a64c, 0x00003c37},
-	{0x0000a670, 0x03020100},
-	{0x0000a674, 0x09080504},
-	{0x0000a678, 0x0d0c0b0a},
-	{0x0000a67c, 0x13121110},
-	{0x0000a680, 0x31301514},
-	{0x0000a684, 0x35343332},
-	{0x0000a688, 0x00000036},
-	{0x0000a690, 0x00000838},
-	{0x0000a6b0, 0x0000000a},
-	{0x0000a6b4, 0x28f12c01},
-	{0x0000a7c0, 0x00000000},
-	{0x0000a7c4, 0xfffffffc},
-	{0x0000a7c8, 0x00000000},
-	{0x0000a7cc, 0x00000000},
-	{0x0000a7d0, 0x00000000},
-	{0x0000a7d4, 0x00000004},
-	{0x0000a7dc, 0x00000001},
-	{0x0000a8d0, 0x004b6a8e},
-	{0x0000a8d4, 0x00000820},
-	{0x0000a8dc, 0x00000000},
-	{0x0000a8f0, 0x00000000},
-	{0x0000a8f4, 0x00000000},
-	{0x0000b2d0, 0x00000080},
-	{0x0000b2d4, 0x00000000},
-	{0x0000b2ec, 0x00000000},
-	{0x0000b2f0, 0x00000000},
-	{0x0000b2f4, 0x00000000},
-	{0x0000b2f8, 0x00000000},
-	{0x0000b408, 0x0e79e5c0},
-	{0x0000b40c, 0x00820820},
-	{0x0000b420, 0x00000000},
-	{0x0000b6b0, 0x0000000a},
-	{0x0000b6b4, 0x00c00001},
-};
-
-static const u32 ar9462_1p0_baseband_postamble[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
-	{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
-	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
-	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
-	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
-	{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
-	{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
-	{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
-	{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
-	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
-	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
-	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
-	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
-	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
-	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
-	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782},
-	{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
-	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
-	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
-	{0x0000a204, 0x0131b7c0, 0x0131b7c4, 0x0131b7c4, 0x0131b7c0},
-	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
-	{0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f},
-	{0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
-	{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
-	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
-	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
-	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
-	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
-	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
-	{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
-	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
-	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
-	{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
-	{0x0000a288, 0x00000110, 0x00000110, 0x00100110, 0x00100110},
-	{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
-	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
-	{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
-	{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
-	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
-	{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
-	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
-	{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
-	{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
-};
-
-static const u32 ar9462_modes_fast_clock_1p0[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
-	{0x00001030, 0x00000268, 0x000004d0},
-	{0x00001070, 0x0000018c, 0x00000318},
-	{0x000010b0, 0x00000fd0, 0x00001fa0},
-	{0x00008014, 0x044c044c, 0x08980898},
-	{0x0000801c, 0x148ec02b, 0x148ec057},
-	{0x00008318, 0x000044c0, 0x00008980},
-	{0x00009e00, 0x0372131c, 0x0372131c},
-	{0x0000a230, 0x0000400b, 0x00004016},
-	{0x0000a254, 0x00000898, 0x00001130},
-};
-
-static const u32 ar9462_modes_low_ob_db_tx_gain_table_1p0[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
-	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
-	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
-	{0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
-	{0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
-	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
-	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
-	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
-	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
-	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
-	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
-	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
-	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
-	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
-	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
-	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
-	{0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
-	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
-	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
-	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
-	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
-	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
-	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
-	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
-	{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
-	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
-	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
-	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
-	{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
-	{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-	{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-	{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-	{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4},
-	{0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060},
-	{0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4},
-	{0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000},
-};
-
-static const u32 ar9462_1p0_soc_postamble[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233},
-};
-
-static const u32 ar9462_common_mixed_rx_gain_table_1p0[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a000, 0x00010000},
-	{0x0000a004, 0x00030002},
-	{0x0000a008, 0x00050004},
-	{0x0000a00c, 0x00810080},
-	{0x0000a010, 0x00830082},
-	{0x0000a014, 0x01810180},
-	{0x0000a018, 0x01830182},
-	{0x0000a01c, 0x01850184},
-	{0x0000a020, 0x01890188},
-	{0x0000a024, 0x018b018a},
-	{0x0000a028, 0x018d018c},
-	{0x0000a02c, 0x03820190},
-	{0x0000a030, 0x03840383},
-	{0x0000a034, 0x03880385},
-	{0x0000a038, 0x038a0389},
-	{0x0000a03c, 0x038c038b},
-	{0x0000a040, 0x0390038d},
-	{0x0000a044, 0x03920391},
-	{0x0000a048, 0x03940393},
-	{0x0000a04c, 0x03960395},
-	{0x0000a050, 0x00000000},
-	{0x0000a054, 0x00000000},
-	{0x0000a058, 0x00000000},
-	{0x0000a05c, 0x00000000},
-	{0x0000a060, 0x00000000},
-	{0x0000a064, 0x00000000},
-	{0x0000a068, 0x00000000},
-	{0x0000a06c, 0x00000000},
-	{0x0000a070, 0x00000000},
-	{0x0000a074, 0x00000000},
-	{0x0000a078, 0x00000000},
-	{0x0000a07c, 0x00000000},
-	{0x0000a080, 0x29292929},
-	{0x0000a084, 0x29292929},
-	{0x0000a088, 0x29292929},
-	{0x0000a08c, 0x29292929},
-	{0x0000a090, 0x22292929},
-	{0x0000a094, 0x1d1d2222},
-	{0x0000a098, 0x0c111117},
-	{0x0000a09c, 0x00030303},
-	{0x0000a0a0, 0x00000000},
-	{0x0000a0a4, 0x00000000},
-	{0x0000a0a8, 0x00000000},
-	{0x0000a0ac, 0x00000000},
-	{0x0000a0b0, 0x00000000},
-	{0x0000a0b4, 0x00000000},
-	{0x0000a0b8, 0x00000000},
-	{0x0000a0bc, 0x00000000},
-	{0x0000a0c0, 0x001f0000},
-	{0x0000a0c4, 0x01000101},
-	{0x0000a0c8, 0x011e011f},
-	{0x0000a0cc, 0x011c011d},
-	{0x0000a0d0, 0x02030204},
-	{0x0000a0d4, 0x02010202},
-	{0x0000a0d8, 0x021f0200},
-	{0x0000a0dc, 0x0302021e},
-	{0x0000a0e0, 0x03000301},
-	{0x0000a0e4, 0x031e031f},
-	{0x0000a0e8, 0x0402031d},
-	{0x0000a0ec, 0x04000401},
-	{0x0000a0f0, 0x041e041f},
-	{0x0000a0f4, 0x0502041d},
-	{0x0000a0f8, 0x05000501},
-	{0x0000a0fc, 0x051e051f},
-	{0x0000a100, 0x06010602},
-	{0x0000a104, 0x061f0600},
-	{0x0000a108, 0x061d061e},
-	{0x0000a10c, 0x07020703},
-	{0x0000a110, 0x07000701},
-	{0x0000a114, 0x00000000},
-	{0x0000a118, 0x00000000},
-	{0x0000a11c, 0x00000000},
-	{0x0000a120, 0x00000000},
-	{0x0000a124, 0x00000000},
-	{0x0000a128, 0x00000000},
-	{0x0000a12c, 0x00000000},
-	{0x0000a130, 0x00000000},
-	{0x0000a134, 0x00000000},
-	{0x0000a138, 0x00000000},
-	{0x0000a13c, 0x00000000},
-	{0x0000a140, 0x001f0000},
-	{0x0000a144, 0x01000101},
-	{0x0000a148, 0x011e011f},
-	{0x0000a14c, 0x011c011d},
-	{0x0000a150, 0x02030204},
-	{0x0000a154, 0x02010202},
-	{0x0000a158, 0x021f0200},
-	{0x0000a15c, 0x0302021e},
-	{0x0000a160, 0x03000301},
-	{0x0000a164, 0x031e031f},
-	{0x0000a168, 0x0402031d},
-	{0x0000a16c, 0x04000401},
-	{0x0000a170, 0x041e041f},
-	{0x0000a174, 0x0502041d},
-	{0x0000a178, 0x05000501},
-	{0x0000a17c, 0x051e051f},
-	{0x0000a180, 0x06010602},
-	{0x0000a184, 0x061f0600},
-	{0x0000a188, 0x061d061e},
-	{0x0000a18c, 0x07020703},
-	{0x0000a190, 0x07000701},
-	{0x0000a194, 0x00000000},
-	{0x0000a198, 0x00000000},
-	{0x0000a19c, 0x00000000},
-	{0x0000a1a0, 0x00000000},
-	{0x0000a1a4, 0x00000000},
-	{0x0000a1a8, 0x00000000},
-	{0x0000a1ac, 0x00000000},
-	{0x0000a1b0, 0x00000000},
-	{0x0000a1b4, 0x00000000},
-	{0x0000a1b8, 0x00000000},
-	{0x0000a1bc, 0x00000000},
-	{0x0000a1c0, 0x00000000},
-	{0x0000a1c4, 0x00000000},
-	{0x0000a1c8, 0x00000000},
-	{0x0000a1cc, 0x00000000},
-	{0x0000a1d0, 0x00000000},
-	{0x0000a1d4, 0x00000000},
-	{0x0000a1d8, 0x00000000},
-	{0x0000a1dc, 0x00000000},
-	{0x0000a1e0, 0x00000000},
-	{0x0000a1e4, 0x00000000},
-	{0x0000a1e8, 0x00000000},
-	{0x0000a1ec, 0x00000000},
-	{0x0000a1f0, 0x00000396},
-	{0x0000a1f4, 0x00000396},
-	{0x0000a1f8, 0x00000396},
-	{0x0000a1fc, 0x00000196},
-	{0x0000b000, 0x00010000},
-	{0x0000b004, 0x00030002},
-	{0x0000b008, 0x00050004},
-	{0x0000b00c, 0x00810080},
-	{0x0000b010, 0x00830082},
-	{0x0000b014, 0x01810180},
-	{0x0000b018, 0x01830182},
-	{0x0000b01c, 0x01850184},
-	{0x0000b020, 0x02810280},
-	{0x0000b024, 0x02830282},
-	{0x0000b028, 0x02850284},
-	{0x0000b02c, 0x02890288},
-	{0x0000b030, 0x028b028a},
-	{0x0000b034, 0x0388028c},
-	{0x0000b038, 0x038a0389},
-	{0x0000b03c, 0x038c038b},
-	{0x0000b040, 0x0390038d},
-	{0x0000b044, 0x03920391},
-	{0x0000b048, 0x03940393},
-	{0x0000b04c, 0x03960395},
-	{0x0000b050, 0x00000000},
-	{0x0000b054, 0x00000000},
-	{0x0000b058, 0x00000000},
-	{0x0000b05c, 0x00000000},
-	{0x0000b060, 0x00000000},
-	{0x0000b064, 0x00000000},
-	{0x0000b068, 0x00000000},
-	{0x0000b06c, 0x00000000},
-	{0x0000b070, 0x00000000},
-	{0x0000b074, 0x00000000},
-	{0x0000b078, 0x00000000},
-	{0x0000b07c, 0x00000000},
-	{0x0000b080, 0x2a2d2f32},
-	{0x0000b084, 0x21232328},
-	{0x0000b088, 0x19191c1e},
-	{0x0000b08c, 0x12141417},
-	{0x0000b090, 0x07070e0e},
-	{0x0000b094, 0x03030305},
-	{0x0000b098, 0x00000003},
-	{0x0000b09c, 0x00000000},
-	{0x0000b0a0, 0x00000000},
-	{0x0000b0a4, 0x00000000},
-	{0x0000b0a8, 0x00000000},
-	{0x0000b0ac, 0x00000000},
-	{0x0000b0b0, 0x00000000},
-	{0x0000b0b4, 0x00000000},
-	{0x0000b0b8, 0x00000000},
-	{0x0000b0bc, 0x00000000},
-	{0x0000b0c0, 0x003f0020},
-	{0x0000b0c4, 0x00400041},
-	{0x0000b0c8, 0x0140005f},
-	{0x0000b0cc, 0x0160015f},
-	{0x0000b0d0, 0x017e017f},
-	{0x0000b0d4, 0x02410242},
-	{0x0000b0d8, 0x025f0240},
-	{0x0000b0dc, 0x027f0260},
-	{0x0000b0e0, 0x0341027e},
-	{0x0000b0e4, 0x035f0340},
-	{0x0000b0e8, 0x037f0360},
-	{0x0000b0ec, 0x04400441},
-	{0x0000b0f0, 0x0460045f},
-	{0x0000b0f4, 0x0541047f},
-	{0x0000b0f8, 0x055f0540},
-	{0x0000b0fc, 0x057f0560},
-	{0x0000b100, 0x06400641},
-	{0x0000b104, 0x0660065f},
-	{0x0000b108, 0x067e067f},
-	{0x0000b10c, 0x07410742},
-	{0x0000b110, 0x075f0740},
-	{0x0000b114, 0x077f0760},
-	{0x0000b118, 0x07800781},
-	{0x0000b11c, 0x07a0079f},
-	{0x0000b120, 0x07c107bf},
-	{0x0000b124, 0x000007c0},
-	{0x0000b128, 0x00000000},
-	{0x0000b12c, 0x00000000},
-	{0x0000b130, 0x00000000},
-	{0x0000b134, 0x00000000},
-	{0x0000b138, 0x00000000},
-	{0x0000b13c, 0x00000000},
-	{0x0000b140, 0x003f0020},
-	{0x0000b144, 0x00400041},
-	{0x0000b148, 0x0140005f},
-	{0x0000b14c, 0x0160015f},
-	{0x0000b150, 0x017e017f},
-	{0x0000b154, 0x02410242},
-	{0x0000b158, 0x025f0240},
-	{0x0000b15c, 0x027f0260},
-	{0x0000b160, 0x0341027e},
-	{0x0000b164, 0x035f0340},
-	{0x0000b168, 0x037f0360},
-	{0x0000b16c, 0x04400441},
-	{0x0000b170, 0x0460045f},
-	{0x0000b174, 0x0541047f},
-	{0x0000b178, 0x055f0540},
-	{0x0000b17c, 0x057f0560},
-	{0x0000b180, 0x06400641},
-	{0x0000b184, 0x0660065f},
-	{0x0000b188, 0x067e067f},
-	{0x0000b18c, 0x07410742},
-	{0x0000b190, 0x075f0740},
-	{0x0000b194, 0x077f0760},
-	{0x0000b198, 0x07800781},
-	{0x0000b19c, 0x07a0079f},
-	{0x0000b1a0, 0x07c107bf},
-	{0x0000b1a4, 0x000007c0},
-	{0x0000b1a8, 0x00000000},
-	{0x0000b1ac, 0x00000000},
-	{0x0000b1b0, 0x00000000},
-	{0x0000b1b4, 0x00000000},
-	{0x0000b1b8, 0x00000000},
-	{0x0000b1bc, 0x00000000},
-	{0x0000b1c0, 0x00000000},
-	{0x0000b1c4, 0x00000000},
-	{0x0000b1c8, 0x00000000},
-	{0x0000b1cc, 0x00000000},
-	{0x0000b1d0, 0x00000000},
-	{0x0000b1d4, 0x00000000},
-	{0x0000b1d8, 0x00000000},
-	{0x0000b1dc, 0x00000000},
-	{0x0000b1e0, 0x00000000},
-	{0x0000b1e4, 0x00000000},
-	{0x0000b1e8, 0x00000000},
-	{0x0000b1ec, 0x00000000},
-	{0x0000b1f0, 0x00000396},
-	{0x0000b1f4, 0x00000396},
-	{0x0000b1f8, 0x00000396},
-	{0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_pcie_phy_clkreq_disable_L1_1p0[][2] = {
-	/* Addr      allmodes  */
-	{0x00018c00, 0x10013e5e},
-	{0x00018c04, 0x000801d8},
-	{0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9462_1p0_baseband_core_emulation[][2] = {
-	/* Addr      allmodes  */
-	{0x00009800, 0xafa68e30},
-	{0x00009884, 0x00002842},
-	{0x00009c04, 0xff55ff55},
-	{0x00009c08, 0x0320ff55},
-	{0x00009e50, 0x00000000},
-	{0x00009fcc, 0x00000014},
-	{0x0000a344, 0x00000010},
-	{0x0000a398, 0x00000000},
-	{0x0000a39c, 0x71733d01},
-	{0x0000a3a0, 0xd0ad5c12},
-	{0x0000a3c0, 0x22222220},
-	{0x0000a3c4, 0x22222222},
-	{0x0000a404, 0x00418a11},
-	{0x0000a418, 0x050001ce},
-	{0x0000a438, 0x00001800},
-	{0x0000a458, 0x01444452},
-	{0x0000a644, 0x3fad9d74},
-	{0x0000a690, 0x00000038},
-};
-
-static const u32 ar9462_1p0_radio_core[][2] = {
-	/* Addr      allmodes  */
-	{0x00016000, 0x36db6db6},
-	{0x00016004, 0x6db6db40},
-	{0x00016008, 0x73f00000},
-	{0x0001600c, 0x00000000},
-	{0x00016010, 0x6d820001},
-	{0x00016040, 0x7f80fff8},
-	{0x0001604c, 0x2699e04f},
-	{0x00016050, 0x6db6db6c},
-	{0x00016054, 0x6db60000},
-	{0x00016058, 0x6c200000},
-	{0x00016080, 0x00040000},
-	{0x00016084, 0x9a68048c},
-	{0x00016088, 0x54214514},
-	{0x0001608c, 0x12030409},
-	{0x00016090, 0x24926490},
-	{0x00016098, 0xd2888888},
-	{0x000160a0, 0x0a108ffe},
-	{0x000160a4, 0x812fc490},
-	{0x000160a8, 0x423c8000},
-	{0x000160b4, 0x92000000},
-	{0x000160b8, 0x0285dddc},
-	{0x000160bc, 0x02908888},
-	{0x000160c0, 0x00adb6d0},
-	{0x000160c4, 0x6db6db60},
-	{0x000160c8, 0x6db6db6c},
-	{0x000160cc, 0x0de6c1b0},
-	{0x00016100, 0x3fffbe04},
-	{0x00016104, 0xfff80000},
-	{0x00016108, 0x00200400},
-	{0x00016110, 0x00000000},
-	{0x00016144, 0x02084080},
-	{0x00016148, 0x000080c0},
-	{0x00016280, 0x050a0001},
-	{0x00016284, 0x3d841400},
-	{0x00016288, 0x00000000},
-	{0x0001628c, 0xe3000000},
-	{0x00016290, 0xa1005080},
-	{0x00016294, 0x00000020},
-	{0x00016298, 0x50a02900},
-	{0x00016340, 0x121e4276},
-	{0x00016344, 0x00300000},
-	{0x00016400, 0x36db6db6},
-	{0x00016404, 0x6db6db40},
-	{0x00016408, 0x73f00000},
-	{0x0001640c, 0x00000000},
-	{0x00016410, 0x6c800001},
-	{0x00016440, 0x7f80fff8},
-	{0x0001644c, 0x4699e04f},
-	{0x00016450, 0x6db6db6c},
-	{0x00016454, 0x6db60000},
-	{0x00016500, 0x3fffbe04},
-	{0x00016504, 0xfff80000},
-	{0x00016508, 0x00200400},
-	{0x00016510, 0x00000000},
-	{0x00016544, 0x02084080},
-	{0x00016548, 0x000080c0},
-};
-
-static const u32 ar9462_1p0_soc_preamble[][2] = {
-	/* Addr      allmodes  */
-	{0x00007020, 0x00000000},
-	{0x00007034, 0x00000002},
-	{0x00007038, 0x000004c2},
-};
-
-static const u32 ar9462_1p0_sys2ant[][2] = {
-	/* Addr      allmodes  */
-	{0x00063120, 0x00801980},
-};
-
-#endif /* INITVALS_9462_1P0_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
index dc2054f..b6ba1e8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
@@ -98,14 +98,6 @@
 	{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
 };
 
-static const u32 ar9462_2p0_mac_core_emulation[][2] = {
-	/* Addr      allmodes  */
-	{0x00000030, 0x000e0085},
-	{0x00000044, 0x00000008},
-	{0x0000805c, 0xffffc7ff},
-	{0x00008344, 0xaa4a105b},
-};
-
 static const u32 ar9462_common_rx_gain_table_2p0[][2] = {
 	/* Addr      allmodes  */
 	{0x0000a000, 0x00010000},
@@ -380,349 +372,6 @@
 	{0x00018c08, 0x0003580c},
 };
 
-static const u32 ar9462_2p0_sys3ant[][2] = {
-	/* Addr      allmodes  */
-	{0x00063280, 0x00040807},
-	{0x00063284, 0x104ccccc},
-};
-
-static const u32 ar9462_common_rx_gain_table_ar9280_2p0[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a000, 0x02000101},
-	{0x0000a004, 0x02000102},
-	{0x0000a008, 0x02000103},
-	{0x0000a00c, 0x02000104},
-	{0x0000a010, 0x02000200},
-	{0x0000a014, 0x02000201},
-	{0x0000a018, 0x02000202},
-	{0x0000a01c, 0x02000203},
-	{0x0000a020, 0x02000204},
-	{0x0000a024, 0x02000205},
-	{0x0000a028, 0x02000208},
-	{0x0000a02c, 0x02000302},
-	{0x0000a030, 0x02000303},
-	{0x0000a034, 0x02000304},
-	{0x0000a038, 0x02000400},
-	{0x0000a03c, 0x02010300},
-	{0x0000a040, 0x02010301},
-	{0x0000a044, 0x02010302},
-	{0x0000a048, 0x02000500},
-	{0x0000a04c, 0x02010400},
-	{0x0000a050, 0x02020300},
-	{0x0000a054, 0x02020301},
-	{0x0000a058, 0x02020302},
-	{0x0000a05c, 0x02020303},
-	{0x0000a060, 0x02020400},
-	{0x0000a064, 0x02030300},
-	{0x0000a068, 0x02030301},
-	{0x0000a06c, 0x02030302},
-	{0x0000a070, 0x02030303},
-	{0x0000a074, 0x02030400},
-	{0x0000a078, 0x02040300},
-	{0x0000a07c, 0x02040301},
-	{0x0000a080, 0x02040302},
-	{0x0000a084, 0x02040303},
-	{0x0000a088, 0x02030500},
-	{0x0000a08c, 0x02040400},
-	{0x0000a090, 0x02050203},
-	{0x0000a094, 0x02050204},
-	{0x0000a098, 0x02050205},
-	{0x0000a09c, 0x02040500},
-	{0x0000a0a0, 0x02050301},
-	{0x0000a0a4, 0x02050302},
-	{0x0000a0a8, 0x02050303},
-	{0x0000a0ac, 0x02050400},
-	{0x0000a0b0, 0x02050401},
-	{0x0000a0b4, 0x02050402},
-	{0x0000a0b8, 0x02050403},
-	{0x0000a0bc, 0x02050500},
-	{0x0000a0c0, 0x02050501},
-	{0x0000a0c4, 0x02050502},
-	{0x0000a0c8, 0x02050503},
-	{0x0000a0cc, 0x02050504},
-	{0x0000a0d0, 0x02050600},
-	{0x0000a0d4, 0x02050601},
-	{0x0000a0d8, 0x02050602},
-	{0x0000a0dc, 0x02050603},
-	{0x0000a0e0, 0x02050604},
-	{0x0000a0e4, 0x02050700},
-	{0x0000a0e8, 0x02050701},
-	{0x0000a0ec, 0x02050702},
-	{0x0000a0f0, 0x02050703},
-	{0x0000a0f4, 0x02050704},
-	{0x0000a0f8, 0x02050705},
-	{0x0000a0fc, 0x02050708},
-	{0x0000a100, 0x02050709},
-	{0x0000a104, 0x0205070a},
-	{0x0000a108, 0x0205070b},
-	{0x0000a10c, 0x0205070c},
-	{0x0000a110, 0x0205070d},
-	{0x0000a114, 0x02050710},
-	{0x0000a118, 0x02050711},
-	{0x0000a11c, 0x02050712},
-	{0x0000a120, 0x02050713},
-	{0x0000a124, 0x02050714},
-	{0x0000a128, 0x02050715},
-	{0x0000a12c, 0x02050730},
-	{0x0000a130, 0x02050731},
-	{0x0000a134, 0x02050732},
-	{0x0000a138, 0x02050733},
-	{0x0000a13c, 0x02050734},
-	{0x0000a140, 0x02050735},
-	{0x0000a144, 0x02050750},
-	{0x0000a148, 0x02050751},
-	{0x0000a14c, 0x02050752},
-	{0x0000a150, 0x02050753},
-	{0x0000a154, 0x02050754},
-	{0x0000a158, 0x02050755},
-	{0x0000a15c, 0x02050770},
-	{0x0000a160, 0x02050771},
-	{0x0000a164, 0x02050772},
-	{0x0000a168, 0x02050773},
-	{0x0000a16c, 0x02050774},
-	{0x0000a170, 0x02050775},
-	{0x0000a174, 0x00000776},
-	{0x0000a178, 0x00000776},
-	{0x0000a17c, 0x00000776},
-	{0x0000a180, 0x00000776},
-	{0x0000a184, 0x00000776},
-	{0x0000a188, 0x00000776},
-	{0x0000a18c, 0x00000776},
-	{0x0000a190, 0x00000776},
-	{0x0000a194, 0x00000776},
-	{0x0000a198, 0x00000776},
-	{0x0000a19c, 0x00000776},
-	{0x0000a1a0, 0x00000776},
-	{0x0000a1a4, 0x00000776},
-	{0x0000a1a8, 0x00000776},
-	{0x0000a1ac, 0x00000776},
-	{0x0000a1b0, 0x00000776},
-	{0x0000a1b4, 0x00000776},
-	{0x0000a1b8, 0x00000776},
-	{0x0000a1bc, 0x00000776},
-	{0x0000a1c0, 0x00000776},
-	{0x0000a1c4, 0x00000776},
-	{0x0000a1c8, 0x00000776},
-	{0x0000a1cc, 0x00000776},
-	{0x0000a1d0, 0x00000776},
-	{0x0000a1d4, 0x00000776},
-	{0x0000a1d8, 0x00000776},
-	{0x0000a1dc, 0x00000776},
-	{0x0000a1e0, 0x00000776},
-	{0x0000a1e4, 0x00000776},
-	{0x0000a1e8, 0x00000776},
-	{0x0000a1ec, 0x00000776},
-	{0x0000a1f0, 0x00000776},
-	{0x0000a1f4, 0x00000776},
-	{0x0000a1f8, 0x00000776},
-	{0x0000a1fc, 0x00000776},
-	{0x0000b000, 0x02000101},
-	{0x0000b004, 0x02000102},
-	{0x0000b008, 0x02000103},
-	{0x0000b00c, 0x02000104},
-	{0x0000b010, 0x02000200},
-	{0x0000b014, 0x02000201},
-	{0x0000b018, 0x02000202},
-	{0x0000b01c, 0x02000203},
-	{0x0000b020, 0x02000204},
-	{0x0000b024, 0x02000205},
-	{0x0000b028, 0x02000208},
-	{0x0000b02c, 0x02000302},
-	{0x0000b030, 0x02000303},
-	{0x0000b034, 0x02000304},
-	{0x0000b038, 0x02000400},
-	{0x0000b03c, 0x02010300},
-	{0x0000b040, 0x02010301},
-	{0x0000b044, 0x02010302},
-	{0x0000b048, 0x02000500},
-	{0x0000b04c, 0x02010400},
-	{0x0000b050, 0x02020300},
-	{0x0000b054, 0x02020301},
-	{0x0000b058, 0x02020302},
-	{0x0000b05c, 0x02020303},
-	{0x0000b060, 0x02020400},
-	{0x0000b064, 0x02030300},
-	{0x0000b068, 0x02030301},
-	{0x0000b06c, 0x02030302},
-	{0x0000b070, 0x02030303},
-	{0x0000b074, 0x02030400},
-	{0x0000b078, 0x02040300},
-	{0x0000b07c, 0x02040301},
-	{0x0000b080, 0x02040302},
-	{0x0000b084, 0x02040303},
-	{0x0000b088, 0x02030500},
-	{0x0000b08c, 0x02040400},
-	{0x0000b090, 0x02050203},
-	{0x0000b094, 0x02050204},
-	{0x0000b098, 0x02050205},
-	{0x0000b09c, 0x02040500},
-	{0x0000b0a0, 0x02050301},
-	{0x0000b0a4, 0x02050302},
-	{0x0000b0a8, 0x02050303},
-	{0x0000b0ac, 0x02050400},
-	{0x0000b0b0, 0x02050401},
-	{0x0000b0b4, 0x02050402},
-	{0x0000b0b8, 0x02050403},
-	{0x0000b0bc, 0x02050500},
-	{0x0000b0c0, 0x02050501},
-	{0x0000b0c4, 0x02050502},
-	{0x0000b0c8, 0x02050503},
-	{0x0000b0cc, 0x02050504},
-	{0x0000b0d0, 0x02050600},
-	{0x0000b0d4, 0x02050601},
-	{0x0000b0d8, 0x02050602},
-	{0x0000b0dc, 0x02050603},
-	{0x0000b0e0, 0x02050604},
-	{0x0000b0e4, 0x02050700},
-	{0x0000b0e8, 0x02050701},
-	{0x0000b0ec, 0x02050702},
-	{0x0000b0f0, 0x02050703},
-	{0x0000b0f4, 0x02050704},
-	{0x0000b0f8, 0x02050705},
-	{0x0000b0fc, 0x02050708},
-	{0x0000b100, 0x02050709},
-	{0x0000b104, 0x0205070a},
-	{0x0000b108, 0x0205070b},
-	{0x0000b10c, 0x0205070c},
-	{0x0000b110, 0x0205070d},
-	{0x0000b114, 0x02050710},
-	{0x0000b118, 0x02050711},
-	{0x0000b11c, 0x02050712},
-	{0x0000b120, 0x02050713},
-	{0x0000b124, 0x02050714},
-	{0x0000b128, 0x02050715},
-	{0x0000b12c, 0x02050730},
-	{0x0000b130, 0x02050731},
-	{0x0000b134, 0x02050732},
-	{0x0000b138, 0x02050733},
-	{0x0000b13c, 0x02050734},
-	{0x0000b140, 0x02050735},
-	{0x0000b144, 0x02050750},
-	{0x0000b148, 0x02050751},
-	{0x0000b14c, 0x02050752},
-	{0x0000b150, 0x02050753},
-	{0x0000b154, 0x02050754},
-	{0x0000b158, 0x02050755},
-	{0x0000b15c, 0x02050770},
-	{0x0000b160, 0x02050771},
-	{0x0000b164, 0x02050772},
-	{0x0000b168, 0x02050773},
-	{0x0000b16c, 0x02050774},
-	{0x0000b170, 0x02050775},
-	{0x0000b174, 0x00000776},
-	{0x0000b178, 0x00000776},
-	{0x0000b17c, 0x00000776},
-	{0x0000b180, 0x00000776},
-	{0x0000b184, 0x00000776},
-	{0x0000b188, 0x00000776},
-	{0x0000b18c, 0x00000776},
-	{0x0000b190, 0x00000776},
-	{0x0000b194, 0x00000776},
-	{0x0000b198, 0x00000776},
-	{0x0000b19c, 0x00000776},
-	{0x0000b1a0, 0x00000776},
-	{0x0000b1a4, 0x00000776},
-	{0x0000b1a8, 0x00000776},
-	{0x0000b1ac, 0x00000776},
-	{0x0000b1b0, 0x00000776},
-	{0x0000b1b4, 0x00000776},
-	{0x0000b1b8, 0x00000776},
-	{0x0000b1bc, 0x00000776},
-	{0x0000b1c0, 0x00000776},
-	{0x0000b1c4, 0x00000776},
-	{0x0000b1c8, 0x00000776},
-	{0x0000b1cc, 0x00000776},
-	{0x0000b1d0, 0x00000776},
-	{0x0000b1d4, 0x00000776},
-	{0x0000b1d8, 0x00000776},
-	{0x0000b1dc, 0x00000776},
-	{0x0000b1e0, 0x00000776},
-	{0x0000b1e4, 0x00000776},
-	{0x0000b1e8, 0x00000776},
-	{0x0000b1ec, 0x00000776},
-	{0x0000b1f0, 0x00000776},
-	{0x0000b1f4, 0x00000776},
-	{0x0000b1f8, 0x00000776},
-	{0x0000b1fc, 0x00000776},
-};
-
-static const u32 ar9200_ar9280_2p0_radio_core[][2] = {
-	/* Addr      allmodes  */
-	{0x00007800, 0x00040000},
-	{0x00007804, 0xdb005012},
-	{0x00007808, 0x04924914},
-	{0x0000780c, 0x21084210},
-	{0x00007810, 0x6d801300},
-	{0x00007814, 0x0019beff},
-	{0x00007818, 0x07e41000},
-	{0x0000781c, 0x00392000},
-	{0x00007820, 0x92592480},
-	{0x00007824, 0x00040000},
-	{0x00007828, 0xdb005012},
-	{0x0000782c, 0x04924914},
-	{0x00007830, 0x21084210},
-	{0x00007834, 0x6d801300},
-	{0x00007838, 0x0019beff},
-	{0x0000783c, 0x07e40000},
-	{0x00007840, 0x00392000},
-	{0x00007844, 0x92592480},
-	{0x00007848, 0x00100000},
-	{0x0000784c, 0x773f0567},
-	{0x00007850, 0x54214514},
-	{0x00007854, 0x12035828},
-	{0x00007858, 0x92592692},
-	{0x0000785c, 0x00000000},
-	{0x00007860, 0x56400000},
-	{0x00007864, 0x0a8e370e},
-	{0x00007868, 0xc0102850},
-	{0x0000786c, 0x812d4000},
-	{0x00007870, 0x807ec400},
-	{0x00007874, 0x001b6db0},
-	{0x00007878, 0x00376b63},
-	{0x0000787c, 0x06db6db6},
-	{0x00007880, 0x006d8000},
-	{0x00007884, 0xffeffffe},
-	{0x00007888, 0xffeffffe},
-	{0x0000788c, 0x00010000},
-	{0x00007890, 0x02060aeb},
-	{0x00007894, 0x5a108000},
-};
-
-static const u32 ar9462_2p0_mac_postamble_emulation[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8},
-	{0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017},
-};
-
-static const u32 ar9462_2p0_radio_postamble_sys3ant[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
-	{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-	{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-};
-
-static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221},
-	{0x00009e44, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000},
-	{0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
-	{0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
-	{0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111},
-	{0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20},
-	{0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c},
-	{0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a},
-	{0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c},
-	{0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc},
-	{0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4},
-	{0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc},
-	{0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede},
-	{0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e},
-	{0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e},
-	{0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e},
-	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-};
-
 static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
@@ -1356,24 +1005,6 @@
 	{0x00016548, 0x000080c0},
 };
 
-static const u32 ar9462_2p0_tx_gain_table_baseband_postamble_emulation[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5},
-	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002},
-	{0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004},
-	{0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c},
-	{0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b},
-	{0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a},
-	{0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a},
-	{0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a},
-	{0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a},
-	{0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a},
-	{0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a},
-	{0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a},
-	{0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a},
-};
-
 static const u32 ar9462_2p0_soc_preamble[][2] = {
 	/* Addr      allmodes  */
 	{0x00007020, 0x00000000},
@@ -1381,11 +1012,6 @@
 	{0x00007038, 0x000004c2},
 };
 
-static const u32 ar9462_2p0_sys2ant[][2] = {
-	/* Addr      allmodes  */
-	{0x00063120, 0x00801980},
-};
-
 static const u32 ar9462_2p0_mac_core[][2] = {
 	/* Addr      allmodes  */
 	{0x00000008, 0x00000000},
@@ -1822,75 +1448,6 @@
 	{0x0000b1fc, 0x00000196},
 };
 
-static const u32 ar9462_modes_green_ob_db_tx_gain_table_2p0[][5] = {
-	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
-	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-	{0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
-	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-	{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-	{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-	{0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-	{0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-	{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-	{0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-	{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-	{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-	{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-	{0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-	{0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-	{0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-	{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-	{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
-	{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-	{0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-	{0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
-	{0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
-	{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
-	{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
-	{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
-	{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-	{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
-	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
-	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
-	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
-	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
-	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
-	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
-	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-	{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-	{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-	{0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060},
-	{0x00016054, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180},
-	{0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-	{0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000},
-	{0x00016454, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180},
-};
-
 static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = {
 	/* Addr      allmodes  */
 	{0x000018c0, 0x10101010},
@@ -1903,26 +1460,4 @@
 	{0x000018dc, 0x10101010},
 };
 
-static const u32 ar9462_2p0_baseband_core_emulation[][2] = {
-	/* Addr      allmodes  */
-	{0x00009800, 0xafa68e30},
-	{0x00009884, 0x00002842},
-	{0x00009c04, 0xff55ff55},
-	{0x00009c08, 0x0320ff55},
-	{0x00009e50, 0x00000000},
-	{0x00009fcc, 0x00000014},
-	{0x0000a344, 0x00000010},
-	{0x0000a398, 0x00000000},
-	{0x0000a39c, 0x71733d01},
-	{0x0000a3a0, 0xd0ad5c12},
-	{0x0000a3c0, 0x22222220},
-	{0x0000a3c4, 0x22222222},
-	{0x0000a404, 0x00418a11},
-	{0x0000a418, 0x050001ce},
-	{0x0000a438, 0x00001800},
-	{0x0000a458, 0x01444452},
-	{0x0000a644, 0x3fad9d74},
-	{0x0000a690, 0x00000038},
-};
-
 #endif /* INITVALS_9462_2P0_H */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 171ccf7..c2ccba6 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -454,9 +454,39 @@
 	struct ath_mci_profile mci;
 };
 
-int ath_init_btcoex_timer(struct ath_softc *sc);
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+int ath9k_init_btcoex(struct ath_softc *sc);
+void ath9k_deinit_btcoex(struct ath_softc *sc);
+void ath9k_start_btcoex(struct ath_softc *sc);
+void ath9k_stop_btcoex(struct ath_softc *sc);
 void ath9k_btcoex_timer_resume(struct ath_softc *sc);
 void ath9k_btcoex_timer_pause(struct ath_softc *sc);
+void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status);
+u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen);
+#else
+static inline int ath9k_init_btcoex(struct ath_softc *sc)
+{
+	return 0;
+}
+static inline void ath9k_deinit_btcoex(struct ath_softc *sc)
+{
+}
+static inline void ath9k_start_btcoex(struct ath_softc *sc)
+{
+}
+static inline void ath9k_stop_btcoex(struct ath_softc *sc)
+{
+}
+static inline void ath9k_btcoex_handle_interrupt(struct ath_softc *sc,
+						 u32 status)
+{
+}
+static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc,
+					  u32 max_4ms_framelen)
+{
+	return 0;
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 /********************/
 /*   LED Control    */
@@ -650,8 +680,11 @@
 	struct ath_beacon_config cur_beacon_conf;
 	struct delayed_work tx_complete_work;
 	struct delayed_work hw_pll_work;
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	struct ath_btcoex btcoex;
 	struct ath_mci_coex mci_coex;
+#endif
 
 	struct ath_descdma txsdma;
 
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index a6712a9..ec32719 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -68,9 +68,6 @@
 	u32 i, idx;
 	bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	if (AR_SREV_9300_20_OR_LATER(ah))
 		rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
 
@@ -98,13 +95,44 @@
 }
 EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
 
+void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+
+	/*
+	 * Check if BTCOEX is globally disabled.
+	 */
+	if (!common->btcoex_enabled) {
+		btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
+		return;
+	}
+
+	if (AR_SREV_9462(ah)) {
+		btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
+	} else if (AR_SREV_9300_20_OR_LATER(ah)) {
+		btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
+		btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
+		btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
+		btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300;
+	} else if (AR_SREV_9280_20_OR_LATER(ah)) {
+		btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280;
+		btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280;
+
+		if (AR_SREV_9285(ah)) {
+			btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
+			btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9285;
+		} else {
+			btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
+		}
+	}
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme);
+
 void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
 {
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	/* connect bt_active to baseband */
 	REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 		    (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
@@ -127,9 +155,6 @@
 {
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	/* btcoex 3-wire */
 	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 			(AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
@@ -152,13 +177,34 @@
 }
 EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire);
 
+void ath9k_hw_btcoex_init_mci(struct ath_hw *ah)
+{
+	ah->btcoex_hw.mci.ready = false;
+	ah->btcoex_hw.mci.bt_state = 0;
+	ah->btcoex_hw.mci.bt_ver_major = 3;
+	ah->btcoex_hw.mci.bt_ver_minor = 0;
+	ah->btcoex_hw.mci.bt_version_known = false;
+	ah->btcoex_hw.mci.update_2g5g = true;
+	ah->btcoex_hw.mci.is_2g = true;
+	ah->btcoex_hw.mci.wlan_channels_update = false;
+	ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
+	ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
+	ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
+	ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
+	ah->btcoex_hw.mci.query_bt = true;
+	ah->btcoex_hw.mci.unhalt_bt_gpm = true;
+	ah->btcoex_hw.mci.halted_bt_gpm = false;
+	ah->btcoex_hw.mci.need_flush_btinfo = false;
+	ah->btcoex_hw.mci.wlan_cal_seq = 0;
+	ah->btcoex_hw.mci.wlan_cal_done = 0;
+	ah->btcoex_hw.mci.config = 0x2201;
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci);
+
 static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
 {
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	/* Configure the desired GPIO port for TX_FRAME output */
 	ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
 			    AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
@@ -170,9 +216,6 @@
 {
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
 				     SM(wlan_weight, AR_BTCOEX_WL_WGHT);
 }
@@ -261,9 +304,6 @@
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 	int i;
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	btcoex_hw->enabled = false;
 	if (btcoex_hw->scheme == ATH_BTCOEX_CFG_MCI) {
 		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
@@ -312,9 +352,6 @@
 void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
 			      enum ath_stomp_type stomp_type)
 {
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
 		ar9003_btcoex_bt_stomp(ah, stomp_type);
 		return;
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 278361c..8f93aef 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -67,7 +67,6 @@
 	u32 wlan_cal_done;
 	u32 config;
 	u8 *gpm_buf;
-	u8 *sched_buf;
 	bool ready;
 	bool update_2g5g;
 	bool is_2g;
@@ -98,13 +97,14 @@
 	u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS];
 };
 
+void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah);
 void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah);
 void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah);
+void ath9k_hw_btcoex_init_mci(struct ath_hw *ah);
 void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum);
 void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
 				u32 bt_weight,
 				u32 wlan_weight);
-void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 void ath9k_hw_btcoex_disable(struct ath_hw *ah);
 void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
 			      enum ath_stomp_type stomp_type);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 68d972b..228c181 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -451,109 +451,6 @@
 	.llseek = default_llseek,
 };
 
-static const char *channel_type_str(enum nl80211_channel_type t)
-{
-	switch (t) {
-	case NL80211_CHAN_NO_HT:
-		return "no ht";
-	case NL80211_CHAN_HT20:
-		return "ht20";
-	case NL80211_CHAN_HT40MINUS:
-		return "ht40-";
-	case NL80211_CHAN_HT40PLUS:
-		return "ht40+";
-	default:
-		return "???";
-	}
-}
-
-static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
-			       size_t count, loff_t *ppos)
-{
-	struct ath_softc *sc = file->private_data;
-	struct ieee80211_channel *chan = sc->hw->conf.channel;
-	struct ieee80211_conf *conf = &(sc->hw->conf);
-	char buf[512];
-	unsigned int len = 0;
-	u8 addr[ETH_ALEN];
-	u32 tmp;
-
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%s (chan=%d  center-freq: %d MHz  channel-type: %d (%s))\n",
-			wiphy_name(sc->hw->wiphy),
-			ieee80211_frequency_to_channel(chan->center_freq),
-			chan->center_freq,
-			conf->channel_type,
-			channel_type_str(conf->channel_type));
-
-	ath9k_ps_wakeup(sc);
-	put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
-	put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"addr: %pM\n", addr);
-	put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
-	put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"addrmask: %pM\n", addr);
-	tmp = ath9k_hw_getrxfilter(sc->sc_ah);
-	ath9k_ps_restore(sc);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"rfilt: 0x%x", tmp);
-	if (tmp & ATH9K_RX_FILTER_UCAST)
-		len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
-	if (tmp & ATH9K_RX_FILTER_MCAST)
-		len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
-	if (tmp & ATH9K_RX_FILTER_BCAST)
-		len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
-	if (tmp & ATH9K_RX_FILTER_CONTROL)
-		len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
-	if (tmp & ATH9K_RX_FILTER_BEACON)
-		len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
-	if (tmp & ATH9K_RX_FILTER_PROM)
-		len += snprintf(buf + len, sizeof(buf) - len, " PROM");
-	if (tmp & ATH9K_RX_FILTER_PROBEREQ)
-		len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
-	if (tmp & ATH9K_RX_FILTER_PHYERR)
-		len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
-	if (tmp & ATH9K_RX_FILTER_MYBEACON)
-		len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
-	if (tmp & ATH9K_RX_FILTER_COMP_BAR)
-		len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
-	if (tmp & ATH9K_RX_FILTER_PSPOLL)
-		len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
-	if (tmp & ATH9K_RX_FILTER_PHYRADAR)
-		len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
-	if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
-		len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL");
-
-	len += snprintf(buf + len, sizeof(buf) - len,
-		       "\n\nReset causes:\n"
-		       "  baseband hang: %d\n"
-		       "  baseband watchdog: %d\n"
-		       "  fatal hardware error interrupt: %d\n"
-		       "  tx hardware error: %d\n"
-		       "  tx path hang: %d\n"
-		       "  pll rx hang: %d\n",
-		       sc->debug.stats.reset[RESET_TYPE_BB_HANG],
-		       sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG],
-		       sc->debug.stats.reset[RESET_TYPE_FATAL_INT],
-		       sc->debug.stats.reset[RESET_TYPE_TX_ERROR],
-		       sc->debug.stats.reset[RESET_TYPE_TX_HANG],
-		       sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
-
-	if (len > sizeof(buf))
-		len = sizeof(buf);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_wiphy = {
-	.read = read_file_wiphy,
-	.open = ath9k_debugfs_open,
-	.owner = THIS_MODULE,
-	.llseek = default_llseek,
-};
-
 #define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
 #define PR(str, elem)							\
 	do {								\
@@ -763,87 +660,128 @@
 {
 	struct ath_softc *sc = file->private_data;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ath_hw *ah = sc->sc_ah;
 	struct ieee80211_hw *hw = sc->hw;
-	char *buf;
-	unsigned int len = 0, size = 8000;
+	struct ath9k_vif_iter_data iter_data;
+	char buf[512];
+	unsigned int len = 0;
 	ssize_t retval = 0;
 	unsigned int reg;
-	struct ath9k_vif_iter_data iter_data;
+	u32 rxfilter;
 
-	ath9k_calculate_iter_data(hw, NULL, &iter_data);
-	
-	buf = kzalloc(size, GFP_KERNEL);
-	if (buf == NULL)
-		return -ENOMEM;
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"BSSID: %pM\n", common->curbssid);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"BSSID-MASK: %pM\n", common->bssidmask);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"OPMODE: %s\n", ath_opmode_to_string(sc->sc_ah->opmode));
 
 	ath9k_ps_wakeup(sc);
-	len += snprintf(buf + len, size - len,
-			"curbssid: %pM\n"
-			"OP-Mode: %s(%i)\n"
-			"Beacon-Timer-Register: 0x%x\n",
-			common->curbssid,
-			ath_opmode_to_string(sc->sc_ah->opmode),
-			(int)(sc->sc_ah->opmode),
-			REG_READ(ah, AR_BEACON_PERIOD));
-
-	reg = REG_READ(ah, AR_TIMER_MODE);
+	rxfilter = ath9k_hw_getrxfilter(sc->sc_ah);
 	ath9k_ps_restore(sc);
-	len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (",
-			reg);
-	if (reg & AR_TBTT_TIMER_EN)
-		len += snprintf(buf + len, size - len, "TBTT ");
-	if (reg & AR_DBA_TIMER_EN)
-		len += snprintf(buf + len, size - len, "DBA ");
-	if (reg & AR_SWBA_TIMER_EN)
-		len += snprintf(buf + len, size - len, "SWBA ");
-	if (reg & AR_HCF_TIMER_EN)
-		len += snprintf(buf + len, size - len, "HCF ");
-	if (reg & AR_TIM_TIMER_EN)
-		len += snprintf(buf + len, size - len, "TIM ");
-	if (reg & AR_DTIM_TIMER_EN)
-		len += snprintf(buf + len, size - len, "DTIM ");
-	len += snprintf(buf + len, size - len, ")\n");
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"RXFILTER: 0x%x", rxfilter);
+
+	if (rxfilter & ATH9K_RX_FILTER_UCAST)
+		len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
+	if (rxfilter & ATH9K_RX_FILTER_MCAST)
+		len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
+	if (rxfilter & ATH9K_RX_FILTER_BCAST)
+		len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
+	if (rxfilter & ATH9K_RX_FILTER_CONTROL)
+		len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
+	if (rxfilter & ATH9K_RX_FILTER_BEACON)
+		len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
+	if (rxfilter & ATH9K_RX_FILTER_PROM)
+		len += snprintf(buf + len, sizeof(buf) - len, " PROM");
+	if (rxfilter & ATH9K_RX_FILTER_PROBEREQ)
+		len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
+	if (rxfilter & ATH9K_RX_FILTER_PHYERR)
+		len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
+	if (rxfilter & ATH9K_RX_FILTER_MYBEACON)
+		len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
+	if (rxfilter & ATH9K_RX_FILTER_COMP_BAR)
+		len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
+	if (rxfilter & ATH9K_RX_FILTER_PSPOLL)
+		len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
+	if (rxfilter & ATH9K_RX_FILTER_PHYRADAR)
+		len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
+	if (rxfilter & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
+		len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL");
+	if (rxfilter & ATH9K_RX_FILTER_CONTROL_WRAPPER)
+		len += snprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER");
+
+	len += snprintf(buf + len, sizeof(buf) - len, "\n");
 
 	reg = sc->sc_ah->imask;
-	len += snprintf(buf + len, size - len, "imask: 0x%x (", reg);
-	if (reg & ATH9K_INT_SWBA)
-		len += snprintf(buf + len, size - len, "SWBA ");
-	if (reg & ATH9K_INT_BMISS)
-		len += snprintf(buf + len, size - len, "BMISS ");
-	if (reg & ATH9K_INT_CST)
-		len += snprintf(buf + len, size - len, "CST ");
-	if (reg & ATH9K_INT_RX)
-		len += snprintf(buf + len, size - len, "RX ");
-	if (reg & ATH9K_INT_RXHP)
-		len += snprintf(buf + len, size - len, "RXHP ");
-	if (reg & ATH9K_INT_RXLP)
-		len += snprintf(buf + len, size - len, "RXLP ");
-	if (reg & ATH9K_INT_BB_WATCHDOG)
-		len += snprintf(buf + len, size - len, "BB_WATCHDOG ");
-	/* there are other IRQs if one wanted to add them. */
-	len += snprintf(buf + len, size - len, ")\n");
 
-	len += snprintf(buf + len, size - len,
-			"VIF Counts: AP: %i STA: %i MESH: %i WDS: %i"
-			" ADHOC: %i OTHER: %i nvifs: %hi beacon-vifs: %hi\n",
+	len += snprintf(buf + len, sizeof(buf) - len, "INTERRUPT-MASK: 0x%x", reg);
+
+	if (reg & ATH9K_INT_SWBA)
+		len += snprintf(buf + len, sizeof(buf) - len, " SWBA");
+	if (reg & ATH9K_INT_BMISS)
+		len += snprintf(buf + len, sizeof(buf) - len, " BMISS");
+	if (reg & ATH9K_INT_CST)
+		len += snprintf(buf + len, sizeof(buf) - len, " CST");
+	if (reg & ATH9K_INT_RX)
+		len += snprintf(buf + len, sizeof(buf) - len, " RX");
+	if (reg & ATH9K_INT_RXHP)
+		len += snprintf(buf + len, sizeof(buf) - len, " RXHP");
+	if (reg & ATH9K_INT_RXLP)
+		len += snprintf(buf + len, sizeof(buf) - len, " RXLP");
+	if (reg & ATH9K_INT_BB_WATCHDOG)
+		len += snprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG");
+
+	len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+	ath9k_calculate_iter_data(hw, NULL, &iter_data);
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i"
+			" ADHOC: %i OTHER: %i TOTAL: %hi BEACON-VIF: %hi\n",
 			iter_data.naps, iter_data.nstations, iter_data.nmeshes,
 			iter_data.nwds, iter_data.nadhocs, iter_data.nothers,
 			sc->nvifs, sc->nbcnvifs);
 
-	len += snprintf(buf + len, size - len,
-			"Calculated-BSSID-Mask: %pM\n",
-			iter_data.mask);
-
-	if (len > size)
-		len = size;
+	if (len > sizeof(buf))
+		len = sizeof(buf);
 
 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-	kfree(buf);
-
 	return retval;
 }
 
+static ssize_t read_file_reset(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[512];
+	unsigned int len = 0;
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%17s: %2d\n", "Baseband Hang",
+			sc->debug.stats.reset[RESET_TYPE_BB_HANG]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%17s: %2d\n", "Baseband Watchdog",
+			sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%17s: %2d\n", "Fatal HW Error",
+			sc->debug.stats.reset[RESET_TYPE_FATAL_INT]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%17s: %2d\n", "TX HW error",
+			sc->debug.stats.reset[RESET_TYPE_TX_ERROR]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%17s: %2d\n", "TX Path Hang",
+			sc->debug.stats.reset[RESET_TYPE_TX_HANG]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%17s: %2d\n", "PLL RX Hang",
+			sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
 		       struct ath_tx_status *ts, struct ath_txq *txq,
 		       unsigned int flags)
@@ -931,16 +869,23 @@
 	.llseek = default_llseek,
 };
 
+static const struct file_operations fops_reset = {
+	.read = read_file_reset,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static ssize_t read_file_recv(struct file *file, char __user *user_buf,
 			      size_t count, loff_t *ppos)
 {
 #define PHY_ERR(s, p) \
-	len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \
+	len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \
 			sc->debug.stats.rxstats.phy_err_stats[p]);
 
 	struct ath_softc *sc = file->private_data;
 	char *buf;
-	unsigned int len = 0, size = 1400;
+	unsigned int len = 0, size = 1600;
 	ssize_t retval = 0;
 
 	buf = kzalloc(size, GFP_KERNEL);
@@ -948,87 +893,80 @@
 		return -ENOMEM;
 
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "CRC ERR",
+			"%22s : %10u\n", "CRC ERR",
 			sc->debug.stats.rxstats.crc_err);
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "DECRYPT CRC ERR",
+			"%22s : %10u\n", "DECRYPT CRC ERR",
 			sc->debug.stats.rxstats.decrypt_crc_err);
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "PHY ERR",
+			"%22s : %10u\n", "PHY ERR",
 			sc->debug.stats.rxstats.phy_err);
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "MIC ERR",
+			"%22s : %10u\n", "MIC ERR",
 			sc->debug.stats.rxstats.mic_err);
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "PRE-DELIM CRC ERR",
+			"%22s : %10u\n", "PRE-DELIM CRC ERR",
 			sc->debug.stats.rxstats.pre_delim_crc_err);
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "POST-DELIM CRC ERR",
+			"%22s : %10u\n", "POST-DELIM CRC ERR",
 			sc->debug.stats.rxstats.post_delim_crc_err);
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "DECRYPT BUSY ERR",
+			"%22s : %10u\n", "DECRYPT BUSY ERR",
 			sc->debug.stats.rxstats.decrypt_busy_err);
 
+	PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
+	PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING);
+	PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY);
+	PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE);
+	PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH);
+	PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR);
+	PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE);
+	PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR);
+	PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING);
+	PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
+	PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
+	PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
+	PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP);
+	PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE);
+	PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART);
+	PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT);
+	PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING);
+	PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC);
+	PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
+	PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE);
+	PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART);
+	PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
+	PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP);
+	PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR);
+	PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
+	PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+
 	len += snprintf(buf + len, size - len,
-			"%18s : %10d\n", "RSSI-CTL0",
+			"%22s : %10d\n", "RSSI-CTL0",
 			sc->debug.stats.rxstats.rs_rssi_ctl0);
-
 	len += snprintf(buf + len, size - len,
-			"%18s : %10d\n", "RSSI-CTL1",
+			"%22s : %10d\n", "RSSI-CTL1",
 			sc->debug.stats.rxstats.rs_rssi_ctl1);
-
 	len += snprintf(buf + len, size - len,
-			"%18s : %10d\n", "RSSI-CTL2",
+			"%22s : %10d\n", "RSSI-CTL2",
 			sc->debug.stats.rxstats.rs_rssi_ctl2);
-
 	len += snprintf(buf + len, size - len,
-			"%18s : %10d\n", "RSSI-EXT0",
+			"%22s : %10d\n", "RSSI-EXT0",
 			sc->debug.stats.rxstats.rs_rssi_ext0);
-
 	len += snprintf(buf + len, size - len,
-			"%18s : %10d\n", "RSSI-EXT1",
+			"%22s : %10d\n", "RSSI-EXT1",
 			sc->debug.stats.rxstats.rs_rssi_ext1);
-
 	len += snprintf(buf + len, size - len,
-			"%18s : %10d\n", "RSSI-EXT2",
+			"%22s : %10d\n", "RSSI-EXT2",
 			sc->debug.stats.rxstats.rs_rssi_ext2);
-
 	len += snprintf(buf + len, size - len,
-			"%18s : %10d\n", "Rx Antenna",
+			"%22s : %10d\n", "Rx Antenna",
 			sc->debug.stats.rxstats.rs_antenna);
-
-	PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
-	PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
-	PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
-	PHY_ERR("RATE", ATH9K_PHYERR_RATE);
-	PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
-	PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
-	PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
-	PHY_ERR("TOR", ATH9K_PHYERR_TOR);
-	PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
-	PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
-	PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
-	PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
-	PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
-	PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
-	PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
-	PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
-	PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
-	PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
-	PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
-	PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
-	PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
-	PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
-	PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
-	PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
-	PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
-	PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
-
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "RX-Pkts-All",
+			"%22s : %10u\n", "RX-Pkts-All",
 			sc->debug.stats.rxstats.rx_pkts_all);
 	len += snprintf(buf + len, size - len,
-			"%18s : %10u\n", "RX-Bytes-All",
+			"%22s : %10u\n", "RX-Bytes-All",
 			sc->debug.stats.rxstats.rx_bytes_all);
 
 	if (len > size)
@@ -1049,8 +987,6 @@
 #define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\
 			[sc->debug.rsidx].c)
 
-	u32 phyerr;
-
 	RX_STAT_INC(rx_pkts_all);
 	sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen;
 
@@ -1069,8 +1005,8 @@
 
 	if (rs->rs_status & ATH9K_RXERR_PHY) {
 		RX_STAT_INC(phy_err);
-		phyerr = rs->rs_phyerr & 0x24;
-		RX_PHY_ERR_INC(phyerr);
+		if (rs->rs_phyerr < ATH9K_PHYERR_MAX)
+			RX_PHY_ERR_INC(rs->rs_phyerr);
 	}
 
 	sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0;
@@ -1637,14 +1573,14 @@
 			    &fops_dma);
 	debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_interrupt);
-	debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-			    sc, &fops_wiphy);
 	debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_xmit);
 	debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_stations);
 	debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_misc);
+	debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_reset);
 	debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_recv);
 	debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
@@ -1677,10 +1613,5 @@
 	debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
 			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
 
-	sc->debug.regidx = 0;
-	memset(&sc->debug.bb_mac_samp, 0, sizeof(sc->debug.bb_mac_samp));
-	sc->debug.sampidx = 0;
-	sc->debug.tsidx = 0;
-	sc->debug.rsidx = 0;
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 597c84e..63e4c4b1 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -110,6 +110,8 @@
 		wiphy_rfkill_start_polling(sc->hw->wiphy);
 }
 
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+
 /******************/
 /*     BTCOEX     */
 /******************/
@@ -245,13 +247,10 @@
 	ath9k_ps_restore(sc);
 }
 
-int ath_init_btcoex_timer(struct ath_softc *sc)
+static int ath_init_btcoex_timer(struct ath_softc *sc)
 {
 	struct ath_btcoex *btcoex = &sc->btcoex;
 
-	if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_NONE)
-		return 0;
-
 	btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
 	btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
 		btcoex->btcoex_period / 100;
@@ -284,9 +283,6 @@
 
 	ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n");
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	/* make sure duty cycle timer is also stopped when resuming */
 	if (btcoex->hw_timer_enabled)
 		ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
@@ -307,9 +303,6 @@
 	struct ath_btcoex *btcoex = &sc->btcoex;
 	struct ath_hw *ah = sc->sc_ah;
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	del_timer_sync(&btcoex->period_timer);
 
 	if (btcoex->hw_timer_enabled)
@@ -317,3 +310,113 @@
 
 	btcoex->hw_timer_enabled = false;
 }
+
+u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
+{
+	struct ath_mci_profile *mci = &sc->btcoex.mci;
+	u16 aggr_limit = 0;
+
+	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
+		aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
+	else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+		aggr_limit = min((max_4ms_framelen * 3) / 8,
+				 (u32)ATH_AMPDU_LIMIT_MAX);
+
+	return aggr_limit;
+}
+
+void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status)
+{
+	struct ath_hw *ah = sc->sc_ah;
+
+	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
+		if (status & ATH9K_INT_GENTIMER)
+			ath_gen_timer_isr(sc->sc_ah);
+
+	if (status & ATH9K_INT_MCI)
+		ath_mci_intr(sc);
+}
+
+void ath9k_start_btcoex(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+
+	if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) &&
+	    !ah->btcoex_hw.enabled) {
+		if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
+			ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+						   AR_STOMP_LOW_WLAN_WGHT);
+		ath9k_hw_btcoex_enable(ah);
+
+		if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
+			ath9k_btcoex_timer_resume(sc);
+	}
+}
+
+void ath9k_stop_btcoex(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+
+	if (ah->btcoex_hw.enabled &&
+	    ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
+		ath9k_hw_btcoex_disable(ah);
+		if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
+			ath9k_btcoex_timer_pause(sc);
+		ath_mci_flush_profile(&sc->btcoex.mci);
+	}
+}
+
+void ath9k_deinit_btcoex(struct ath_softc *sc)
+{
+        if ((sc->btcoex.no_stomp_timer) &&
+	    ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE)
+		ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
+
+	if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI)
+		ath_mci_cleanup(sc);
+}
+
+int ath9k_init_btcoex(struct ath_softc *sc)
+{
+	struct ath_txq *txq;
+	struct ath_hw *ah = sc->sc_ah;
+	int r;
+
+	ath9k_hw_btcoex_init_scheme(ah);
+
+	switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) {
+	case ATH_BTCOEX_CFG_NONE:
+		break;
+	case ATH_BTCOEX_CFG_2WIRE:
+		ath9k_hw_btcoex_init_2wire(sc->sc_ah);
+		break;
+	case ATH_BTCOEX_CFG_3WIRE:
+		ath9k_hw_btcoex_init_3wire(sc->sc_ah);
+		r = ath_init_btcoex_timer(sc);
+		if (r)
+			return -1;
+		txq = sc->tx.txq_map[WME_AC_BE];
+		ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
+		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+		break;
+	case ATH_BTCOEX_CFG_MCI:
+		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+		sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+		INIT_LIST_HEAD(&sc->btcoex.mci.info);
+
+		r = ath_mci_setup(sc);
+		if (r)
+			return r;
+
+		ath9k_hw_btcoex_init_mci(ah);
+
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index da55967..1357952 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -400,9 +400,21 @@
 	u32 btscan_no_stomp;
 };
 
-void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv);
-void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv);
-void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product);
+void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv);
+void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv);
+#else
+static inline void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product)
+{
+}
+static inline void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv)
+{
+}
+static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)
+{
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #define OP_INVALID		   BIT(0)
 #define OP_SCANNING		   BIT(1)
@@ -483,7 +495,10 @@
 	int cabq;
 	int hwq_map[WME_NUM_AC];
 
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	struct ath_btcoex btcoex;
+#endif
+
 	struct delayed_work coex_period_work;
 	struct delayed_work duty_cycle_work;
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 6506e1f..1c10e2e 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -20,6 +20,10 @@
 /*     BTCOEX     */
 /******************/
 
+#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+
 /*
  * Detects if there is any priority bt traffic
  */
@@ -111,13 +115,10 @@
 	ath9k_hw_btcoex_enable(priv->ah);
 }
 
-void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
+static void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
 {
 	struct ath_btcoex *btcoex = &priv->btcoex;
 
-	if (ath9k_hw_get_btcoex_scheme(priv->ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
 	btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
 		btcoex->btcoex_period / 100;
@@ -131,14 +132,11 @@
  * (Re)start btcoex work
  */
 
-void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
+static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
 {
 	struct ath_btcoex *btcoex = &priv->btcoex;
 	struct ath_hw *ah = priv->ah;
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex work\n");
 
 	btcoex->bt_priority_cnt = 0;
@@ -151,15 +149,66 @@
 /*
  * Cancel btcoex and bt duty cycle work.
  */
-void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
+static void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
 {
-	if (ath9k_hw_get_btcoex_scheme(priv->ah) == ATH_BTCOEX_CFG_NONE)
-		return;
-
 	cancel_delayed_work_sync(&priv->coex_period_work);
 	cancel_delayed_work_sync(&priv->duty_cycle_work);
 }
 
+void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv)
+{
+	struct ath_hw *ah = priv->ah;
+
+	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) {
+		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+					   AR_STOMP_LOW_WLAN_WGHT);
+		ath9k_hw_btcoex_enable(ah);
+		ath_htc_resume_btcoex_work(priv);
+	}
+}
+
+void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)
+{
+	struct ath_hw *ah = priv->ah;
+
+	if (ah->btcoex_hw.enabled &&
+	    ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
+		ath9k_hw_btcoex_disable(ah);
+		if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+			ath_htc_cancel_btcoex_work(priv);
+	}
+}
+
+void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product)
+{
+	struct ath_hw *ah = priv->ah;
+	int qnum;
+
+	if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
+		ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
+	}
+
+	switch (ath9k_hw_get_btcoex_scheme(priv->ah)) {
+	case ATH_BTCOEX_CFG_NONE:
+		break;
+	case ATH_BTCOEX_CFG_3WIRE:
+		priv->ah->btcoex_hw.btactive_gpio = 7;
+		priv->ah->btcoex_hw.btpriority_gpio = 6;
+		priv->ah->btcoex_hw.wlanactive_gpio = 8;
+		priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+		ath9k_hw_btcoex_init_3wire(priv->ah);
+		ath_htc_init_btcoex_work(priv);
+		qnum = priv->hwq_map[WME_AC_BE];
+		ath9k_hw_init_btcoex_hw(priv->ah, qnum);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+}
+
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
+
 /*******/
 /* LED */
 /*******/
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index fc7519c..de5ee15 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -41,8 +41,6 @@
 	.max_power = 20, \
 }
 
-#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
-
 static struct ieee80211_channel ath9k_2ghz_channels[] = {
 	CHAN2G(2412, 0), /* Channel 1 */
 	CHAN2G(2417, 1), /* Channel 2 */
@@ -603,29 +601,6 @@
 	priv->ah->opmode = NL80211_IFTYPE_STATION;
 }
 
-static void ath9k_init_btcoex(struct ath9k_htc_priv *priv)
-{
-	int qnum;
-
-	switch (ath9k_hw_get_btcoex_scheme(priv->ah)) {
-	case ATH_BTCOEX_CFG_NONE:
-		break;
-	case ATH_BTCOEX_CFG_3WIRE:
-		priv->ah->btcoex_hw.btactive_gpio = 7;
-		priv->ah->btcoex_hw.btpriority_gpio = 6;
-		priv->ah->btcoex_hw.wlanactive_gpio = 8;
-		priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-		ath9k_hw_btcoex_init_3wire(priv->ah);
-		ath_htc_init_btcoex_work(priv);
-		qnum = priv->hwq_map[WME_AC_BE];
-		ath9k_hw_init_btcoex_hw(priv->ah, qnum);
-		break;
-	default:
-		WARN_ON(1);
-		break;
-	}
-}
-
 static int ath9k_init_priv(struct ath9k_htc_priv *priv,
 			   u16 devid, char *product,
 			   u32 drv_info)
@@ -698,12 +673,7 @@
 	ath9k_cmn_init_crypto(ah);
 	ath9k_init_channels_rates(priv);
 	ath9k_init_misc(priv);
-
-	if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
-		ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
-		if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE)
-			ath9k_init_btcoex(priv);
-	}
+	ath9k_htc_init_btcoex(priv, product);
 
 	return 0;
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 06101b6..2a29a7c 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -957,12 +957,8 @@
 	mod_timer(&priv->tx.cleanup_timer,
 		  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) {
-		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-					   AR_STOMP_LOW_WLAN_WGHT);
-		ath9k_hw_btcoex_enable(ah);
-		ath_htc_resume_btcoex_work(priv);
-	}
+	ath9k_htc_start_btcoex(priv);
+
 	mutex_unlock(&priv->mutex);
 
 	return ret;
@@ -1009,12 +1005,7 @@
 
 	mutex_lock(&priv->mutex);
 
-	if (ah->btcoex_hw.enabled &&
-	    ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
-		ath9k_hw_btcoex_disable(ah);
-		if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
-			ath_htc_cancel_btcoex_work(priv);
-	}
+	ath9k_htc_stop_btcoex(priv);
 
 	/* Remove a monitor interface if it's present. */
 	if (priv->ah->is_monitoring)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index d0d13d7..5c57568 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -23,6 +23,7 @@
 #include "hw-ops.h"
 #include "rc.h"
 #include "ar9003_mac.h"
+#include "ar9003_mci.h"
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
 
@@ -1518,61 +1519,22 @@
 		   struct ath9k_hw_cal_data *caldata, bool bChannelChange)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 	u32 saveLedState;
 	struct ath9k_channel *curchan = ah->curchan;
 	u32 saveDefAntenna;
 	u32 macStaId1;
 	u64 tsf = 0;
 	int i, r;
-	bool allow_fbs = false;
+	bool allow_fbs = false, start_mci_reset = false;
 	bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
 	bool save_fullsleep = ah->chip_fullsleep;
 
 	if (mci) {
-
-		ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
-
-		if (mci_hw->bt_state == MCI_BT_CAL_START) {
-			u32 payload[4] = {0, 0, 0, 0};
-
-			ath_dbg(common, MCI, "MCI stop rx for BT CAL\n");
-
-			mci_hw->bt_state = MCI_BT_CAL;
-
-			/*
-			 * MCI FIX: disable mci interrupt here. This is to avoid
-			 * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
-			 * lead to mci_intr reentry.
-			 */
-
-			ar9003_mci_disable_interrupt(ah);
-
-			ath_dbg(common, MCI, "send WLAN_CAL_GRANT\n");
-			MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
-			ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
-						16, true, false);
-
-			ath_dbg(common, MCI, "\nMCI BT is calibrating\n");
-
-			/* Wait BT calibration to be completed for 25ms */
-
-			if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
-								  0, 25000))
-				ath_dbg(common, MCI,
-					"MCI got BT_CAL_DONE\n");
-			else
-				ath_dbg(common, MCI,
-					"MCI ### BT cal takes to long, force bt_state to be bt_awake\n");
-			mci_hw->bt_state = MCI_BT_AWAKE;
-			/* MCI FIX: enable mci interrupt here */
-			ar9003_mci_enable_interrupt(ah);
-
-			return true;
-		}
+		start_mci_reset = ar9003_mci_start_reset(ah, chan);
+		if (start_mci_reset)
+			return 0;
 	}
 
-
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
 		return -EIO;
 
@@ -1609,7 +1571,7 @@
 		if (ath9k_hw_channel_change(ah, chan)) {
 			ath9k_hw_loadnf(ah, ah->curchan);
 			ath9k_hw_start_nfcal(ah, true);
-			if (mci && mci_hw->ready)
+			if (mci && ar9003_mci_is_ready(ah))
 				ar9003_mci_2g5g_switch(ah, true);
 
 			if (AR_SREV_9271(ah))
@@ -1618,19 +1580,8 @@
 		}
 	}
 
-	if (mci) {
-		ar9003_mci_disable_interrupt(ah);
-
-		if (mci_hw->ready && !save_fullsleep) {
-			ar9003_mci_mute_bt(ah);
-			udelay(20);
-			REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
-		}
-
-		mci_hw->bt_state = MCI_BT_SLEEP;
-		mci_hw->ready = false;
-	}
-
+	if (mci)
+		ar9003_mci_stop_bt(ah, save_fullsleep);
 
 	saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
 	if (saveDefAntenna == 0)
@@ -1807,53 +1758,8 @@
 	ath9k_hw_loadnf(ah, chan);
 	ath9k_hw_start_nfcal(ah, true);
 
-	if (mci && mci_hw->ready) {
-
-		if (IS_CHAN_2GHZ(chan) &&
-		    (mci_hw->bt_state == MCI_BT_SLEEP)) {
-
-			if (ar9003_mci_check_int(ah,
-			    AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
-			    ar9003_mci_check_int(ah,
-			    AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
-
-				/*
-				 * BT is sleeping. Check if BT wakes up during
-				 * WLAN calibration. If BT wakes up during
-				 * WLAN calibration, need to go through all
-				 * message exchanges again and recal.
-				 */
-
-				ath_dbg(common, MCI,
-					"MCI BT wakes up during WLAN calibration\n");
-
-				REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-					  AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
-					  AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
-				ath_dbg(common, MCI, "MCI send REMOTE_RESET\n");
-				ar9003_mci_remote_reset(ah, true);
-				ar9003_mci_send_sys_waking(ah, true);
-				udelay(1);
-				if (IS_CHAN_2GHZ(chan))
-					ar9003_mci_send_lna_transfer(ah, true);
-
-				mci_hw->bt_state = MCI_BT_AWAKE;
-
-				ath_dbg(common, MCI, "MCI re-cal\n");
-
-				if (caldata) {
-					caldata->done_txiqcal_once = false;
-					caldata->done_txclcal_once = false;
-					caldata->rtt_hist.num_readings = 0;
-				}
-
-				if (!ath9k_hw_init_cal(ah, chan))
-					return -EIO;
-
-			}
-		}
-		ar9003_mci_enable_interrupt(ah);
-	}
+	if (mci && ar9003_mci_end_reset(ah, chan, caldata))
+		return -EIO;
 
 	ENABLE_REGWRITE_BUFFER(ah);
 
@@ -1894,24 +1800,11 @@
 #endif
 	}
 
-	if (ah->btcoex_hw.enabled &&
-	    ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE)
+	if (ath9k_hw_btcoex_is_enabled(ah))
 		ath9k_hw_btcoex_enable(ah);
 
-	if (mci && mci_hw->ready) {
-		/*
-		 * check BT state again to make
-		 * sure it's not changed.
-		 */
-
-		ar9003_mci_sync_bt_state(ah);
-		ar9003_mci_2g5g_switch(ah, true);
-
-		if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
-				(mci_hw->query_bt == true)) {
-			mci_hw->need_flush_btinfo = true;
-		}
-	}
+	if (mci)
+		ar9003_mci_check_bt(ah);
 
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
 		ar9003_hw_bb_watchdog_config(ah);
@@ -1962,8 +1855,7 @@
 			REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
 
 		/* Shutdown chip. Active low */
-		if (!AR_SREV_5416(ah) &&
-				!AR_SREV_9271(ah) && !AR_SREV_9462_10(ah)) {
+		if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
 			REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
 			udelay(2);
 		}
@@ -2076,7 +1968,6 @@
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	int status = true, setChip = true;
 	static const char *modes[] = {
 		"AWAKE",
@@ -2100,20 +1991,8 @@
 
 		break;
 	case ATH9K_PM_FULL_SLEEP:
-
-		if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
-			if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
-				(mci->bt_state != MCI_BT_SLEEP) &&
-				!mci->halted_bt_gpm) {
-				ath_dbg(common, MCI,
-					"MCI halt BT GPM (full_sleep)\n");
-				ar9003_mci_send_coex_halt_bt_gpm(ah,
-								 true, true);
-			}
-
-			mci->ready = false;
-			REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-		}
+		if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+			ar9003_mci_set_full_sleep(ah);
 
 		ath9k_set_power_sleep(ah, setChip);
 		ah->chip_fullsleep = true;
@@ -2303,7 +2182,6 @@
 	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 	unsigned int chip_chainmask;
 
 	u16 eeval;
@@ -2422,30 +2300,6 @@
 	else
 		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
-	if (common->btcoex_enabled) {
-		if (AR_SREV_9462(ah))
-			btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
-		else if (AR_SREV_9300_20_OR_LATER(ah)) {
-			btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
-			btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
-			btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
-			btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300;
-		} else if (AR_SREV_9280_20_OR_LATER(ah)) {
-			btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280;
-			btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280;
-
-			if (AR_SREV_9285(ah)) {
-				btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
-				btcoex_hw->btpriority_gpio =
-						ATH_BTPRIORITY_GPIO_9285;
-			} else {
-				btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
-			}
-		}
-	} else {
-		btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
-	}
-
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
 		pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK;
 		if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah))
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c8261d4..1707137 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -209,11 +209,7 @@
 	ATH9K_HW_CAP_5GHZ			= BIT(12),
 	ATH9K_HW_CAP_APM			= BIT(13),
 	ATH9K_HW_CAP_RTT			= BIT(14),
-#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	ATH9K_HW_CAP_MCI			= BIT(15),
-#else
-	ATH9K_HW_CAP_MCI			= 0,
-#endif
 	ATH9K_HW_CAP_DFS			= BIT(16),
 };
 
@@ -432,161 +428,6 @@
 	ATH9K_RX_QUEUE_MAX,
 };
 
-enum mci_message_header {		/* length of payload */
-	MCI_LNA_CTRL     = 0x10,        /* len = 0 */
-	MCI_CONT_NACK    = 0x20,        /* len = 0 */
-	MCI_CONT_INFO    = 0x30,        /* len = 4 */
-	MCI_CONT_RST     = 0x40,        /* len = 0 */
-	MCI_SCHD_INFO    = 0x50,        /* len = 16 */
-	MCI_CPU_INT      = 0x60,        /* len = 4 */
-	MCI_SYS_WAKING   = 0x70,        /* len = 0 */
-	MCI_GPM          = 0x80,        /* len = 16 */
-	MCI_LNA_INFO     = 0x90,        /* len = 1 */
-	MCI_LNA_STATE    = 0x94,
-	MCI_LNA_TAKE     = 0x98,
-	MCI_LNA_TRANS    = 0x9c,
-	MCI_SYS_SLEEPING = 0xa0,        /* len = 0 */
-	MCI_REQ_WAKE     = 0xc0,        /* len = 0 */
-	MCI_DEBUG_16     = 0xfe,        /* len = 2 */
-	MCI_REMOTE_RESET = 0xff         /* len = 16 */
-};
-
-enum ath_mci_gpm_coex_profile_type {
-	MCI_GPM_COEX_PROFILE_UNKNOWN,
-	MCI_GPM_COEX_PROFILE_RFCOMM,
-	MCI_GPM_COEX_PROFILE_A2DP,
-	MCI_GPM_COEX_PROFILE_HID,
-	MCI_GPM_COEX_PROFILE_BNEP,
-	MCI_GPM_COEX_PROFILE_VOICE,
-	MCI_GPM_COEX_PROFILE_MAX
-};
-
-/* MCI GPM/Coex opcode/type definitions */
-enum {
-	MCI_GPM_COEX_W_GPM_PAYLOAD      = 1,
-	MCI_GPM_COEX_B_GPM_TYPE         = 4,
-	MCI_GPM_COEX_B_GPM_OPCODE       = 5,
-	/* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */
-	MCI_GPM_WLAN_CAL_W_SEQUENCE     = 2,
-
-	/* MCI_GPM_COEX_VERSION_QUERY */
-	/* MCI_GPM_COEX_VERSION_RESPONSE */
-	MCI_GPM_COEX_B_MAJOR_VERSION    = 6,
-	MCI_GPM_COEX_B_MINOR_VERSION    = 7,
-	/* MCI_GPM_COEX_STATUS_QUERY */
-	MCI_GPM_COEX_B_BT_BITMAP        = 6,
-	MCI_GPM_COEX_B_WLAN_BITMAP      = 7,
-	/* MCI_GPM_COEX_HALT_BT_GPM */
-	MCI_GPM_COEX_B_HALT_STATE       = 6,
-	/* MCI_GPM_COEX_WLAN_CHANNELS */
-	MCI_GPM_COEX_B_CHANNEL_MAP      = 6,
-	/* MCI_GPM_COEX_BT_PROFILE_INFO */
-	MCI_GPM_COEX_B_PROFILE_TYPE     = 6,
-	MCI_GPM_COEX_B_PROFILE_LINKID   = 7,
-	MCI_GPM_COEX_B_PROFILE_STATE    = 8,
-	MCI_GPM_COEX_B_PROFILE_ROLE     = 9,
-	MCI_GPM_COEX_B_PROFILE_RATE     = 10,
-	MCI_GPM_COEX_B_PROFILE_VOTYPE   = 11,
-	MCI_GPM_COEX_H_PROFILE_T        = 12,
-	MCI_GPM_COEX_B_PROFILE_W        = 14,
-	MCI_GPM_COEX_B_PROFILE_A        = 15,
-	/* MCI_GPM_COEX_BT_STATUS_UPDATE */
-	MCI_GPM_COEX_B_STATUS_TYPE      = 6,
-	MCI_GPM_COEX_B_STATUS_LINKID    = 7,
-	MCI_GPM_COEX_B_STATUS_STATE     = 8,
-	/* MCI_GPM_COEX_BT_UPDATE_FLAGS */
-	MCI_GPM_COEX_W_BT_FLAGS         = 6,
-	MCI_GPM_COEX_B_BT_FLAGS_OP      = 10
-};
-
-enum mci_gpm_subtype {
-	MCI_GPM_BT_CAL_REQ      = 0,
-	MCI_GPM_BT_CAL_GRANT    = 1,
-	MCI_GPM_BT_CAL_DONE     = 2,
-	MCI_GPM_WLAN_CAL_REQ    = 3,
-	MCI_GPM_WLAN_CAL_GRANT  = 4,
-	MCI_GPM_WLAN_CAL_DONE   = 5,
-	MCI_GPM_COEX_AGENT      = 0x0c,
-	MCI_GPM_RSVD_PATTERN    = 0xfe,
-	MCI_GPM_RSVD_PATTERN32  = 0xfefefefe,
-	MCI_GPM_BT_DEBUG        = 0xff
-};
-
-enum mci_bt_state {
-	MCI_BT_SLEEP,
-	MCI_BT_AWAKE,
-	MCI_BT_CAL_START,
-	MCI_BT_CAL
-};
-
-/* Type of state query */
-enum mci_state_type {
-	MCI_STATE_ENABLE,
-	MCI_STATE_INIT_GPM_OFFSET,
-	MCI_STATE_NEXT_GPM_OFFSET,
-	MCI_STATE_LAST_GPM_OFFSET,
-	MCI_STATE_BT,
-	MCI_STATE_SET_BT_SLEEP,
-	MCI_STATE_SET_BT_AWAKE,
-	MCI_STATE_SET_BT_CAL_START,
-	MCI_STATE_SET_BT_CAL,
-	MCI_STATE_LAST_SCHD_MSG_OFFSET,
-	MCI_STATE_REMOTE_SLEEP,
-	MCI_STATE_CONT_RSSI_POWER,
-	MCI_STATE_CONT_PRIORITY,
-	MCI_STATE_CONT_TXRX,
-	MCI_STATE_RESET_REQ_WAKE,
-	MCI_STATE_SEND_WLAN_COEX_VERSION,
-	MCI_STATE_SET_BT_COEX_VERSION,
-	MCI_STATE_SEND_WLAN_CHANNELS,
-	MCI_STATE_SEND_VERSION_QUERY,
-	MCI_STATE_SEND_STATUS_QUERY,
-	MCI_STATE_NEED_FLUSH_BT_INFO,
-	MCI_STATE_SET_CONCUR_TX_PRI,
-	MCI_STATE_RECOVER_RX,
-	MCI_STATE_NEED_FTP_STOMP,
-	MCI_STATE_NEED_TUNING,
-	MCI_STATE_DEBUG,
-	MCI_STATE_MAX
-};
-
-enum mci_gpm_coex_opcode {
-	MCI_GPM_COEX_VERSION_QUERY,
-	MCI_GPM_COEX_VERSION_RESPONSE,
-	MCI_GPM_COEX_STATUS_QUERY,
-	MCI_GPM_COEX_HALT_BT_GPM,
-	MCI_GPM_COEX_WLAN_CHANNELS,
-	MCI_GPM_COEX_BT_PROFILE_INFO,
-	MCI_GPM_COEX_BT_STATUS_UPDATE,
-	MCI_GPM_COEX_BT_UPDATE_FLAGS
-};
-
-#define MCI_GPM_NOMORE  0
-#define MCI_GPM_MORE    1
-#define MCI_GPM_INVALID 0xffffffff
-
-#define MCI_GPM_RECYCLE(_p_gpm)	do {			  \
-	*(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \
-				MCI_GPM_RSVD_PATTERN32;   \
-} while (0)
-
-#define MCI_GPM_TYPE(_p_gpm)	\
-	(*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff)
-
-#define MCI_GPM_OPCODE(_p_gpm)	\
-	(*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff)
-
-#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type)	do {			   \
-	*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\
-} while (0)
-
-#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do {		   \
-	*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff;	   \
-	*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\
-} while (0)
-
-#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE)
-
 struct ath9k_beacon_state {
 	u32 bs_nexttbtt;
 	u32 bs_nextdtim;
@@ -956,8 +797,9 @@
 	int firpwr[5];
 	enum ath9k_ani_cmd ani_function;
 
-	/* Bluetooth coexistance */
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	struct ath_btcoex_hw btcoex_hw;
+#endif
 
 	u32 intr_txqs;
 	u8 txchainmask;
@@ -1205,41 +1047,31 @@
 void ath9k_hw_proc_mib_event(struct ath_hw *ah);
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
-bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
-			     u32 *payload, u8 len, bool wait_done,
-			     bool check_bt);
-void ar9003_mci_mute_bt(struct ath_hw *ah);
-u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
-void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
-		      u16 len, u32 sched_addr);
-void ar9003_mci_cleanup(struct ath_hw *ah);
-void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
-				      bool wait_done);
-u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
-			    u8 gpm_opcode, int time_out);
-void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g);
-void ar9003_mci_disable_interrupt(struct ath_hw *ah);
-void ar9003_mci_enable_interrupt(struct ath_hw *ah);
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
-void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
-		      bool is_full_sleep);
-bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints);
-void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done);
-void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done);
-void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done);
-void ar9003_mci_sync_bt_state(struct ath_hw *ah);
-void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
-			      u32 *rx_msg_intr);
-
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
+{
+	return ah->btcoex_hw.enabled;
+}
+void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 static inline enum ath_btcoex_scheme
 ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
 {
 	return ah->btcoex_hw.scheme;
 }
 #else
-#define ath9k_hw_get_btcoex_scheme(...) ATH_BTCOEX_CFG_NONE
-#endif
+static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
+{
+	return false;
+}
+static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+{
+}
+static inline enum ath_btcoex_scheme
+ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
+{
+	return ATH_BTCOEX_CFG_NONE;
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #define ATH9K_CLOCK_RATE_CCK		22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM	40
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 53a005d..d8b0596 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -419,66 +419,6 @@
 	return error;
 }
 
-static int ath9k_init_btcoex(struct ath_softc *sc)
-{
-	struct ath_txq *txq;
-	struct ath_hw *ah = sc->sc_ah;
-	int r;
-
-	switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) {
-	case ATH_BTCOEX_CFG_NONE:
-		break;
-	case ATH_BTCOEX_CFG_2WIRE:
-		ath9k_hw_btcoex_init_2wire(sc->sc_ah);
-		break;
-	case ATH_BTCOEX_CFG_3WIRE:
-		ath9k_hw_btcoex_init_3wire(sc->sc_ah);
-		r = ath_init_btcoex_timer(sc);
-		if (r)
-			return -1;
-		txq = sc->tx.txq_map[WME_AC_BE];
-		ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
-		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-		break;
-	case ATH_BTCOEX_CFG_MCI:
-		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-		sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
-		INIT_LIST_HEAD(&sc->btcoex.mci.info);
-
-		r = ath_mci_setup(sc);
-		if (r)
-			return r;
-
-		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
-			ah->btcoex_hw.mci.ready = false;
-			ah->btcoex_hw.mci.bt_state = 0;
-			ah->btcoex_hw.mci.bt_ver_major = 3;
-			ah->btcoex_hw.mci.bt_ver_minor = 0;
-			ah->btcoex_hw.mci.bt_version_known = false;
-			ah->btcoex_hw.mci.update_2g5g = true;
-			ah->btcoex_hw.mci.is_2g = true;
-			ah->btcoex_hw.mci.wlan_channels_update = false;
-			ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
-			ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
-			ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
-			ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
-			ah->btcoex_hw.mci.query_bt = true;
-			ah->btcoex_hw.mci.unhalt_bt_gpm = true;
-			ah->btcoex_hw.mci.halted_bt_gpm = false;
-			ah->btcoex_hw.mci.need_flush_btinfo = false;
-			ah->btcoex_hw.mci.wlan_cal_seq = 0;
-			ah->btcoex_hw.mci.wlan_cal_done = 0;
-			ah->btcoex_hw.mci.config = 0x2201;
-		}
-		break;
-	default:
-		WARN_ON(1);
-		break;
-	}
-
-	return 0;
-}
-
 static int ath9k_init_queues(struct ath_softc *sc)
 {
 	int i = 0;
@@ -880,12 +820,7 @@
 	if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
 		kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
 
-        if ((sc->btcoex.no_stomp_timer) &&
-	    ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE)
-		ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
-
-	if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI)
-		ath_mci_cleanup(sc);
+	ath9k_deinit_btcoex(sc);
 
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
 		if (ATH_TXQ_SETUP(sc, i))
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index ec82e92..02e95c8 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -371,12 +371,8 @@
 	if (sc->sc_flags & SC_OP_INVALID)
 		return -EIO;
 
-	ath9k_ps_wakeup(sc);
-
 	r = ath_reset_internal(sc, hchan, false);
 
-	ath9k_ps_restore(sc);
-
 	return r;
 }
 
@@ -739,12 +735,7 @@
 			ath_tx_tasklet(sc);
 	}
 
-	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
-		if (status & ATH9K_INT_GENTIMER)
-			ath_gen_timer_isr(sc->sc_ah);
-
-	if ((status & ATH9K_INT_MCI) && ATH9K_HW_CAP_MCI)
-		ath_mci_intr(sc);
+	ath9k_btcoex_handle_interrupt(sc, status);
 
 out:
 	/* re-enable hardware interrupt */
@@ -1079,16 +1070,7 @@
 
 	spin_unlock_bh(&sc->sc_pcu_lock);
 
-	if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) &&
-	    !ah->btcoex_hw.enabled) {
-		if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
-			ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-						   AR_STOMP_LOW_WLAN_WGHT);
-		ath9k_hw_btcoex_enable(ah);
-
-		if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
-			ath9k_btcoex_timer_resume(sc);
-	}
+	ath9k_start_btcoex(sc);
 
 	if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
 		common->bus_ops->extn_synch_en(common);
@@ -1189,13 +1171,7 @@
 	/* Ensure HW is awake when we try to shut it down. */
 	ath9k_ps_wakeup(sc);
 
-	if (ah->btcoex_hw.enabled &&
-	    ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
-		ath9k_hw_btcoex_disable(ah);
-		if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
-			ath9k_btcoex_timer_pause(sc);
-		ath_mci_flush_profile(&sc->btcoex.mci);
-	}
+	ath9k_stop_btcoex(sc);
 
 	spin_lock_bh(&sc->sc_pcu_lock);
 
@@ -1587,12 +1563,6 @@
 	ath9k_ps_wakeup(sc);
 	mutex_lock(&sc->mutex);
 
-	/*
-	 * Leave this as the first check because we need to turn on the
-	 * radio if it was disabled before prior to processing the rest
-	 * of the changes. Likewise we must only disable the radio towards
-	 * the end.
-	 */
 	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
 		sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 		if (sc->ps_idle)
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 05c23ea..29fe52d 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -42,24 +42,18 @@
 	struct ath_mci_profile_info *entry;
 
 	if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&
-	    (info->type == MCI_GPM_COEX_PROFILE_VOICE)) {
-		ath_dbg(common, MCI,
-			"Too many SCO profile, failed to add new profile\n");
+	    (info->type == MCI_GPM_COEX_PROFILE_VOICE))
 		return false;
-	}
 
 	if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) &&
-	    (info->type != MCI_GPM_COEX_PROFILE_VOICE)) {
-		ath_dbg(common, MCI,
-			"Too many ACL profile, failed to add new profile\n");
+	    (info->type != MCI_GPM_COEX_PROFILE_VOICE))
 		return false;
-	}
 
 	entry = ath_mci_find_profile(mci, info);
 
-	if (entry)
+	if (entry) {
 		memcpy(entry, info, 10);
-	else {
+	} else {
 		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 		if (!entry)
 			return false;
@@ -68,6 +62,7 @@
 		INC_PROF(mci, info);
 		list_add_tail(&info->list, &mci->info);
 	}
+
 	return true;
 }
 
@@ -79,10 +74,9 @@
 
 	entry = ath_mci_find_profile(mci, info);
 
-	if (!entry) {
-		ath_dbg(common, MCI, "Profile to be deleted not found\n");
+	if (!entry)
 		return;
-	}
+
 	DEC_PROF(mci, entry);
 	list_del(&entry->list);
 	kfree(entry);
@@ -177,13 +171,12 @@
 
 	btcoex->btcoex_period *= 1000;
 	btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
-					(100 - btcoex->duty_cycle) / 100;
+		(100 - btcoex->duty_cycle) / 100;
 
 	ath9k_hw_btcoex_enable(sc->sc_ah);
 	ath9k_btcoex_timer_resume(sc);
 }
 
-
 static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 {
 	struct ath_hw *ah = sc->sc_ah;
@@ -192,42 +185,24 @@
 
 	switch (opcode) {
 	case MCI_GPM_BT_CAL_REQ:
-
-		ath_dbg(common, MCI, "MCI received BT_CAL_REQ\n");
-
 		if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
 			ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL);
 			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-		} else
-			ath_dbg(common, MCI, "MCI State mismatches: %d\n",
+		} else {
+			ath_dbg(common, MCI, "MCI State mismatch: %d\n",
 				ar9003_mci_state(ah, MCI_STATE_BT, NULL));
-
+		}
 		break;
-
 	case MCI_GPM_BT_CAL_DONE:
-
-		ath_dbg(common, MCI, "MCI received BT_CAL_DONE\n");
-
-		if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_CAL)
-			ath_dbg(common, MCI, "MCI error illegal!\n");
-		else
-			ath_dbg(common, MCI, "MCI BT not in CAL state\n");
-
+		ar9003_mci_state(ah, MCI_STATE_BT, NULL);
 		break;
-
 	case MCI_GPM_BT_CAL_GRANT:
-
-		ath_dbg(common, MCI, "MCI received BT_CAL_GRANT\n");
-
-		/* Send WLAN_CAL_DONE for now */
-		ath_dbg(common, MCI, "MCI send WLAN_CAL_DONE\n");
 		MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
 		ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload,
 					16, false, true);
 		break;
-
 	default:
-		ath_dbg(common, MCI, "MCI Unknown GPM CAL message\n");
+		ath_dbg(common, MCI, "Unknown GPM CAL message\n");
 		break;
 	}
 }
@@ -247,6 +222,7 @@
 
 	btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
 	mci->aggr_limit = mci->num_sco ? 6 : 0;
+
 	if (NUM_PROF(mci)) {
 		btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
 		btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
@@ -262,31 +238,24 @@
 static void ath_mci_process_status(struct ath_softc *sc,
 				   struct ath_mci_profile_status *status)
 {
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_btcoex *btcoex = &sc->btcoex;
 	struct ath_mci_profile *mci = &btcoex->mci;
 	struct ath_mci_profile_info info;
 	int i = 0, old_num_mgmt = mci->num_mgmt;
 
 	/* Link status type are not handled */
-	if (status->is_link) {
-		ath_dbg(common, MCI, "Skip link type status update\n");
+	if (status->is_link)
 		return;
-	}
 
 	memset(&info, 0, sizeof(struct ath_mci_profile_info));
 
 	info.conn_handle = status->conn_handle;
-	if (ath_mci_find_profile(mci, &info)) {
-		ath_dbg(common, MCI,
-			"Skip non link state update for existing profile %d\n",
-			status->conn_handle);
+	if (ath_mci_find_profile(mci, &info))
 		return;
-	}
-	if (status->conn_handle >= ATH_MCI_MAX_PROFILE) {
-		ath_dbg(common, MCI, "Ignore too many non-link update\n");
+
+	if (status->conn_handle >= ATH_MCI_MAX_PROFILE)
 		return;
-	}
+
 	if (status->is_critical)
 		__set_bit(status->conn_handle, mci->status);
 	else
@@ -314,43 +283,28 @@
 	u32 seq_num;
 
 	switch (opcode) {
-
 	case MCI_GPM_COEX_VERSION_QUERY:
-		ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n");
-		version = ar9003_mci_state(ah,
-				MCI_STATE_SEND_WLAN_COEX_VERSION, NULL);
+		version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION,
+					   NULL);
 		break;
-
 	case MCI_GPM_COEX_VERSION_RESPONSE:
-		ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n");
 		major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
 		minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
-		ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n",
-			major, minor);
 		version = (major << 8) + minor;
-		version = ar9003_mci_state(ah,
-			  MCI_STATE_SET_BT_COEX_VERSION, &version);
+		version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION,
+					   &version);
 		break;
-
 	case MCI_GPM_COEX_STATUS_QUERY:
-		ath_dbg(common, MCI,
-			"MCI Recv GPM COEX Status Query = 0x%02x\n",
-			*(rx_payload + MCI_GPM_COEX_B_WLAN_BITMAP));
-		ar9003_mci_state(ah,
-		MCI_STATE_SEND_WLAN_CHANNELS, NULL);
+		ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL);
 		break;
-
 	case MCI_GPM_COEX_BT_PROFILE_INFO:
-		ath_dbg(common, MCI, "MCI Recv GPM Coex BT profile info\n");
 		memcpy(&profile_info,
 		       (rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10);
 
-		if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN)
-		    || (profile_info.type >=
-					    MCI_GPM_COEX_PROFILE_MAX)) {
-
+		if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN) ||
+		    (profile_info.type >= MCI_GPM_COEX_PROFILE_MAX)) {
 			ath_dbg(common, MCI,
-				"illegal profile type = %d, state = %d\n",
+				"Illegal profile type = %d, state = %d\n",
 				profile_info.type,
 				profile_info.start);
 			break;
@@ -358,7 +312,6 @@
 
 		ath_mci_process_profile(sc, &profile_info);
 		break;
-
 	case MCI_GPM_COEX_BT_STATUS_UPDATE:
 		profile_status.is_link = *(rx_payload +
 					   MCI_GPM_COEX_B_STATUS_TYPE);
@@ -369,98 +322,66 @@
 
 		seq_num = *((u32 *)(rx_payload + 12));
 		ath_dbg(common, MCI,
-			"MCI Recv GPM COEX BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n",
+			"BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n",
 			profile_status.is_link, profile_status.conn_handle,
 			profile_status.is_critical, seq_num);
 
 		ath_mci_process_status(sc, &profile_status);
 		break;
-
 	default:
-		ath_dbg(common, MCI, "MCI Unknown GPM COEX message = 0x%02x\n",
-			opcode);
+		ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode);
 		break;
 	}
 }
 
-static int ath_mci_buf_alloc(struct ath_softc *sc, struct ath_mci_buf *buf)
-{
-	int error = 0;
-
-	buf->bf_addr = dma_alloc_coherent(sc->dev, buf->bf_len,
-					  &buf->bf_paddr, GFP_KERNEL);
-
-	if (buf->bf_addr == NULL) {
-		error = -ENOMEM;
-		goto fail;
-	}
-
-	return 0;
-
-fail:
-	memset(buf, 0, sizeof(*buf));
-	return error;
-}
-
-static void ath_mci_buf_free(struct ath_softc *sc, struct ath_mci_buf *buf)
-{
-	if (buf->bf_addr) {
-		dma_free_coherent(sc->dev, buf->bf_len, buf->bf_addr,
-							buf->bf_paddr);
-		memset(buf, 0, sizeof(*buf));
-	}
-}
-
 int ath_mci_setup(struct ath_softc *sc)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_mci_coex *mci = &sc->mci_coex;
-	int error = 0;
+	struct ath_mci_buf *buf = &mci->sched_buf;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return 0;
+	buf->bf_addr = dma_alloc_coherent(sc->dev,
+				  ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
+				  &buf->bf_paddr, GFP_KERNEL);
 
-	mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE;
-
-	if (ath_mci_buf_alloc(sc, &mci->sched_buf)) {
+	if (buf->bf_addr == NULL) {
 		ath_dbg(common, FATAL, "MCI buffer alloc failed\n");
-		error = -ENOMEM;
-		goto fail;
+		return -ENOMEM;
 	}
 
+	memset(buf->bf_addr, MCI_GPM_RSVD_PATTERN,
+	       ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE);
+
 	mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE;
 
-	memset(mci->sched_buf.bf_addr, MCI_GPM_RSVD_PATTERN,
-						mci->sched_buf.bf_len);
-
 	mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE;
-	mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr +
-							mci->sched_buf.bf_len;
+	mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + mci->sched_buf.bf_len;
 	mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len;
 
-	/* initialize the buffer */
-	memset(mci->gpm_buf.bf_addr, MCI_GPM_RSVD_PATTERN, mci->gpm_buf.bf_len);
-
 	ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr,
 			 mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
 			 mci->sched_buf.bf_paddr);
-fail:
-	return error;
+
+	ath_dbg(common, MCI, "MCI Initialized\n");
+
+	return 0;
 }
 
 void ath_mci_cleanup(struct ath_softc *sc)
 {
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_mci_coex *mci = &sc->mci_coex;
+	struct ath_mci_buf *buf = &mci->sched_buf;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return;
+	if (buf->bf_addr)
+		dma_free_coherent(sc->dev,
+				  ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
+				  buf->bf_addr, buf->bf_paddr);
 
-	/*
-	 * both schedule and gpm buffers will be released
-	 */
-	ath_mci_buf_free(sc, &mci->sched_buf);
 	ar9003_mci_cleanup(ah);
+
+	ath_dbg(common, MCI, "MCI De-Initialized\n");
 }
 
 void ath_mci_intr(struct ath_softc *sc)
@@ -474,19 +395,10 @@
 	u32 more_data = MCI_GPM_MORE;
 	bool skip_gpm = false;
 
-	if (!ATH9K_HW_CAP_MCI)
-		return;
-
 	ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg);
 
 	if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) {
-
-		ar9003_mci_state(sc->sc_ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
-		ath_dbg(common, MCI, "MCI interrupt but MCI disabled\n");
-
-		ath_dbg(common, MCI,
-			"MCI interrupt: intr = 0x%x, intr_rxmsg = 0x%x\n",
-			mci_int, mci_int_rxmsg);
+		ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
 		return;
 	}
 
@@ -499,11 +411,8 @@
 		 * only when BT wake up. Now they are always sent, as a
 		 * recovery method to reset BT MCI's RX alignment.
 		 */
-		ath_dbg(common, MCI, "MCI interrupt send REMOTE_RESET\n");
-
 		ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0,
 					payload, 16, true, false);
-		ath_dbg(common, MCI, "MCI interrupt send SYS_WAKING\n");
 		ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0,
 					NULL, 0, true, false);
 
@@ -513,74 +422,51 @@
 		/*
 		 * always do this for recovery and 2G/5G toggling and LNA_TRANS
 		 */
-		ath_dbg(common, MCI, "MCI Set BT state to AWAKE\n");
 		ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL);
 	}
 
-	/* Processing SYS_WAKING/SYS_SLEEPING */
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
 		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
 
 		if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) {
-
-			if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL)
-					== MCI_BT_SLEEP)
-				ath_dbg(common, MCI,
-					"MCI BT stays in sleep mode\n");
-			else {
-				ath_dbg(common, MCI,
-					"MCI Set BT state to AWAKE\n");
-				ar9003_mci_state(ah,
-						 MCI_STATE_SET_BT_AWAKE, NULL);
-			}
-		} else
-			ath_dbg(common, MCI, "MCI BT stays in AWAKE mode\n");
+			if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
+			    MCI_BT_SLEEP)
+				ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE,
+						 NULL);
+		}
 	}
 
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
-
 		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
 
 		if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
-
-			if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL)
-					== MCI_BT_AWAKE)
-				ath_dbg(common, MCI,
-					"MCI BT stays in AWAKE mode\n");
-			else {
-				ath_dbg(common, MCI,
-					"MCI SetBT state to SLEEP\n");
+			if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
+			    MCI_BT_AWAKE)
 				ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP,
 						 NULL);
-			}
-		} else
-			ath_dbg(common, MCI, "MCI BT stays in SLEEP mode\n");
+		}
 	}
 
 	if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
 	    (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
-
-		ath_dbg(common, MCI, "MCI RX broken, skip GPM msgs\n");
 		ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL);
 		skip_gpm = true;
 	}
 
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
-
 		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
 		offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET,
 					  NULL);
 	}
 
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) {
-
 		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;
 
 		while (more_data == MCI_GPM_MORE) {
 
 			pgpm = mci->gpm_buf.bf_addr;
-			offset = ar9003_mci_state(ah,
-					MCI_STATE_NEXT_GPM_OFFSET, &more_data);
+			offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
+						  &more_data);
 
 			if (offset == MCI_GPM_INVALID)
 				break;
@@ -591,44 +477,38 @@
 			 * The first dword is timer.
 			 * The real data starts from 2nd dword.
 			 */
-
 			subtype = MCI_GPM_TYPE(pgpm);
 			opcode = MCI_GPM_OPCODE(pgpm);
 
-			if (!skip_gpm) {
+			if (skip_gpm)
+				goto recycle;
 
-				if (MCI_GPM_IS_CAL_TYPE(subtype))
-					ath_mci_cal_msg(sc, subtype,
-							(u8 *) pgpm);
-				else {
-					switch (subtype) {
-					case MCI_GPM_COEX_AGENT:
-						ath_mci_msg(sc, opcode,
-							    (u8 *) pgpm);
-						break;
-					default:
-						break;
-					}
+			if (MCI_GPM_IS_CAL_TYPE(subtype)) {
+				ath_mci_cal_msg(sc, subtype, (u8 *)pgpm);
+			} else {
+				switch (subtype) {
+				case MCI_GPM_COEX_AGENT:
+					ath_mci_msg(sc, opcode, (u8 *)pgpm);
+					break;
+				default:
+					break;
 				}
 			}
+		recycle:
 			MCI_GPM_RECYCLE(pgpm);
 		}
 	}
 
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) {
-
 		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL)
 			mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL;
 
-		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) {
+		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO)
 			mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO;
-			ath_dbg(common, MCI, "MCI LNA_INFO\n");
-		}
 
 		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
-
 			int value_dbm = ar9003_mci_state(ah,
-					MCI_STATE_CONT_RSSI_POWER, NULL);
+						 MCI_STATE_CONT_RSSI_POWER, NULL);
 
 			mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO;
 
@@ -636,33 +516,25 @@
 				ath_dbg(common, MCI,
 					"MCI CONT_INFO: (tx) pri = %d, pwr = %d dBm\n",
 					ar9003_mci_state(ah,
-						MCI_STATE_CONT_PRIORITY, NULL),
+						 MCI_STATE_CONT_PRIORITY, NULL),
 					value_dbm);
 			else
 				ath_dbg(common, MCI,
 					"MCI CONT_INFO: (rx) pri = %d,pwr = %d dBm\n",
 					ar9003_mci_state(ah,
-						MCI_STATE_CONT_PRIORITY, NULL),
+						 MCI_STATE_CONT_PRIORITY, NULL),
 					value_dbm);
 		}
 
-		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) {
+		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK)
 			mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK;
-			ath_dbg(common, MCI, "MCI CONT_NACK\n");
-		}
 
-		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) {
+		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST)
 			mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST;
-			ath_dbg(common, MCI, "MCI CONT_RST\n");
-		}
 	}
 
 	if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
 	    (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT))
 		mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
 			     AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
-
-	if (mci_int_rxmsg & 0xfffffffe)
-		ath_dbg(common, MCI, "MCI not processed mci_int_rxmsg = 0x%x\n",
-			mci_int_rxmsg);
 }
diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h
index 29e3e51..c841444 100644
--- a/drivers/net/wireless/ath/ath9k/mci.h
+++ b/drivers/net/wireless/ath/ath9k/mci.h
@@ -17,6 +17,8 @@
 #ifndef MCI_H
 #define MCI_H
 
+#include "ar9003_mci.h"
+
 #define ATH_MCI_SCHED_BUF_SIZE		(16 * 16) /* 16 entries, 4 dword each */
 #define ATH_MCI_GPM_MAX_ENTRY		16
 #define ATH_MCI_GPM_BUF_SIZE		(ATH_MCI_GPM_MAX_ENTRY * 16)
@@ -113,7 +115,6 @@
 	u8 num_bdr;
 };
 
-
 struct ath_mci_buf {
 	void *bf_addr;		/* virtual addr of desc */
 	dma_addr_t bf_paddr;    /* physical addr of buffer */
@@ -121,10 +122,8 @@
 };
 
 struct ath_mci_coex {
-	atomic_t mci_cal_flag;
 	struct ath_mci_buf sched_buf;
 	struct ath_mci_buf gpm_buf;
-	u32 bt_cal_start;
 };
 
 void ath_mci_flush_profile(struct ath_mci_profile *mci);
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index a427a16..b8c6c38 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -567,10 +567,8 @@
 
 static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
 				  const struct ath_rate_table *rate_table,
-				  u8 *mcs_set, u32 capflag)
+				  struct ath_rateset *rateset, u32 capflag)
 {
-	struct ath_rateset *rateset = (struct ath_rateset *)mcs_set;
-
 	u8 i, j, hi = 0;
 
 	/* Use intersection of working rates and valid rates */
@@ -1212,7 +1210,7 @@
 {
 	struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
+	struct ath_rateset *ht_mcs = &ath_rc_priv->neg_ht_rates;
 	u8 i, j, k, hi = 0, hthi = 0;
 
 	/* Initial rate table size. Will change depending
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 6e2f188..80b1856 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -797,7 +797,6 @@
 #define AR_SREV_VERSION_9580		0x1C0
 #define AR_SREV_REVISION_9580_10	4 /* AR9580 1.0 */
 #define AR_SREV_VERSION_9462		0x280
-#define AR_SREV_REVISION_9462_10	0
 #define AR_SREV_REVISION_9462_20	2
 
 #define AR_SREV_5416(_ah) \
@@ -898,10 +897,6 @@
 #define AR_SREV_9462(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462))
 
-#define AR_SREV_9462_10(_ah) \
-	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
-	((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_10))
-
 #define AR_SREV_9462_20(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
 	((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20))
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 3182408..5dd27d2 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -647,9 +647,8 @@
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *tx_info;
 	struct ieee80211_tx_rate *rates;
-	struct ath_mci_profile *mci = &sc->btcoex.mci;
 	u32 max_4ms_framelen, frmlen;
-	u16 aggr_limit, legacy = 0;
+	u16 aggr_limit, bt_aggr_limit, legacy = 0;
 	int i;
 
 	skb = bf->bf_mpdu;
@@ -694,14 +693,14 @@
 	if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
 		return 0;
 
-	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
-		aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
-	else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
-		aggr_limit = min((max_4ms_framelen * 3) / 8,
-				 (u32)ATH_AMPDU_LIMIT_MAX);
-	else
-		aggr_limit = min(max_4ms_framelen,
-				 (u32)ATH_AMPDU_LIMIT_MAX);
+	aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX);
+
+	/*
+	 * Override the default aggregation limit for BTCOEX.
+	 */
+	bt_aggr_limit = ath9k_btcoex_aggr_limit(sc, max_4ms_framelen);
+	if (bt_aggr_limit)
+		aggr_limit = bt_aggr_limit;
 
 	/*
 	 * h/w can accept aggregates up to 16 bit lengths (65535).
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index 771e1a9..aed3051 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -1236,6 +1236,7 @@
 {
 	struct ieee80211_sta *sta;
 	struct carl9170_sta_info *sta_info;
+	struct ieee80211_tx_info *tx_info;
 
 	rcu_read_lock();
 	sta = __carl9170_get_tx_sta(ar, skb);
@@ -1243,16 +1244,18 @@
 		goto out_rcu;
 
 	sta_info = (void *) sta->drv_priv;
-	if (unlikely(sta_info->sleeping)) {
-		struct ieee80211_tx_info *tx_info;
+	tx_info = IEEE80211_SKB_CB(skb);
 
+	if (unlikely(sta_info->sleeping) &&
+	    !(tx_info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER |
+				IEEE80211_TX_CTL_CLEAR_PS_FILT))) {
 		rcu_read_unlock();
 
-		tx_info = IEEE80211_SKB_CB(skb);
 		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
 			atomic_dec(&ar->tx_ampdu_upload);
 
 		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+		carl9170_release_dev_space(ar, skb);
 		carl9170_tx_status(ar, skb, false);
 		return true;
 	}
diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig
index cd6375d..c510453 100644
--- a/drivers/net/wireless/brcm80211/Kconfig
+++ b/drivers/net/wireless/brcm80211/Kconfig
@@ -26,16 +26,25 @@
 	  it'll be called brcmfmac.ko.
 
 config BRCMFMAC_SDIO
-	bool "SDIO bus interface support for FullMAC"
+	bool "SDIO bus interface support for FullMAC driver"
 	depends on MMC
 	depends on BRCMFMAC
 	select FW_LOADER
 	default y
 	---help---
 	  This option enables the SDIO bus interface support for Broadcom
-	  FullMAC WLAN driver.
-	  Say Y if you want to use brcmfmac for a compatible SDIO interface
-	  wireless card.
+	  IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
+	  use the driver for a SDIO wireless card.
+
+config BRCMFMAC_USB
+	bool "USB bus interface support for FullMAC driver"
+	depends on USB
+	depends on BRCMFMAC
+	select FW_LOADER
+	---help---
+	  This option enables the USB bus interface support for Broadcom
+	  IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
+	  use the driver for an USB wireless card.
 
 config BRCMDBG
 	bool "Broadcom driver debug functions"
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 9ca9ea1..abb48032 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -19,6 +19,8 @@
 	-Idrivers/net/wireless/brcm80211/brcmfmac	\
 	-Idrivers/net/wireless/brcm80211/include
 
+ccflags-y += -D__CHECK_ENDIAN__
+
 obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
 brcmfmac-objs += \
 		wl_cfg80211.o \
@@ -30,5 +32,5 @@
 		bcmsdh.o \
 		bcmsdh_sdmmc.o \
 		sdio_chip.o
-
-ccflags-y += -D__CHECK_ENDIAN__
+brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
+		usb.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index ac71ade..83ca3cc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -294,13 +294,14 @@
 			       struct sk_buff *pkt)
 {
 	int status;
-	uint pkt_len = pkt->len;
+	uint pkt_len;
 	bool fifo = (fix_inc == SDIOH_DATA_FIX);
 
 	brcmf_dbg(TRACE, "Enter\n");
 
 	if (pkt == NULL)
 		return -EINVAL;
+	pkt_len = pkt->len;
 
 	brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
 	if (brcmf_pm_resume_error(sdiodev))
@@ -488,7 +489,7 @@
 		sdiodev->func[0] = func->card->sdio_func[0];
 		sdiodev->func[1] = func;
 		sdiodev->bus_if = bus_if;
-		bus_if->bus_priv = sdiodev;
+		bus_if->bus_priv.sdio = sdiodev;
 		bus_if->type = SDIO_BUS;
 		bus_if->align = BRCMF_SDALIGN;
 		dev_set_drvdata(&func->card->dev, sdiodev);
@@ -529,7 +530,7 @@
 
 	if (func->num == 2) {
 		bus_if = dev_get_drvdata(&func->dev);
-		sdiodev = bus_if->bus_priv;
+		sdiodev = bus_if->bus_priv.sdio;
 		brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
 		brcmf_sdio_remove(sdiodev);
 		dev_set_drvdata(&func->card->dev, NULL);
@@ -596,14 +597,14 @@
 #endif	/* CONFIG_PM_SLEEP */
 };
 
-static void __exit brcmf_sdio_exit(void)
+void brcmf_sdio_exit(void)
 {
 	brcmf_dbg(TRACE, "Enter\n");
 
 	sdio_unregister_driver(&brcmf_sdmmc_driver);
 }
 
-static int __init brcmf_sdio_init(void)
+int brcmf_sdio_init(void)
 {
 	int ret;
 
@@ -616,6 +617,3 @@
 
 	return ret;
 }
-
-module_init(brcmf_sdio_init);
-module_exit(brcmf_sdio_exit);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index ad9be24..b7671b3 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -39,8 +39,11 @@
 /* interface structure between common and bus layer */
 struct brcmf_bus {
 	u8 type;		/* bus type */
-	void *bus_priv;		/* pointer to bus private structure */
-	void *drvr;		/* pointer to driver pub structure brcmf_pub */
+	union {
+		struct brcmf_sdio_dev *sdio;
+		struct brcmf_usbdev *usb;
+	} bus_priv;
+	struct brcmf_pub *drvr;	/* pointer to driver pub structure brcmf_pub */
 	enum brcmf_bus_state state;
 	uint maxctl;		/* Max size rxctl request from proto to bus */
 	bool drvr_up;		/* Status flag of driver up/down */
@@ -102,4 +105,14 @@
 
 extern int brcmf_add_if(struct device *dev, int ifidx,
 			char *name, u8 *mac_addr);
+
+#ifdef CONFIG_BRCMFMAC_SDIO
+extern void brcmf_sdio_exit(void);
+extern int brcmf_sdio_init(void);
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+extern void brcmf_usb_exit(void);
+extern int brcmf_usb_init(void);
+#endif
+
 #endif				/* _BRCMF_BUS_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index db2df1f..c4da058 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -796,18 +796,19 @@
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_pub *drvr = ifp->drvr;
+	struct brcmf_bus *bus_if = drvr->bus_if;
 	u32 toe_ol;
 	s32 ret = 0;
 
 	brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
 
 	if (ifp->idx == 0) {	/* do it only for primary eth0 */
-		/* try to bring up bus */
-		ret = brcmf_bus_start(drvr->dev);
-		if (ret != 0) {
-			brcmf_dbg(ERROR, "failed with code %d\n", ret);
-			return -1;
+		/* If bus is not ready, can't continue */
+		if (bus_if->state != BRCMF_BUS_DATA) {
+			brcmf_dbg(ERROR, "failed bus is not ready\n");
+			return -EAGAIN;
 		}
+
 		atomic_set(&drvr->pend_8021x_cnt, 0);
 
 		memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
@@ -979,12 +980,6 @@
 		return ret;
 	}
 
-	/* If bus is not ready, can't come up */
-	if (bus_if->state != BRCMF_BUS_DATA) {
-		brcmf_dbg(ERROR, "failed bus is not ready\n");
-		return -ENODEV;
-	}
-
 	brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
 		      iovbuf, sizeof(iovbuf));
 	brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
@@ -1021,6 +1016,8 @@
 	if (ret < 0)
 		return ret;
 
+	/* signal bus ready */
+	bus_if->state = BRCMF_BUS_DATA;
 	return 0;
 }
 
@@ -1109,13 +1106,13 @@
 		if (drvr->iflist[i])
 			brcmf_del_if(drvr, i);
 
-	cancel_work_sync(&drvr->setmacaddr_work);
-	cancel_work_sync(&drvr->multicast_work);
-
 	brcmf_bus_detach(drvr);
 
-	if (drvr->prot)
+	if (drvr->prot) {
+		cancel_work_sync(&drvr->setmacaddr_work);
+		cancel_work_sync(&drvr->multicast_work);
 		brcmf_proto_detach(drvr);
+	}
 
 	bus_if->drvr = NULL;
 	kfree(drvr);
@@ -1183,3 +1180,35 @@
 	return ret;
 }
 #endif				/* DEBUG */
+
+static int __init brcmfmac_init(void)
+{
+	int ret = 0;
+
+#ifdef CONFIG_BRCMFMAC_SDIO
+	ret = brcmf_sdio_init();
+	if (ret)
+		goto fail;
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+	ret = brcmf_usb_init();
+	if (ret)
+		goto fail;
+#endif
+
+fail:
+	return ret;
+}
+
+static void __exit brcmfmac_exit(void)
+{
+#ifdef CONFIG_BRCMFMAC_SDIO
+	brcmf_sdio_exit();
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+	brcmf_usb_exit();
+#endif
+}
+
+module_init(brcmfmac_init);
+module_exit(brcmfmac_exit);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index bd2d1dd..2bf5dda 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -309,10 +309,10 @@
 /* Flags for SDH calls */
 #define F2SYNC	(SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 
-#define BRCMFMAC_FW_NAME	"brcm/brcmfmac.bin"
-#define BRCMFMAC_NV_NAME	"brcm/brcmfmac.txt"
-MODULE_FIRMWARE(BRCMFMAC_FW_NAME);
-MODULE_FIRMWARE(BRCMFMAC_NV_NAME);
+#define BRCMF_SDIO_FW_NAME	"brcm/brcmfmac-sdio.bin"
+#define BRCMF_SDIO_NV_NAME	"brcm/brcmfmac-sdio.txt"
+MODULE_FIRMWARE(BRCMF_SDIO_FW_NAME);
+MODULE_FIRMWARE(BRCMF_SDIO_NV_NAME);
 
 #define BRCMF_IDLE_IMMEDIATE	(-1)	/* Enter idle immediately */
 #define BRCMF_IDLE_ACTIVE	0	/* Do not request any SD clock change
@@ -2276,7 +2276,7 @@
 	uint retries;
 	int err;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 	struct brcmf_sdio *bus = sdiodev->bus;
 
 	brcmf_dbg(TRACE, "Enter\n");
@@ -2626,7 +2626,7 @@
 	int ret = -EBADE;
 	uint datalen, prec;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 	struct brcmf_sdio *bus = sdiodev->bus;
 
 	brcmf_dbg(TRACE, "Enter\n");
@@ -2867,7 +2867,7 @@
 	u8 doff = 0;
 	int ret = -1;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 	struct brcmf_sdio *bus = sdiodev->bus;
 
 	brcmf_dbg(TRACE, "Enter\n");
@@ -2976,7 +2976,7 @@
 	uint rxlen = 0;
 	bool pending;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 	struct brcmf_sdio *bus = sdiodev->bus;
 
 	brcmf_dbg(TRACE, "Enter\n");
@@ -3200,7 +3200,7 @@
 
 	brcmf_dbg(INFO, "Enter\n");
 
-	ret = request_firmware(&bus->firmware, BRCMFMAC_FW_NAME,
+	ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME,
 			       &bus->sdiodev->func[2]->dev);
 	if (ret) {
 		brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
@@ -3297,7 +3297,7 @@
 	char *bufp;
 	int ret;
 
-	ret = request_firmware(&bus->firmware, BRCMFMAC_NV_NAME,
+	ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
 			       &bus->sdiodev->func[2]->dev);
 	if (ret) {
 		brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
@@ -3387,7 +3387,7 @@
 static int brcmf_sdbrcm_bus_init(struct device *dev)
 {
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 	struct brcmf_sdio *bus = sdiodev->bus;
 	unsigned long timeout;
 	uint retries = 0;
@@ -3462,16 +3462,12 @@
 
 		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
 				       SBSDIO_WATERMARK, 8, &err);
-
-		/* Set bus state according to enable result */
-		bus_if->state = BRCMF_BUS_DATA;
-	}
-
-	else {
+	} else {
 		/* Disable F2 again */
 		enable = SDIO_FUNC_ENABLE_1;
 		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
 				       SDIO_CCCR_IOEx, enable, NULL);
+		ret = -ENODEV;
 	}
 
 	/* Restore previous clock setting */
@@ -3479,7 +3475,7 @@
 			       SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
 
 	/* If we didn't come up, turn off backplane clock */
-	if (bus_if->state != BRCMF_BUS_DATA)
+	if (!ret)
 		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
 
 exit:
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
new file mode 100644
index 0000000..d4a9e8e
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -0,0 +1,1623 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/firmware.h>
+#include <linux/usb.h>
+#include <net/cfg80211.h>
+
+#include <defs.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include <dhd_bus.h>
+#include <dhd_dbg.h>
+
+#include "usb_rdl.h"
+#include "usb.h"
+
+#define IOCTL_RESP_TIMEOUT  2000
+
+#define BRCMF_USB_SYNC_TIMEOUT		300	/* ms */
+#define BRCMF_USB_DLIMAGE_SPINWAIT	100	/* in unit of ms */
+#define BRCMF_USB_DLIMAGE_LIMIT		500	/* spinwait limit (ms) */
+
+#define BRCMF_POSTBOOT_ID		0xA123  /* ID to detect if dongle
+						   has boot up */
+#define BRCMF_USB_RESETCFG_SPINWAIT	1	/* wait after resetcfg (ms) */
+
+#define BRCMF_USB_NRXQ	50
+#define BRCMF_USB_NTXQ	50
+
+#define CONFIGDESC(usb)         (&((usb)->actconfig)->desc)
+#define IFPTR(usb, idx)         ((usb)->actconfig->interface[(idx)])
+#define IFALTS(usb, idx)        (IFPTR((usb), (idx))->altsetting[0])
+#define IFDESC(usb, idx)        IFALTS((usb), (idx)).desc
+#define IFEPDESC(usb, idx, ep)  (IFALTS((usb), (idx)).endpoint[(ep)]).desc
+
+#define CONTROL_IF              0
+#define BULK_IF                 0
+
+#define BRCMF_USB_CBCTL_WRITE	0
+#define BRCMF_USB_CBCTL_READ	1
+#define BRCMF_USB_MAX_PKT_SIZE	1600
+
+#define BRCMF_USB_43236_FW_NAME	"brcm/brcmfmac43236b.bin"
+
+enum usbdev_suspend_state {
+	USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow
+						  suspend */
+	USBOS_SUSPEND_STATE_SUSPEND_PENDING,	/* Device is idle, can be
+						 * suspended. Wating PM to
+						 * suspend the device
+						 */
+	USBOS_SUSPEND_STATE_SUSPENDED	/* Device suspended */
+};
+
+struct brcmf_usb_probe_info {
+	void *usbdev_info;
+	struct usb_device *usb; /* USB device pointer from OS */
+	uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
+	int intr_size; /* Size of interrupt message */
+	int interval;  /* Interrupt polling interval */
+	int vid;
+	int pid;
+	enum usb_device_speed device_speed;
+	enum usbdev_suspend_state suspend_state;
+	struct usb_interface *intf;
+};
+static struct brcmf_usb_probe_info usbdev_probe_info;
+
+struct brcmf_usb_image {
+	void *data;
+	u32 len;
+};
+static struct brcmf_usb_image g_image = { NULL, 0 };
+
+struct intr_transfer_buf {
+	u32 notification;
+	u32 reserved;
+};
+
+struct brcmf_usbdev_info {
+	struct brcmf_usbdev bus_pub; /* MUST BE FIRST */
+	spinlock_t qlock;
+	struct list_head rx_freeq;
+	struct list_head rx_postq;
+	struct list_head tx_freeq;
+	struct list_head tx_postq;
+	enum usbdev_suspend_state suspend_state;
+	uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
+
+	bool activity;
+	int rx_low_watermark;
+	int tx_low_watermark;
+	int tx_high_watermark;
+	bool txoff;
+	bool rxoff;
+	bool txoverride;
+
+	struct brcmf_usbreq *tx_reqs;
+	struct brcmf_usbreq *rx_reqs;
+
+	u8 *image;	/* buffer for combine fw and nvram */
+	int image_len;
+
+	wait_queue_head_t wait;
+	bool waitdone;
+	int sync_urb_status;
+
+	struct usb_device *usbdev;
+	struct device *dev;
+	enum usb_device_speed  device_speed;
+
+	int ctl_in_pipe, ctl_out_pipe;
+	struct urb *ctl_urb; /* URB for control endpoint */
+	struct usb_ctrlrequest ctl_write;
+	struct usb_ctrlrequest ctl_read;
+	u32 ctl_urb_actual_length;
+	int ctl_urb_status;
+	int ctl_completed;
+	wait_queue_head_t ioctl_resp_wait;
+	wait_queue_head_t ctrl_wait;
+	ulong ctl_op;
+
+	bool rxctl_deferrespok;
+
+	struct urb *bulk_urb; /* used for FW download */
+	struct urb *intr_urb; /* URB for interrupt endpoint */
+	int intr_size;          /* Size of interrupt message */
+	int interval;           /* Interrupt polling interval */
+	struct intr_transfer_buf intr; /* Data buffer for interrupt endpoint */
+
+	struct brcmf_usb_probe_info probe_info;
+
+};
+
+static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
+				struct brcmf_usbreq  *req);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac usb driver.");
+MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac usb cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct brcmf_usbdev *brcmf_usb_get_buspub(struct device *dev)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	return bus_if->bus_priv.usb;
+}
+
+static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev)
+{
+	return brcmf_usb_get_buspub(dev)->devinfo;
+}
+
+#if 0
+static void
+brcmf_usb_txflowcontrol(struct brcmf_usbdev_info *devinfo, bool onoff)
+{
+	dhd_txflowcontrol(devinfo->bus_pub.netdev, 0, onoff);
+}
+#endif
+
+static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo,
+	 uint *condition, bool *pending)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int timeout = IOCTL_RESP_TIMEOUT;
+
+	/* Convert timeout in millsecond to jiffies */
+	timeout = msecs_to_jiffies(timeout);
+	/* Wait until control frame is available */
+	add_wait_queue(&devinfo->ioctl_resp_wait, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	smp_mb();
+	while (!(*condition) && (!signal_pending(current) && timeout)) {
+		timeout = schedule_timeout(timeout);
+		/* Wait until control frame is available */
+		smp_mb();
+	}
+
+	if (signal_pending(current))
+		*pending = true;
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&devinfo->ioctl_resp_wait, &wait);
+
+	return timeout;
+}
+
+static int brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
+{
+	if (waitqueue_active(&devinfo->ioctl_resp_wait))
+		wake_up_interruptible(&devinfo->ioctl_resp_wait);
+
+	return 0;
+}
+
+static void
+brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status)
+{
+
+	if (unlikely(devinfo == NULL))
+		return;
+
+	if (type == BRCMF_USB_CBCTL_READ) {
+		if (status == 0)
+			devinfo->bus_pub.stats.rx_ctlpkts++;
+		else
+			devinfo->bus_pub.stats.rx_ctlerrs++;
+	} else if (type == BRCMF_USB_CBCTL_WRITE) {
+		if (status == 0)
+			devinfo->bus_pub.stats.tx_ctlpkts++;
+		else
+			devinfo->bus_pub.stats.tx_ctlerrs++;
+	}
+
+	devinfo->ctl_urb_status = status;
+	devinfo->ctl_completed = true;
+	brcmf_usb_ioctl_resp_wake(devinfo);
+}
+
+static void
+brcmf_usb_ctlread_complete(struct urb *urb)
+{
+	struct brcmf_usbdev_info *devinfo =
+		(struct brcmf_usbdev_info *)urb->context;
+
+	devinfo->ctl_urb_actual_length = urb->actual_length;
+	brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ,
+		urb->status);
+}
+
+static void
+brcmf_usb_ctlwrite_complete(struct urb *urb)
+{
+	struct brcmf_usbdev_info *devinfo =
+		(struct brcmf_usbdev_info *)urb->context;
+
+	brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_WRITE,
+		urb->status);
+}
+
+static int brcmf_usb_pnp(struct brcmf_usbdev_info *devinfo, uint state)
+{
+	return 0;
+}
+
+static int
+brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
+{
+	int ret;
+	u16 size;
+
+	if (devinfo == NULL || buf == NULL ||
+	    len == 0 || devinfo->ctl_urb == NULL)
+		return -EINVAL;
+
+	/* If the USB/HSIC bus in sleep state, wake it up */
+	if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED)
+		if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
+			brcmf_dbg(ERROR, "Could not Resume the bus!\n");
+			return -EIO;
+		}
+
+	devinfo->activity = true;
+	size = len;
+	devinfo->ctl_write.wLength = cpu_to_le16p(&size);
+	devinfo->ctl_urb->transfer_buffer_length = size;
+	devinfo->ctl_urb_status = 0;
+	devinfo->ctl_urb_actual_length = 0;
+
+	usb_fill_control_urb(devinfo->ctl_urb,
+		devinfo->usbdev,
+		devinfo->ctl_out_pipe,
+		(unsigned char *) &devinfo->ctl_write,
+		buf, size,
+		(usb_complete_t)brcmf_usb_ctlwrite_complete,
+		devinfo);
+
+	ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+	if (ret < 0)
+		brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+
+	return ret;
+}
+
+static int
+brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
+{
+	int ret;
+	u16 size;
+
+	if ((devinfo == NULL) || (buf == NULL) || (len == 0)
+		|| (devinfo->ctl_urb == NULL))
+		return -EINVAL;
+
+	size = len;
+	devinfo->ctl_read.wLength = cpu_to_le16p(&size);
+	devinfo->ctl_urb->transfer_buffer_length = size;
+
+	if (devinfo->rxctl_deferrespok) {
+		/* BMAC model */
+		devinfo->ctl_read.bRequestType = USB_DIR_IN
+			| USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
+		devinfo->ctl_read.bRequest = DL_DEFER_RESP_OK;
+	} else {
+		/* full dongle model */
+		devinfo->ctl_read.bRequestType = USB_DIR_IN
+			| USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+		devinfo->ctl_read.bRequest = 1;
+	}
+
+	usb_fill_control_urb(devinfo->ctl_urb,
+		devinfo->usbdev,
+		devinfo->ctl_in_pipe,
+		(unsigned char *) &devinfo->ctl_read,
+		buf, size,
+		(usb_complete_t)brcmf_usb_ctlread_complete,
+		devinfo);
+
+	ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+	if (ret < 0)
+		brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+
+	return ret;
+}
+
+static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
+{
+	int err = 0;
+	int timeout = 0;
+	bool pending;
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+	if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+		/* TODO: handle suspend/resume */
+		return -EIO;
+	}
+
+	if (test_and_set_bit(0, &devinfo->ctl_op))
+		return -EIO;
+
+	err = brcmf_usb_send_ctl(devinfo, buf, len);
+	if (err) {
+		brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
+		return err;
+	}
+
+	devinfo->ctl_completed = false;
+	timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
+					    &pending);
+	clear_bit(0, &devinfo->ctl_op);
+	if (!timeout) {
+		brcmf_dbg(ERROR, "Txctl wait timed out\n");
+		err = -EIO;
+	}
+	return err;
+}
+
+static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
+{
+	int err = 0;
+	int timeout = 0;
+	bool pending;
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+	if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+		/* TODO: handle suspend/resume */
+		return -EIO;
+	}
+	if (test_and_set_bit(0, &devinfo->ctl_op))
+		return -EIO;
+
+	err = brcmf_usb_recv_ctl(devinfo, buf, len);
+	if (err) {
+		brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
+		return err;
+	}
+	devinfo->ctl_completed = false;
+	timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
+					    &pending);
+	err = devinfo->ctl_urb_status;
+	clear_bit(0, &devinfo->ctl_op);
+	if (!timeout) {
+		brcmf_dbg(ERROR, "rxctl wait timed out\n");
+		err = -EIO;
+	}
+	if (!err)
+		return devinfo->ctl_urb_actual_length;
+	else
+		return err;
+}
+
+static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo,
+					  struct list_head *q)
+{
+	unsigned long flags;
+	struct brcmf_usbreq  *req;
+	spin_lock_irqsave(&devinfo->qlock, flags);
+	if (list_empty(q)) {
+		spin_unlock_irqrestore(&devinfo->qlock, flags);
+		return NULL;
+	}
+	req = list_entry(q->next, struct brcmf_usbreq, list);
+	list_del_init(q->next);
+	spin_unlock_irqrestore(&devinfo->qlock, flags);
+	return req;
+
+}
+
+static void brcmf_usb_enq(struct brcmf_usbdev_info *devinfo,
+			  struct list_head *q, struct brcmf_usbreq *req)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&devinfo->qlock, flags);
+	list_add_tail(&req->list, q);
+	spin_unlock_irqrestore(&devinfo->qlock, flags);
+}
+
+static struct brcmf_usbreq *
+brcmf_usbdev_qinit(struct list_head *q, int qsize)
+{
+	int i;
+	struct brcmf_usbreq *req, *reqs;
+
+	reqs = kzalloc(sizeof(struct brcmf_usbreq) * qsize, GFP_ATOMIC);
+	if (reqs == NULL) {
+		brcmf_dbg(ERROR, "fail to allocate memory!\n");
+		return NULL;
+	}
+	req = reqs;
+
+	for (i = 0; i < qsize; i++) {
+		req->urb = usb_alloc_urb(0, GFP_ATOMIC);
+		if (!req->urb)
+			goto fail;
+
+		INIT_LIST_HEAD(&req->list);
+		list_add_tail(&req->list, q);
+		req++;
+	}
+	return reqs;
+fail:
+	brcmf_dbg(ERROR, "fail!\n");
+	while (!list_empty(q)) {
+		req = list_entry(q->next, struct brcmf_usbreq, list);
+		if (req && req->urb)
+			usb_free_urb(req->urb);
+		list_del(q->next);
+	}
+	return NULL;
+
+}
+
+static void brcmf_usb_free_q(struct list_head *q, bool pending)
+{
+	struct brcmf_usbreq *req, *next;
+	int i = 0;
+	list_for_each_entry_safe(req, next, q, list) {
+		if (!req->urb) {
+			brcmf_dbg(ERROR, "bad req\n");
+			break;
+		}
+		i++;
+		if (pending) {
+			usb_kill_urb(req->urb);
+		} else {
+			usb_free_urb(req->urb);
+			list_del_init(&req->list);
+		}
+	}
+}
+
+static void brcmf_usb_del_fromq(struct brcmf_usbdev_info *devinfo,
+				struct brcmf_usbreq *req)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&devinfo->qlock, flags);
+	list_del_init(&req->list);
+	spin_unlock_irqrestore(&devinfo->qlock, flags);
+}
+
+
+static void brcmf_usb_tx_complete(struct urb *urb)
+{
+	struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
+	struct brcmf_usbdev_info *devinfo = req->devinfo;
+
+	brcmf_usb_del_fromq(devinfo, req);
+	if (urb->status == 0)
+		devinfo->bus_pub.stats.tx_packets++;
+	else
+		devinfo->bus_pub.stats.tx_errors++;
+
+	dev_kfree_skb(req->skb);
+	req->skb = NULL;
+	brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
+
+}
+
+static void brcmf_usb_rx_complete(struct urb *urb)
+{
+	struct brcmf_usbreq  *req = (struct brcmf_usbreq *)urb->context;
+	struct brcmf_usbdev_info *devinfo = req->devinfo;
+	struct sk_buff *skb;
+	int ifidx = 0;
+
+	brcmf_usb_del_fromq(devinfo, req);
+	skb = req->skb;
+	req->skb = NULL;
+
+	if (urb->status == 0) {
+		devinfo->bus_pub.stats.rx_packets++;
+	} else {
+		devinfo->bus_pub.stats.rx_errors++;
+		dev_kfree_skb(skb);
+		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+		return;
+	}
+
+	if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) {
+		skb_put(skb, urb->actual_length);
+		if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
+			brcmf_dbg(ERROR, "rx protocol error\n");
+			brcmu_pkt_buf_free_skb(skb);
+			devinfo->bus_pub.bus->dstats.rx_errors++;
+		} else {
+			brcmf_rx_packet(devinfo->dev, ifidx, skb);
+			brcmf_usb_rx_refill(devinfo, req);
+		}
+	} else {
+		dev_kfree_skb(skb);
+	}
+	return;
+
+}
+
+static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
+				struct brcmf_usbreq  *req)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	if (!req || !devinfo)
+		return;
+
+	skb = dev_alloc_skb(devinfo->bus_pub.bus_mtu);
+	if (!skb) {
+		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+		return;
+	}
+	req->skb = skb;
+
+	usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe,
+			  skb->data, skb_tailroom(skb), brcmf_usb_rx_complete,
+			  req);
+	req->urb->transfer_flags |= URB_ZERO_PACKET;
+	req->devinfo = devinfo;
+
+	ret = usb_submit_urb(req->urb, GFP_ATOMIC);
+	if (ret == 0) {
+		brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
+	} else {
+		dev_kfree_skb(req->skb);
+		req->skb = NULL;
+		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+	}
+	return;
+}
+
+static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo)
+{
+	struct brcmf_usbreq *req;
+
+	if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+		brcmf_dbg(ERROR, "bus is not up\n");
+		return;
+	}
+	while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq)) != NULL)
+		brcmf_usb_rx_refill(devinfo, req);
+}
+
+static void
+brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
+{
+	struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus;
+	int old_state;
+
+
+	if (devinfo->bus_pub.state == state)
+		return;
+
+	old_state = devinfo->bus_pub.state;
+	brcmf_dbg(TRACE, "dbus state change from %d to to %d\n",
+		  old_state, state);
+
+	/* Don't update state if it's PnP firmware re-download */
+	if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */
+		devinfo->bus_pub.state = state;
+
+	if ((old_state  == BCMFMAC_USB_STATE_SLEEP)
+		&& (state == BCMFMAC_USB_STATE_UP)) {
+		brcmf_usb_rx_fill_all(devinfo);
+	}
+
+	/* update state of upper layer */
+	if (state == BCMFMAC_USB_STATE_DOWN) {
+		brcmf_dbg(INFO, "DBUS is down\n");
+		bcmf_bus->state = BRCMF_BUS_DOWN;
+	} else {
+		brcmf_dbg(INFO, "DBUS current state=%d\n", state);
+	}
+}
+
+static void
+brcmf_usb_intr_complete(struct urb *urb)
+{
+	struct brcmf_usbdev_info *devinfo =
+			(struct brcmf_usbdev_info *)urb->context;
+	bool killed;
+
+	if (devinfo == NULL)
+		return;
+
+	if (unlikely(urb->status)) {
+		if (devinfo->suspend_state ==
+			USBOS_SUSPEND_STATE_SUSPEND_PENDING)
+			killed = true;
+
+		if ((urb->status == -ENOENT && (!killed))
+			|| urb->status == -ESHUTDOWN ||
+			urb->status == -ENODEV) {
+			brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
+		}
+	}
+
+	if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) {
+		brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n");
+		return;
+	}
+
+	if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
+		usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
+}
+
+static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
+{
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+	struct brcmf_usbreq  *req;
+	int ret;
+
+	if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+		/* TODO: handle suspend/resume */
+		return -EIO;
+	}
+
+	req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq);
+	if (!req) {
+		brcmf_dbg(ERROR, "no req to send\n");
+		return -ENOMEM;
+	}
+	if (!req->urb) {
+		brcmf_dbg(ERROR, "no urb for req %p\n", req);
+		return -ENOBUFS;
+	}
+
+	req->skb = skb;
+	req->devinfo = devinfo;
+	usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
+			  skb->data, skb->len, brcmf_usb_tx_complete, req);
+	req->urb->transfer_flags |= URB_ZERO_PACKET;
+	ret = usb_submit_urb(req->urb, GFP_ATOMIC);
+	if (!ret) {
+		brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
+	} else {
+		req->skb = NULL;
+		brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
+	}
+
+	return ret;
+}
+
+
+static int brcmf_usb_up(struct device *dev)
+{
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+	u16 ifnum;
+
+	if (devinfo == NULL)
+		return -EINVAL;
+
+	if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
+		return 0;
+
+	/* If the USB/HSIC bus in sleep state, wake it up */
+	if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) {
+		if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
+			brcmf_dbg(ERROR, "Could not Resume the bus!\n");
+			return -EIO;
+		}
+	}
+	devinfo->activity = true;
+
+	/* Success, indicate devinfo is fully up */
+	brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_UP);
+
+	if (devinfo->intr_urb) {
+		int ret;
+
+		usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev,
+			devinfo->intr_pipe,
+			&devinfo->intr,
+			devinfo->intr_size,
+			(usb_complete_t)brcmf_usb_intr_complete,
+			devinfo,
+			devinfo->interval);
+
+		ret = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
+		if (ret) {
+			brcmf_dbg(ERROR, "USB_SUBMIT_URB failed with status %d\n",
+				  ret);
+			return -EINVAL;
+		}
+	}
+
+	if (devinfo->ctl_urb) {
+		devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);
+		devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0);
+
+		ifnum = IFDESC(devinfo->usbdev, CONTROL_IF).bInterfaceNumber;
+
+		/* CTL Write */
+		devinfo->ctl_write.bRequestType =
+			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+		devinfo->ctl_write.bRequest = 0;
+		devinfo->ctl_write.wValue = cpu_to_le16(0);
+		devinfo->ctl_write.wIndex = cpu_to_le16p(&ifnum);
+
+		/* CTL Read */
+		devinfo->ctl_read.bRequestType =
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+		devinfo->ctl_read.bRequest = 1;
+		devinfo->ctl_read.wValue = cpu_to_le16(0);
+		devinfo->ctl_read.wIndex = cpu_to_le16p(&ifnum);
+	}
+	brcmf_usb_rx_fill_all(devinfo);
+	return 0;
+}
+
+static void brcmf_usb_down(struct device *dev)
+{
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+	if (devinfo == NULL)
+		return;
+
+	brcmf_dbg(TRACE, "enter\n");
+	if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN)
+		return;
+
+	brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
+	if (devinfo->intr_urb)
+		usb_kill_urb(devinfo->intr_urb);
+
+	if (devinfo->ctl_urb)
+		usb_kill_urb(devinfo->ctl_urb);
+
+	if (devinfo->bulk_urb)
+		usb_kill_urb(devinfo->bulk_urb);
+	brcmf_usb_free_q(&devinfo->tx_postq, true);
+
+	brcmf_usb_free_q(&devinfo->rx_postq, true);
+}
+
+static int
+brcmf_usb_sync_wait(struct brcmf_usbdev_info *devinfo, u16 time)
+{
+	int ret;
+	int err = 0;
+	int ms = time;
+
+	ret = wait_event_interruptible_timeout(devinfo->wait,
+		devinfo->waitdone == true, (ms * HZ / 1000));
+
+	if ((devinfo->waitdone == false) || (devinfo->sync_urb_status)) {
+		brcmf_dbg(ERROR, "timeout(%d) or urb err=%d\n",
+			  ret, devinfo->sync_urb_status);
+		err = -EINVAL;
+	}
+	devinfo->waitdone = false;
+	return err;
+}
+
+static void
+brcmf_usb_sync_complete(struct urb *urb)
+{
+	struct brcmf_usbdev_info *devinfo =
+			(struct brcmf_usbdev_info *)urb->context;
+
+	devinfo->waitdone = true;
+	wake_up_interruptible(&devinfo->wait);
+	devinfo->sync_urb_status = urb->status;
+}
+
+static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
+			     void *buffer, int buflen)
+{
+	int ret = 0;
+	char *tmpbuf;
+	u16 size;
+
+	if ((!devinfo) || (devinfo->ctl_urb == NULL))
+		return false;
+
+	tmpbuf = kmalloc(buflen, GFP_ATOMIC);
+	if (!tmpbuf)
+		return false;
+
+	size = buflen;
+	devinfo->ctl_urb->transfer_buffer_length = size;
+
+	devinfo->ctl_read.wLength = cpu_to_le16p(&size);
+	devinfo->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR |
+		USB_RECIP_INTERFACE;
+	devinfo->ctl_read.bRequest = cmd;
+
+	usb_fill_control_urb(devinfo->ctl_urb,
+		devinfo->usbdev,
+		usb_rcvctrlpipe(devinfo->usbdev, 0),
+		(unsigned char *) &devinfo->ctl_read,
+		(void *) tmpbuf, size,
+		(usb_complete_t)brcmf_usb_sync_complete, devinfo);
+
+	ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+	if (ret < 0) {
+		brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+		kfree(tmpbuf);
+		return false;
+	}
+
+	ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT);
+	memcpy(buffer, tmpbuf, buflen);
+	kfree(tmpbuf);
+
+	return (ret == 0);
+}
+
+static bool
+brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo)
+{
+	struct bootrom_id_le id;
+	u32 chipid, chiprev;
+
+	brcmf_dbg(TRACE, "enter\n");
+
+	if (devinfo == NULL)
+		return false;
+
+	/* Check if firmware downloaded already by querying runtime ID */
+	id.chip = cpu_to_le32(0xDEAD);
+	brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
+		sizeof(struct bootrom_id_le));
+
+	chipid = le32_to_cpu(id.chip);
+	chiprev = le32_to_cpu(id.chiprev);
+
+	if ((chipid & 0x4300) == 0x4300)
+		brcmf_dbg(INFO, "chip %x rev 0x%x\n", chipid, chiprev);
+	else
+		brcmf_dbg(INFO, "chip %d rev 0x%x\n", chipid, chiprev);
+	if (chipid == BRCMF_POSTBOOT_ID) {
+		brcmf_dbg(INFO, "firmware already downloaded\n");
+		brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
+			sizeof(struct bootrom_id_le));
+		return false;
+	} else {
+		devinfo->bus_pub.attrib.devid = chipid;
+		devinfo->bus_pub.attrib.chiprev = chiprev;
+	}
+	return true;
+}
+
+static int
+brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
+{
+	struct bootrom_id_le id;
+	u16 wait = 0, wait_time;
+
+	brcmf_dbg(TRACE, "enter\n");
+
+	if (devinfo == NULL)
+		return -EINVAL;
+
+	/* Give dongle chance to boot */
+	wait_time = BRCMF_USB_DLIMAGE_SPINWAIT;
+	while (wait < BRCMF_USB_DLIMAGE_LIMIT) {
+		mdelay(wait_time);
+		wait += wait_time;
+		id.chip = cpu_to_le32(0xDEAD);       /* Get the ID */
+		brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
+			sizeof(struct bootrom_id_le));
+		if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
+			break;
+	}
+
+	if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) {
+		brcmf_dbg(INFO, "download done %d ms postboot chip 0x%x/rev 0x%x\n",
+			  wait, le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));
+
+		brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
+			sizeof(struct bootrom_id_le));
+
+		/* XXX this wait may not be necessary */
+		mdelay(BRCMF_USB_RESETCFG_SPINWAIT);
+		return 0;
+	} else {
+		brcmf_dbg(ERROR, "Cannot talk to Dongle. Firmware is not UP, %d ms\n",
+			  wait);
+		return -EINVAL;
+	}
+}
+
+
+static int
+brcmf_usb_dl_send_bulk(struct brcmf_usbdev_info *devinfo, void *buffer, int len)
+{
+	int ret;
+
+	if ((devinfo == NULL) || (devinfo->bulk_urb == NULL))
+		return -EINVAL;
+
+	/* Prepare the URB */
+	usb_fill_bulk_urb(devinfo->bulk_urb, devinfo->usbdev,
+			  devinfo->tx_pipe, buffer, len,
+			  (usb_complete_t)brcmf_usb_sync_complete, devinfo);
+
+	devinfo->bulk_urb->transfer_flags |= URB_ZERO_PACKET;
+
+	ret = usb_submit_urb(devinfo->bulk_urb, GFP_ATOMIC);
+	if (ret) {
+		brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+		return ret;
+	}
+	ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT);
+	return ret;
+}
+
+static int
+brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
+{
+	unsigned int sendlen, sent, dllen;
+	char *bulkchunk = NULL, *dlpos;
+	struct rdl_state_le state;
+	u32 rdlstate, rdlbytes;
+	int err = 0;
+	brcmf_dbg(TRACE, "fw %p, len %d\n", fw, fwlen);
+
+	bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);
+	if (bulkchunk == NULL) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	/* 1) Prepare USB boot loader for runtime image */
+	brcmf_usb_dl_cmd(devinfo, DL_START, &state,
+			 sizeof(struct rdl_state_le));
+
+	rdlstate = le32_to_cpu(state.state);
+	rdlbytes = le32_to_cpu(state.bytes);
+
+	/* 2) Check we are in the Waiting state */
+	if (rdlstate != DL_WAITING) {
+		brcmf_dbg(ERROR, "Failed to DL_START\n");
+		err = -EINVAL;
+		goto fail;
+	}
+	sent = 0;
+	dlpos = fw;
+	dllen = fwlen;
+
+	/* Get chip id and rev */
+	while (rdlbytes != dllen) {
+		/* Wait until the usb device reports it received all
+		 * the bytes we sent */
+		if ((rdlbytes == sent) && (rdlbytes != dllen)) {
+			if ((dllen-sent) < RDL_CHUNK)
+				sendlen = dllen-sent;
+			else
+				sendlen = RDL_CHUNK;
+
+			/* simply avoid having to send a ZLP by ensuring we
+			 * never have an even
+			 * multiple of 64
+			 */
+			if (!(sendlen % 64))
+				sendlen -= 4;
+
+			/* send data */
+			memcpy(bulkchunk, dlpos, sendlen);
+			if (brcmf_usb_dl_send_bulk(devinfo, bulkchunk,
+						   sendlen)) {
+				brcmf_dbg(ERROR, "send_bulk failed\n");
+				err = -EINVAL;
+				goto fail;
+			}
+
+			dlpos += sendlen;
+			sent += sendlen;
+		}
+		if (!brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
+				      sizeof(struct rdl_state_le))) {
+			brcmf_dbg(ERROR, "DL_GETSTATE Failed xxxx\n");
+			err = -EINVAL;
+			goto fail;
+		}
+
+		rdlstate = le32_to_cpu(state.state);
+		rdlbytes = le32_to_cpu(state.bytes);
+
+		/* restart if an error is reported */
+		if (rdlstate == DL_BAD_HDR || rdlstate == DL_BAD_CRC) {
+			brcmf_dbg(ERROR, "Bad Hdr or Bad CRC state %d\n",
+				  rdlstate);
+			err = -EINVAL;
+			goto fail;
+		}
+	}
+
+fail:
+	kfree(bulkchunk);
+	brcmf_dbg(TRACE, "err=%d\n", err);
+	return err;
+}
+
+static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
+{
+	int err;
+
+	brcmf_dbg(TRACE, "enter\n");
+
+	if (devinfo == NULL)
+		return -EINVAL;
+
+	if (devinfo->bus_pub.attrib.devid == 0xDEAD)
+		return -EINVAL;
+
+	err = brcmf_usb_dl_writeimage(devinfo, fw, len);
+	if (err == 0)
+		devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE;
+	else
+		devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING;
+	brcmf_dbg(TRACE, "exit: err=%d\n", err);
+
+	return err;
+}
+
+static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
+{
+	struct rdl_state_le state;
+
+	brcmf_dbg(TRACE, "enter\n");
+	if (!devinfo)
+		return -EINVAL;
+
+	if (devinfo->bus_pub.attrib.devid == 0xDEAD)
+		return -EINVAL;
+
+	/* Check we are runnable */
+	brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
+		sizeof(struct rdl_state_le));
+
+	/* Start the image */
+	if (state.state == cpu_to_le32(DL_RUNNABLE)) {
+		if (!brcmf_usb_dl_cmd(devinfo, DL_GO, &state,
+			sizeof(struct rdl_state_le)))
+			return -ENODEV;
+		if (brcmf_usb_resetcfg(devinfo))
+			return -ENODEV;
+		/* The Dongle may go for re-enumeration. */
+	} else {
+		brcmf_dbg(ERROR, "Dongle not runnable\n");
+		return -EINVAL;
+	}
+	brcmf_dbg(TRACE, "exit\n");
+	return 0;
+}
+
+static bool brcmf_usb_chip_support(int chipid, int chiprev)
+{
+	switch(chipid) {
+	case 43235:
+	case 43236:
+	case 43238:
+		return (chiprev == 3);
+	default:
+		break;
+	}
+	return false;
+}
+
+static int
+brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
+{
+	struct brcmf_usb_attrib *attr;
+	int err;
+
+	brcmf_dbg(TRACE, "enter\n");
+	if (devinfo == NULL)
+		return -ENODEV;
+
+	attr = &devinfo->bus_pub.attrib;
+
+	if (!brcmf_usb_chip_support(attr->devid, attr->chiprev)) {
+		brcmf_dbg(ERROR, "unsupported chip %d rev %d\n",
+			  attr->devid, attr->chiprev);
+		return -EINVAL;
+	}
+
+	if (!devinfo->image) {
+		brcmf_dbg(ERROR, "No firmware!\n");
+		return -ENOENT;
+	}
+
+	err = brcmf_usb_dlstart(devinfo,
+		devinfo->image, devinfo->image_len);
+	if (err == 0)
+		err = brcmf_usb_dlrun(devinfo);
+	return err;
+}
+
+
+static void brcmf_usb_detach(const struct brcmf_usbdev *bus_pub)
+{
+	struct brcmf_usbdev_info *devinfo =
+		(struct brcmf_usbdev_info *)bus_pub;
+
+	brcmf_dbg(TRACE, "devinfo %p\n", devinfo);
+
+	/* store the image globally */
+	g_image.data = devinfo->image;
+	g_image.len = devinfo->image_len;
+
+	/* free the URBS */
+	brcmf_usb_free_q(&devinfo->rx_freeq, false);
+	brcmf_usb_free_q(&devinfo->tx_freeq, false);
+
+	usb_free_urb(devinfo->intr_urb);
+	usb_free_urb(devinfo->ctl_urb);
+	usb_free_urb(devinfo->bulk_urb);
+
+	kfree(devinfo->tx_reqs);
+	kfree(devinfo->rx_reqs);
+	kfree(devinfo);
+}
+
+#define TRX_MAGIC       0x30524448      /* "HDR0" */
+#define TRX_VERSION     1               /* Version 1 */
+#define TRX_MAX_LEN     0x3B0000        /* Max length */
+#define TRX_NO_HEADER   1               /* Do not write TRX header */
+#define TRX_MAX_OFFSET  3               /* Max number of individual files */
+#define TRX_UNCOMP_IMAGE        0x20    /* Trx contains uncompressed image */
+
+struct trx_header_le {
+	__le32 magic;		/* "HDR0" */
+	__le32 len;		/* Length of file including header */
+	__le32 crc32;		/* CRC from flag_version to end of file */
+	__le32 flag_version;	/* 0:15 flags, 16:31 version */
+	__le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of
+					 * header */
+};
+
+static int check_file(const u8 *headers)
+{
+	struct trx_header_le *trx;
+	int actual_len = -1;
+
+	/* Extract trx header */
+	trx = (struct trx_header_le *) headers;
+	if (trx->magic != cpu_to_le32(TRX_MAGIC))
+		return -1;
+
+	headers += sizeof(struct trx_header_le);
+
+	if (le32_to_cpu(trx->flag_version) & TRX_UNCOMP_IMAGE) {
+		actual_len = le32_to_cpu(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]);
+		return actual_len + sizeof(struct trx_header_le);
+	}
+	return -1;
+}
+
+static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
+{
+	s8 *fwname;
+	const struct firmware *fw;
+	int err;
+
+	devinfo->image = g_image.data;
+	devinfo->image_len = g_image.len;
+
+	/*
+	 * if we have an image we can leave here.
+	 */
+	if (devinfo->image)
+		return 0;
+
+	fwname = BRCMF_USB_43236_FW_NAME;
+
+	err = request_firmware(&fw, fwname, devinfo->dev);
+	if (!fw) {
+		brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname);
+		return err;
+	}
+	if (check_file(fw->data) < 0) {
+		brcmf_dbg(ERROR, "invalid firmware %s\n", fwname);
+		return -EINVAL;
+	}
+
+	devinfo->image = kmalloc(fw->size, GFP_ATOMIC); /* plus nvram */
+	if (!devinfo->image)
+		return -ENOMEM;
+
+	memcpy(devinfo->image, fw->data, fw->size);
+	devinfo->image_len = fw->size;
+
+	release_firmware(fw);
+	return 0;
+}
+
+
+static
+struct brcmf_usbdev *brcmf_usb_attach(int nrxq, int ntxq, struct device *dev)
+{
+	struct brcmf_usbdev_info *devinfo;
+
+	devinfo = kzalloc(sizeof(struct brcmf_usbdev_info), GFP_ATOMIC);
+	if (devinfo == NULL)
+		return NULL;
+
+	devinfo->bus_pub.nrxq = nrxq;
+	devinfo->rx_low_watermark = nrxq / 2;
+	devinfo->bus_pub.devinfo = devinfo;
+	devinfo->bus_pub.ntxq = ntxq;
+
+	/* flow control when too many tx urbs posted */
+	devinfo->tx_low_watermark = ntxq / 4;
+	devinfo->tx_high_watermark = devinfo->tx_low_watermark * 3;
+	devinfo->dev = dev;
+	devinfo->usbdev = usbdev_probe_info.usb;
+	devinfo->tx_pipe = usbdev_probe_info.tx_pipe;
+	devinfo->rx_pipe = usbdev_probe_info.rx_pipe;
+	devinfo->rx_pipe2 = usbdev_probe_info.rx_pipe2;
+	devinfo->intr_pipe = usbdev_probe_info.intr_pipe;
+
+	devinfo->interval = usbdev_probe_info.interval;
+	devinfo->intr_size = usbdev_probe_info.intr_size;
+
+	memcpy(&devinfo->probe_info, &usbdev_probe_info,
+		sizeof(struct brcmf_usb_probe_info));
+	devinfo->bus_pub.bus_mtu = BRCMF_USB_MAX_PKT_SIZE;
+
+	/* Initialize other structure content */
+	init_waitqueue_head(&devinfo->ioctl_resp_wait);
+
+	/* Initialize the spinlocks */
+	spin_lock_init(&devinfo->qlock);
+
+	INIT_LIST_HEAD(&devinfo->rx_freeq);
+	INIT_LIST_HEAD(&devinfo->rx_postq);
+
+	INIT_LIST_HEAD(&devinfo->tx_freeq);
+	INIT_LIST_HEAD(&devinfo->tx_postq);
+
+	devinfo->rx_reqs = brcmf_usbdev_qinit(&devinfo->rx_freeq, nrxq);
+	if (!devinfo->rx_reqs)
+		goto error;
+
+	devinfo->tx_reqs = brcmf_usbdev_qinit(&devinfo->tx_freeq, ntxq);
+	if (!devinfo->tx_reqs)
+		goto error;
+
+	devinfo->intr_urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!devinfo->intr_urb) {
+		brcmf_dbg(ERROR, "usb_alloc_urb (intr) failed\n");
+		goto error;
+	}
+	devinfo->ctl_urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!devinfo->ctl_urb) {
+		brcmf_dbg(ERROR, "usb_alloc_urb (ctl) failed\n");
+		goto error;
+	}
+	devinfo->rxctl_deferrespok = 0;
+
+	devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!devinfo->bulk_urb) {
+		brcmf_dbg(ERROR, "usb_alloc_urb (bulk) failed\n");
+		goto error;
+	}
+
+	init_waitqueue_head(&devinfo->wait);
+	if (!brcmf_usb_dlneeded(devinfo))
+		return &devinfo->bus_pub;
+
+	brcmf_dbg(TRACE, "start fw downloading\n");
+	if (brcmf_usb_get_fw(devinfo))
+		goto error;
+
+	if (brcmf_usb_fw_download(devinfo))
+		goto error;
+
+	return &devinfo->bus_pub;
+
+error:
+	brcmf_dbg(ERROR, "failed!\n");
+	brcmf_usb_detach(&devinfo->bus_pub);
+	return NULL;
+}
+
+static int brcmf_usb_probe_cb(struct device *dev, const char *desc,
+				u32 bustype, u32 hdrlen)
+{
+	struct brcmf_bus *bus = NULL;
+	struct brcmf_usbdev *bus_pub = NULL;
+	int ret;
+
+
+	bus_pub = brcmf_usb_attach(BRCMF_USB_NRXQ, BRCMF_USB_NTXQ, dev);
+	if (!bus_pub) {
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
+	if (!bus) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	bus_pub->bus = bus;
+	bus->brcmf_bus_txdata = brcmf_usb_tx;
+	bus->brcmf_bus_init = brcmf_usb_up;
+	bus->brcmf_bus_stop = brcmf_usb_down;
+	bus->brcmf_bus_txctl = brcmf_usb_tx_ctlpkt;
+	bus->brcmf_bus_rxctl = brcmf_usb_rx_ctlpkt;
+	bus->type = bustype;
+	bus->bus_priv.usb = bus_pub;
+	dev_set_drvdata(dev, bus);
+
+	/* Attach to the common driver interface */
+	ret = brcmf_attach(hdrlen, dev);
+	if (ret) {
+		brcmf_dbg(ERROR, "dhd_attach failed\n");
+		goto fail;
+	}
+
+	ret = brcmf_bus_start(dev);
+	if (ret == -ENOLINK) {
+		brcmf_dbg(ERROR, "dongle is not responding\n");
+		brcmf_detach(dev);
+		goto fail;
+	}
+
+	/* add interface and open for business */
+	ret = brcmf_add_if(dev, 0, "wlan%d", NULL);
+	if (ret) {
+		brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
+		brcmf_detach(dev);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	/* Release resources in reverse order */
+	if (bus_pub)
+		brcmf_usb_detach(bus_pub);
+	kfree(bus);
+	return ret;
+}
+
+static void
+brcmf_usb_disconnect_cb(struct brcmf_usbdev *bus_pub)
+{
+	if (!bus_pub)
+		return;
+	brcmf_dbg(TRACE, "enter: bus_pub %p\n", bus_pub);
+
+	brcmf_detach(bus_pub->devinfo->dev);
+	kfree(bus_pub->bus);
+	brcmf_usb_detach(bus_pub);
+
+}
+
+static int
+brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	int ep;
+	struct usb_endpoint_descriptor *endpoint;
+	int ret = 0;
+	struct usb_device *usb = interface_to_usbdev(intf);
+	int num_of_eps;
+	u8 endpoint_num;
+
+	brcmf_dbg(TRACE, "enter\n");
+
+	usbdev_probe_info.usb = usb;
+	usbdev_probe_info.intf = intf;
+
+	if (id != NULL) {
+		usbdev_probe_info.vid = id->idVendor;
+		usbdev_probe_info.pid = id->idProduct;
+	}
+
+	usb_set_intfdata(intf, &usbdev_probe_info);
+
+	/* Check that the device supports only one configuration */
+	if (usb->descriptor.bNumConfigurations != 1) {
+		ret = -1;
+		goto fail;
+	}
+
+	if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
+		ret = -1;
+		goto fail;
+	}
+
+	/*
+	 * Only the BDC interface configuration is supported:
+	 *	Device class: USB_CLASS_VENDOR_SPEC
+	 *	if0 class: USB_CLASS_VENDOR_SPEC
+	 *	if0/ep0: control
+	 *	if0/ep1: bulk in
+	 *	if0/ep2: bulk out (ok if swapped with bulk in)
+	 */
+	if (CONFIGDESC(usb)->bNumInterfaces != 1) {
+		ret = -1;
+		goto fail;
+	}
+
+	/* Check interface */
+	if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+	    IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 ||
+	    IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) {
+		brcmf_dbg(ERROR, "invalid control interface: class %d, subclass %d, proto %d\n",
+			  IFDESC(usb, CONTROL_IF).bInterfaceClass,
+			  IFDESC(usb, CONTROL_IF).bInterfaceSubClass,
+			  IFDESC(usb, CONTROL_IF).bInterfaceProtocol);
+		ret = -1;
+		goto fail;
+	}
+
+	/* Check control endpoint */
+	endpoint = &IFEPDESC(usb, CONTROL_IF, 0);
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+		!= USB_ENDPOINT_XFER_INT) {
+		brcmf_dbg(ERROR, "invalid control endpoint %d\n",
+			  endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+		ret = -1;
+		goto fail;
+	}
+
+	endpoint_num = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	usbdev_probe_info.intr_pipe = usb_rcvintpipe(usb, endpoint_num);
+
+	usbdev_probe_info.rx_pipe = 0;
+	usbdev_probe_info.rx_pipe2 = 0;
+	usbdev_probe_info.tx_pipe = 0;
+	num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1;
+
+	/* Check data endpoints and get pipes */
+	for (ep = 1; ep <= num_of_eps; ep++) {
+		endpoint = &IFEPDESC(usb, BULK_IF, ep);
+		if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+		    USB_ENDPOINT_XFER_BULK) {
+			brcmf_dbg(ERROR, "invalid data endpoint %d\n", ep);
+			ret = -1;
+			goto fail;
+		}
+
+		endpoint_num = endpoint->bEndpointAddress &
+			       USB_ENDPOINT_NUMBER_MASK;
+		if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+			== USB_DIR_IN) {
+			if (!usbdev_probe_info.rx_pipe) {
+				usbdev_probe_info.rx_pipe =
+					usb_rcvbulkpipe(usb, endpoint_num);
+			} else {
+				usbdev_probe_info.rx_pipe2 =
+					usb_rcvbulkpipe(usb, endpoint_num);
+			}
+		} else {
+			usbdev_probe_info.tx_pipe =
+					usb_sndbulkpipe(usb, endpoint_num);
+		}
+	}
+
+	/* Allocate interrupt URB and data buffer */
+	/* RNDIS says 8-byte intr, our old drivers used 4-byte */
+	if (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == cpu_to_le16(16))
+		usbdev_probe_info.intr_size = 8;
+	else
+		usbdev_probe_info.intr_size = 4;
+
+	usbdev_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;
+
+	usbdev_probe_info.device_speed = usb->speed;
+	if (usb->speed == USB_SPEED_HIGH)
+		brcmf_dbg(INFO, "Broadcom high speed USB wireless device detected\n");
+	else
+		brcmf_dbg(INFO, "Broadcom full speed USB wireless device detected\n");
+
+	ret = brcmf_usb_probe_cb(&usb->dev, "", USB_BUS, 0);
+	if (ret)
+		goto fail;
+
+	/* Success */
+	return 0;
+
+fail:
+	brcmf_dbg(ERROR, "failed with errno %d\n", ret);
+	usb_set_intfdata(intf, NULL);
+	return ret;
+
+}
+
+static void
+brcmf_usb_disconnect(struct usb_interface *intf)
+{
+	struct usb_device *usb = interface_to_usbdev(intf);
+
+	brcmf_dbg(TRACE, "enter\n");
+	brcmf_usb_disconnect_cb(brcmf_usb_get_buspub(&usb->dev));
+	usb_set_intfdata(intf, NULL);
+}
+
+/*
+ *	only need to signal the bus being down and update the suspend state.
+ */
+static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
+{
+	struct usb_device *usb = interface_to_usbdev(intf);
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+
+	brcmf_dbg(TRACE, "enter\n");
+	devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN;
+	devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;
+	return 0;
+}
+
+/*
+ *	mark suspend state active and crank up the bus.
+ */
+static int brcmf_usb_resume(struct usb_interface *intf)
+{
+	struct usb_device *usb = interface_to_usbdev(intf);
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+
+	brcmf_dbg(TRACE, "enter\n");
+	devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
+	brcmf_bus_start(&usb->dev);
+	return 0;
+}
+
+#define BRCMF_USB_VENDOR_ID_BROADCOM	0x0a5c
+#define BRCMF_USB_DEVICE_ID_43236	0xbd17
+#define BRCMF_USB_DEVICE_ID_BCMFW	0x0bdc
+
+static struct usb_device_id brcmf_usb_devid_table[] = {
+	{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) },
+	/* special entry for device with firmware loaded and running */
+	{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
+MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
+
+/* TODO: suspend and resume entries */
+static struct usb_driver brcmf_usbdrvr = {
+	.name = KBUILD_MODNAME,
+	.probe = brcmf_usb_probe,
+	.disconnect = brcmf_usb_disconnect,
+	.id_table = brcmf_usb_devid_table,
+	.suspend = brcmf_usb_suspend,
+	.resume = brcmf_usb_resume,
+	.supports_autosuspend = 1
+};
+
+void brcmf_usb_exit(void)
+{
+	usb_deregister(&brcmf_usbdrvr);
+	kfree(g_image.data);
+	g_image.data = NULL;
+	g_image.len = 0;
+}
+
+int brcmf_usb_init(void)
+{
+	return usb_register(&brcmf_usbdrvr);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.h b/drivers/net/wireless/brcm80211/brcmfmac/usb.h
new file mode 100644
index 0000000..b31da7b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef BRCMFMAC_USB_H
+#define BRCMFMAC_USB_H
+
+enum brcmf_usb_state {
+	BCMFMAC_USB_STATE_DL_PENDING,
+	BCMFMAC_USB_STATE_DL_DONE,
+	BCMFMAC_USB_STATE_UP,
+	BCMFMAC_USB_STATE_DOWN,
+	BCMFMAC_USB_STATE_PNP_FWDL,
+	BCMFMAC_USB_STATE_DISCONNECT,
+	BCMFMAC_USB_STATE_SLEEP
+};
+
+enum brcmf_usb_pnp_state {
+	BCMFMAC_USB_PNP_DISCONNECT,
+	BCMFMAC_USB_PNP_SLEEP,
+	BCMFMAC_USB_PNP_RESUME,
+};
+
+struct brcmf_stats {
+	u32 tx_errors;
+	u32 tx_packets;
+	u32 tx_multicast;
+	u32 tx_ctlpkts;
+	u32 tx_ctlerrs;
+	u32 tx_dropped;
+	u32 tx_flushed;
+	u32 rx_errors;
+	u32 rx_packets;
+	u32 rx_multicast;
+	u32 rx_ctlpkts;
+	u32 rx_ctlerrs;
+	u32 rx_dropped;
+	u32 rx_flushed;
+
+};
+
+struct brcmf_usb_attrib {
+	int bustype;
+	int vid;
+	int pid;
+	int devid;
+	int chiprev; /* chip revsion number */
+	int mtu;
+	int nchan; /* Data Channels */
+	int has_2nd_bulk_in_ep;
+};
+
+struct brcmf_usbdev_info;
+
+struct brcmf_usbdev {
+	struct brcmf_bus *bus;
+	struct brcmf_usbdev_info *devinfo;
+	enum brcmf_usb_state state;
+	struct brcmf_stats stats;
+	int ntxq, nrxq, rxsize;
+	u32 bus_mtu;
+	struct brcmf_usb_attrib attrib;
+};
+
+/* IO Request Block (IRB) */
+struct brcmf_usbreq {
+	struct list_head list;
+	struct brcmf_usbdev_info *devinfo;
+	struct urb *urb;
+	struct sk_buff  *skb;
+};
+
+#endif /* BRCMFMAC_USB_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h
new file mode 100644
index 0000000..0a35c51
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _USB_RDL_H
+#define _USB_RDL_H
+
+/* Control messages: bRequest values */
+#define DL_GETSTATE	0	/* returns the rdl_state_t struct */
+#define DL_CHECK_CRC	1	/* currently unused */
+#define DL_GO		2	/* execute downloaded image */
+#define DL_START	3	/* initialize dl state */
+#define DL_REBOOT	4	/* reboot the device in 2 seconds */
+#define DL_GETVER	5	/* returns the bootrom_id_t struct */
+#define DL_GO_PROTECTED	6	/* execute the downloaded code and set reset
+				 * event to occur in 2 seconds.  It is the
+				 * responsibility of the downloaded code to
+				 * clear this event
+				 */
+#define DL_EXEC		7	/* jump to a supplied address */
+#define DL_RESETCFG	8	/* To support single enum on dongle
+				 * - Not used by bootloader
+				 */
+#define DL_DEFER_RESP_OK 9	/* Potentially defer the response to setup
+				 * if resp unavailable
+				 */
+
+/* states */
+#define DL_WAITING	0	/* waiting to rx first pkt */
+#define DL_READY	1	/* hdr was good, waiting for more of the
+				 * compressed image */
+#define DL_BAD_HDR	2	/* hdr was corrupted */
+#define DL_BAD_CRC	3	/* compressed image was corrupted */
+#define DL_RUNNABLE	4	/* download was successful,waiting for go cmd */
+#define DL_START_FAIL	5	/* failed to initialize correctly */
+#define DL_NVRAM_TOOBIG	6	/* host specified nvram data exceeds DL_NVRAM
+				 * value */
+#define DL_IMAGE_TOOBIG	7	/* download image too big (exceeds DATA_START
+				 *  for rdl) */
+
+struct rdl_state_le {
+	__le32 state;
+	__le32 bytes;
+};
+
+struct bootrom_id_le {
+	__le32 chip;	/* Chip id */
+	__le32 chiprev;	/* Chip rev */
+	__le32 ramsize;	/* Size of  RAM */
+	__le32 remapbase;	/* Current remap base address */
+	__le32 boardtype;	/* Type of board */
+	__le32 boardrev;	/* Board revision */
+};
+
+#define RDL_CHUNK	1500  /* size of each dl transfer */
+
+#define TRX_OFFSETS_DLFWLEN_IDX	0
+#define TRX_OFFSETS_JUMPTO_IDX	1
+#define TRX_OFFSETS_NVM_LEN_IDX	2
+
+#define TRX_OFFSETS_DLBASE_IDX  0
+
+#endif  /* _USB_RDL_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 74c95a5..15d7f00 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -1376,7 +1376,7 @@
 	memset(&join_params, 0, sizeof(join_params));
 	join_params_size = sizeof(join_params.ssid_le);
 
-	ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len);
+	ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), (u32)sme->ssid_len);
 	memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len);
 	memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len);
 	join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
@@ -3297,7 +3297,9 @@
 }
 
 /*
-** push event to tail of the queue
+*	push event to tail of the queue
+*
+*	remark: this function may not sleep as it is called in atomic context.
 */
 
 static s32
@@ -3306,17 +3308,18 @@
 {
 	struct brcmf_cfg80211_event_q *e;
 	s32 err = 0;
+	ulong flags;
 
-	e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL);
+	e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_ATOMIC);
 	if (!e)
 		return -ENOMEM;
 
 	e->etype = event;
 	memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
 
-	spin_lock_irq(&cfg_priv->evt_q_lock);
+	spin_lock_irqsave(&cfg_priv->evt_q_lock, flags);
 	list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list);
-	spin_unlock_irq(&cfg_priv->evt_q_lock);
+	spin_unlock_irqrestore(&cfg_priv->evt_q_lock, flags);
 
 	return err;
 }
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index c842797..fec0f10 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -1136,8 +1136,8 @@
 	hw = bcma_get_drvdata(pdev);
 	wl = hw->priv;
 	if (!wl) {
-		wiphy_err(wl->wiphy,
-			  "brcms_suspend: bcma_get_drvdata failed\n");
+		pr_err("%s: %s: no driver private struct!\n", KBUILD_MODNAME,
+		       __func__);
 		return -ENODEV;
 	}
 
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 90331dd..231ddf4 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -2901,7 +2901,6 @@
 		objoff += 2;
 
 	return bcma_read16(core, objoff);
-;
 }
 
 static void
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index 62eedd8..3909574 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -17824,8 +17824,6 @@
 	if (pi->sh->sromrev < 4) {
 		idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
 		idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
-		target_pwr_qtrdbm[0] = 13 * 4;
-		target_pwr_qtrdbm[1] = 13 * 4;
 		a1[0] = -424;
 		a1[1] = -424;
 		b0[0] = 5612;
@@ -17839,10 +17837,6 @@
 		case WL_CHAN_FREQ_RANGE_2G:
 			idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
 			idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
-			target_pwr_qtrdbm[0] =
-				pi->nphy_pwrctrl_info[0].max_pwr_2g;
-			target_pwr_qtrdbm[1] =
-				pi->nphy_pwrctrl_info[1].max_pwr_2g;
 			a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_a1;
 			a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_a1;
 			b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b0;
@@ -17853,10 +17847,6 @@
 		case WL_CHAN_FREQ_RANGE_5GL:
 			idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
 			idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
-			target_pwr_qtrdbm[0] =
-				pi->nphy_pwrctrl_info[0].max_pwr_5gl;
-			target_pwr_qtrdbm[1] =
-				pi->nphy_pwrctrl_info[1].max_pwr_5gl;
 			a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1;
 			a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1;
 			b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0;
@@ -17867,10 +17857,6 @@
 		case WL_CHAN_FREQ_RANGE_5GM:
 			idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
 			idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
-			target_pwr_qtrdbm[0] =
-				pi->nphy_pwrctrl_info[0].max_pwr_5gm;
-			target_pwr_qtrdbm[1] =
-				pi->nphy_pwrctrl_info[1].max_pwr_5gm;
 			a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_a1;
 			a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_a1;
 			b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b0;
@@ -17881,10 +17867,6 @@
 		case WL_CHAN_FREQ_RANGE_5GH:
 			idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
 			idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
-			target_pwr_qtrdbm[0] =
-				pi->nphy_pwrctrl_info[0].max_pwr_5gh;
-			target_pwr_qtrdbm[1] =
-				pi->nphy_pwrctrl_info[1].max_pwr_5gh;
 			a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1;
 			a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1;
 			b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0;
@@ -17895,8 +17877,6 @@
 		default:
 			idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
 			idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
-			target_pwr_qtrdbm[0] = 13 * 4;
-			target_pwr_qtrdbm[1] = 13 * 4;
 			a1[0] = -424;
 			a1[1] = -424;
 			b0[0] = 5612;
@@ -17907,6 +17887,7 @@
 		}
 	}
 
+	/* use the provided transmit power */
 	target_pwr_qtrdbm[0] = (s8) pi->tx_power_max;
 	target_pwr_qtrdbm[1] = (s8) pi->tx_power_max;
 
@@ -19989,12 +19970,11 @@
 		switch (pi->pubpi.radiorev) {
 		case 5:
 
-			if (pi->pubpi.radiover == 0x0)
+			if (NREV_IS(pi->pubpi.phy_rev, 8))
 				regs_2057_ptr = regs_2057_rev5;
-			else if (pi->pubpi.radiover == 0x1)
+			else if (NREV_IS(pi->pubpi.phy_rev, 9))
 				regs_2057_ptr = regs_2057_rev5v1;
-			else
-				break;
+			break;
 
 		case 7:
 
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c
index 5637436..b96f4b9 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/srom.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.c
@@ -621,7 +621,7 @@
 /*
  * convert binary srom data into linked list of srom variable items.
  */
-static void
+static int
 _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
 {
 	struct brcms_srom_list_head *entry;
@@ -638,6 +638,9 @@
 
 	/* first store the srom revision */
 	entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
 	entry->varid = BRCMS_SROM_REV;
 	entry->var_type = BRCMS_SROM_UNUMBER;
 	entry->uval = sromrev;
@@ -715,6 +718,8 @@
 
 		entry = kzalloc(sizeof(struct brcms_srom_list_head) +
 				extra_space, GFP_KERNEL);
+		if (!entry)
+			return -ENOMEM;
 		entry->varid = id;
 		entry->var_type = type;
 		if (flags & SRFL_ETHADDR) {
@@ -754,6 +759,8 @@
 			entry =
 			    kzalloc(sizeof(struct brcms_srom_list_head),
 				    GFP_KERNEL);
+			if (!entry)
+				return -ENOMEM;
 			entry->varid = srv->varid+p;
 			entry->var_type = BRCMS_SROM_UNUMBER;
 			entry->uval = val;
@@ -761,6 +768,7 @@
 		}
 		pb += psz;
 	}
+	return 0;
 }
 
 /*
@@ -906,7 +914,9 @@
 		INIT_LIST_HEAD(&sii->var_list);
 
 		/* parse SROM into name=value pairs. */
-		_initvars_srom_pci(sromrev, srom, &sii->var_list);
+		err = _initvars_srom_pci(sromrev, srom, &sii->var_list);
+		if (err)
+			srom_free_vars(sih);
 	}
 
 errout:
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index e847737..5fd56ad 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -309,13 +309,6 @@
 
 #define FREQ_COUNT	ARRAY_SIZE(ipw2100_frequencies)
 
-static const long ipw2100_rates_11b[] = {
-	1000000,
-	2000000,
-	5500000,
-	11000000
-};
-
 static struct ieee80211_rate ipw2100_bg_rates[] = {
 	{ .bitrate = 10 },
 	{ .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
@@ -323,7 +316,7 @@
 	{ .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
 };
 
-#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
+#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
 
 /* Pre-decl until we get the code solid and then we can clean it up */
 static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
@@ -6893,7 +6886,7 @@
 	range->num_bitrates = RATE_COUNT;
 
 	for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
-		range->bitrate[i] = ipw2100_rates_11b[i];
+		range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
 	}
 
 	range->min_rts = MIN_RTS_THRESHOLD;
@@ -8105,61 +8098,41 @@
 #endif				/* CONFIG_IPW2100_MONITOR */
 
 static iw_handler ipw2100_wx_handlers[] = {
-	NULL,			/* SIOCSIWCOMMIT */
-	ipw2100_wx_get_name,	/* SIOCGIWNAME */
-	NULL,			/* SIOCSIWNWID */
-	NULL,			/* SIOCGIWNWID */
-	ipw2100_wx_set_freq,	/* SIOCSIWFREQ */
-	ipw2100_wx_get_freq,	/* SIOCGIWFREQ */
-	ipw2100_wx_set_mode,	/* SIOCSIWMODE */
-	ipw2100_wx_get_mode,	/* SIOCGIWMODE */
-	NULL,			/* SIOCSIWSENS */
-	NULL,			/* SIOCGIWSENS */
-	NULL,			/* SIOCSIWRANGE */
-	ipw2100_wx_get_range,	/* SIOCGIWRANGE */
-	NULL,			/* SIOCSIWPRIV */
-	NULL,			/* SIOCGIWPRIV */
-	NULL,			/* SIOCSIWSTATS */
-	NULL,			/* SIOCGIWSTATS */
-	NULL,			/* SIOCSIWSPY */
-	NULL,			/* SIOCGIWSPY */
-	NULL,			/* SIOCGIWTHRSPY */
-	NULL,			/* SIOCWIWTHRSPY */
-	ipw2100_wx_set_wap,	/* SIOCSIWAP */
-	ipw2100_wx_get_wap,	/* SIOCGIWAP */
-	ipw2100_wx_set_mlme,	/* SIOCSIWMLME */
-	NULL,			/* SIOCGIWAPLIST -- deprecated */
-	ipw2100_wx_set_scan,	/* SIOCSIWSCAN */
-	ipw2100_wx_get_scan,	/* SIOCGIWSCAN */
-	ipw2100_wx_set_essid,	/* SIOCSIWESSID */
-	ipw2100_wx_get_essid,	/* SIOCGIWESSID */
-	ipw2100_wx_set_nick,	/* SIOCSIWNICKN */
-	ipw2100_wx_get_nick,	/* SIOCGIWNICKN */
-	NULL,			/* -- hole -- */
-	NULL,			/* -- hole -- */
-	ipw2100_wx_set_rate,	/* SIOCSIWRATE */
-	ipw2100_wx_get_rate,	/* SIOCGIWRATE */
-	ipw2100_wx_set_rts,	/* SIOCSIWRTS */
-	ipw2100_wx_get_rts,	/* SIOCGIWRTS */
-	ipw2100_wx_set_frag,	/* SIOCSIWFRAG */
-	ipw2100_wx_get_frag,	/* SIOCGIWFRAG */
-	ipw2100_wx_set_txpow,	/* SIOCSIWTXPOW */
-	ipw2100_wx_get_txpow,	/* SIOCGIWTXPOW */
-	ipw2100_wx_set_retry,	/* SIOCSIWRETRY */
-	ipw2100_wx_get_retry,	/* SIOCGIWRETRY */
-	ipw2100_wx_set_encode,	/* SIOCSIWENCODE */
-	ipw2100_wx_get_encode,	/* SIOCGIWENCODE */
-	ipw2100_wx_set_power,	/* SIOCSIWPOWER */
-	ipw2100_wx_get_power,	/* SIOCGIWPOWER */
-	NULL,			/* -- hole -- */
-	NULL,			/* -- hole -- */
-	ipw2100_wx_set_genie,	/* SIOCSIWGENIE */
-	ipw2100_wx_get_genie,	/* SIOCGIWGENIE */
-	ipw2100_wx_set_auth,	/* SIOCSIWAUTH */
-	ipw2100_wx_get_auth,	/* SIOCGIWAUTH */
-	ipw2100_wx_set_encodeext,	/* SIOCSIWENCODEEXT */
-	ipw2100_wx_get_encodeext,	/* SIOCGIWENCODEEXT */
-	NULL,			/* SIOCSIWPMKSA */
+	IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
+	IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
+	IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
+	IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
+	IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
+	IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
+	IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
+	IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
+	IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
+	IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
+	IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
+	IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
+	IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
+	IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
+	IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
+	IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
+	IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
+	IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
+	IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
+	IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
+	IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
+	IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
+	IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
+	IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
+	IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
+	IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
+	IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
+	IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
+	IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
+	IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
+	IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
+	IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
+	IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
+	IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
+	IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
 };
 
 #define IPW2100_PRIV_SET_MONITOR	SIOCIWFIRSTPRIV
diff --git a/drivers/net/wireless/iwlegacy/3945-debug.c b/drivers/net/wireless/iwlegacy/3945-debug.c
index 5e1a19f..f767dd1 100644
--- a/drivers/net/wireless/iwlegacy/3945-debug.c
+++ b/drivers/net/wireless/iwlegacy/3945-debug.c
@@ -503,3 +503,9 @@
 	kfree(buf);
 	return ret;
 }
+
+const struct il_debugfs_ops il3945_debugfs_ops = {
+	.rx_stats_read = il3945_ucode_rx_stats_read,
+	.tx_stats_read = il3945_ucode_tx_stats_read,
+	.general_stats_read = il3945_ucode_general_stats_read,
+};
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index aa8f5c0..0ccc934 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -573,7 +573,6 @@
 	len = (u16) skb->len;
 	tx_cmd->len = cpu_to_le16(len);
 
-	il_dbg_log_tx_data_frame(il, len, hdr);
 	il_update_stats(il, true, fc, len);
 	tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
 	tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
@@ -616,7 +615,7 @@
 
 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 	 * first entry */
-	il->ops->lib->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
+	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
 
 	/* Set up TFD's 2nd entry to point directly to remainder of skb,
 	 * if any (802.11 null frames have no payload). */
@@ -625,8 +624,8 @@
 		phys_addr =
 		    pci_map_single(il->pci_dev, skb->data + hdr_len, len,
 				   PCI_DMA_TODEVICE);
-		il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
-						    U32_PAD(len));
+		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
+					       U32_PAD(len));
 	}
 
 	/* Tell device the write idx *just past* this latest filled TFD */
@@ -810,16 +809,16 @@
 	_il_wr(il, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
 	if (flags & HW_CARD_DISABLED)
-		set_bit(S_RF_KILL_HW, &il->status);
+		set_bit(S_RFKILL, &il->status);
 	else
-		clear_bit(S_RF_KILL_HW, &il->status);
+		clear_bit(S_RFKILL, &il->status);
 
 	il_scan_cancel(il);
 
-	if ((test_bit(S_RF_KILL_HW, &status) !=
-	     test_bit(S_RF_KILL_HW, &il->status)))
+	if ((test_bit(S_RFKILL, &status) !=
+	     test_bit(S_RFKILL, &il->status)))
 		wiphy_rfkill_set_hw_state(il->hw->wiphy,
-					  test_bit(S_RF_KILL_HW, &il->status));
+					  test_bit(S_RFKILL, &il->status));
 	else
 		wake_up(&il->wait_command_queue);
 }
@@ -2167,7 +2166,7 @@
 	D_INFO("RFKILL status: 0x%x\n", rfkill);
 
 	if (rfkill & 0x1) {
-		clear_bit(S_RF_KILL_HW, &il->status);
+		clear_bit(S_RFKILL, &il->status);
 		/* if RFKILL is not on, then wait for thermal
 		 * sensor in adapter to kick in */
 		while (il3945_hw_get_temperature(il) == 0) {
@@ -2179,7 +2178,7 @@
 			D_INFO("Thermal calibration took %dus\n",
 			       thermal_spin * 10);
 	} else
-		set_bit(S_RF_KILL_HW, &il->status);
+		set_bit(S_RFKILL, &il->status);
 
 	/* After the ALIVE response, we can send commands to 3945 uCode */
 	set_bit(S_ALIVE, &il->status);
@@ -2273,12 +2272,8 @@
 	 * clear all bits but the RF Kill bits and return */
 	if (!il_is_init(il)) {
 		il->status =
-		    test_bit(S_RF_KILL_HW,
-			     &il->
-			     status) << S_RF_KILL_HW |
-		    test_bit(S_GEO_CONFIGURED,
-			     &il->
-			     status) << S_GEO_CONFIGURED |
+		    test_bit(S_RFKILL, &il->status) << S_RFKILL |
+		    test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
 		    test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
 		goto exit;
 	}
@@ -2286,25 +2281,30 @@
 	/* ...otherwise clear out all the status bits but the RF Kill
 	 * bit and continue taking the NIC down. */
 	il->status &=
-	    test_bit(S_RF_KILL_HW,
-		     &il->status) << S_RF_KILL_HW | test_bit(S_GEO_CONFIGURED,
-							     &il->
-							     status) <<
-	    S_GEO_CONFIGURED | test_bit(S_FW_ERROR,
-					&il->
-					status) << S_FW_ERROR |
+	    test_bit(S_RFKILL, &il->status) << S_RFKILL |
+	    test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
+	    test_bit(S_FW_ERROR, &il->status) << S_FW_ERROR |
 	    test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
 
+	/*
+	 * We disabled and synchronized interrupt, and priv->mutex is taken, so
+	 * here is the only thread which will program device registers, but
+	 * still have lockdep assertions, so we are taking reg_lock.
+	 */
+	spin_lock_irq(&il->reg_lock);
+	/* FIXME: il_grab_nic_access if rfkill is off ? */
+
 	il3945_hw_txq_ctx_stop(il);
 	il3945_hw_rxq_stop(il);
-
 	/* Power-down device's busmaster DMA clocks */
-	il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+	_il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
 	udelay(5);
-
 	/* Stop the device, and put it in low power state */
-	il_apm_stop(il);
+	_il_apm_stop(il);
 
+	spin_unlock_irq(&il->reg_lock);
+
+	il3945_hw_txq_ctx_free(il);
 exit:
 	memset(&il->card_alive, 0, sizeof(struct il_alive_resp));
 
@@ -2371,9 +2371,9 @@
 
 	/* If platform's RF_KILL switch is NOT set to KILL */
 	if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-		clear_bit(S_RF_KILL_HW, &il->status);
+		clear_bit(S_RFKILL, &il->status);
 	else {
-		set_bit(S_RF_KILL_HW, &il->status);
+		set_bit(S_RFKILL, &il->status);
 		IL_WARN("Radio disabled by HW RF Kill switch\n");
 		return -ENODEV;
 	}
@@ -2405,7 +2405,7 @@
 	       il->ucode_data.len);
 
 	/* We return success when we resume from suspend and rf_kill is on. */
-	if (test_bit(S_RF_KILL_HW, &il->status))
+	if (test_bit(S_RFKILL, &il->status))
 		return 0;
 
 	for (i = 0; i < MAX_HW_RESTARTS; i++) {
@@ -2413,7 +2413,7 @@
 		/* load bootstrap state machine,
 		 * load bootstrap program into processor's memory,
 		 * prepare to load the "initialize" uCode */
-		rc = il->ops->lib->load_ucode(il);
+		rc = il->ops->load_ucode(il);
 
 		if (rc) {
 			IL_ERR("Unable to set up bootstrap uCode: %d\n", rc);
@@ -2485,15 +2485,15 @@
 {
 	struct il_priv *il =
 	    container_of(data, struct il_priv, _3945.rfkill_poll.work);
-	bool old_rfkill = test_bit(S_RF_KILL_HW, &il->status);
+	bool old_rfkill = test_bit(S_RFKILL, &il->status);
 	bool new_rfkill =
 	    !(_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
 
 	if (new_rfkill != old_rfkill) {
 		if (new_rfkill)
-			set_bit(S_RF_KILL_HW, &il->status);
+			set_bit(S_RFKILL, &il->status);
 		else
-			clear_bit(S_RF_KILL_HW, &il->status);
+			clear_bit(S_RFKILL, &il->status);
 
 		wiphy_rfkill_set_hw_state(il->hw->wiphy, new_rfkill);
 
@@ -2782,10 +2782,9 @@
 	struct il_priv *il = hw->priv;
 	int ret;
 
-	D_MAC80211("enter\n");
-
 	/* we should be verifying the device is ready to be opened */
 	mutex_lock(&il->mutex);
+	D_MAC80211("enter\n");
 
 	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
 	 * ucode filename and max sizes are card-specific. */
@@ -2941,15 +2940,19 @@
 	 * hardware will then not attempt to decrypt the frames.
 	 */
 	if (vif->type == NL80211_IFTYPE_ADHOC &&
-	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+		D_MAC80211("leave - IBSS RSN\n");
 		return -EOPNOTSUPP;
+	}
 
 	static_key = !il_is_associated(il);
 
 	if (!static_key) {
 		sta_id = il_sta_id_or_broadcast(il, sta);
-		if (sta_id == IL_INVALID_STATION)
+		if (sta_id == IL_INVALID_STATION) {
+			D_MAC80211("leave - station not found\n");
 			return -EINVAL;
+		}
 	}
 
 	mutex_lock(&il->mutex);
@@ -2974,8 +2977,8 @@
 		ret = -EINVAL;
 	}
 
+	D_MAC80211("leave ret %d\n", ret);
 	mutex_unlock(&il->mutex);
-	D_MAC80211("leave\n");
 
 	return ret;
 }
@@ -2990,9 +2993,8 @@
 	bool is_ap = vif->type == NL80211_IFTYPE_STATION;
 	u8 sta_id;
 
-	D_INFO("received request to add station %pM\n", sta->addr);
 	mutex_lock(&il->mutex);
-	D_INFO("proceeding to add station %pM\n", sta->addr);
+	D_INFO("station %pM\n", sta->addr);
 	sta_priv->common.sta_id = IL_INVALID_STATION;
 
 	ret = il_add_station_common(il, sta->addr, is_ap, sta, &sta_id);
@@ -3098,11 +3100,9 @@
 	ret = strict_strtoul(buf, 0, &val);
 	if (ret)
 		IL_INFO("%s is not in hex or decimal form.\n", buf);
-	else {
+	else
 		il->debug_level = val;
-		if (il_alloc_traffic_mem(il))
-			IL_ERR("Not enough memory to generate traffic log\n");
-	}
+
 	return strnlen(buf, count);
 }
 
@@ -3619,12 +3619,12 @@
 	D_INFO("*** LOAD DRIVER ***\n");
 	il->cfg = cfg;
 	il->ops = &il3945_ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+	il->debugfs_ops = &il3945_debugfs_ops;
+#endif
 	il->pci_dev = pdev;
 	il->inta_mask = CSR_INI_SET_MASK;
 
-	if (il_alloc_traffic_mem(il))
-		IL_ERR("Not enough memory to generate traffic log\n");
-
 	/***************************
 	 * 2. Initializing PCI bus
 	 * *************************/
@@ -3655,7 +3655,7 @@
 	/***********************
 	 * 3. Read REV Register
 	 * ********************/
-	il->hw_base = pci_iomap(pdev, 0, 0);
+	il->hw_base = pci_ioremap_bar(pdev, 0);
 	if (!il->hw_base) {
 		err = -ENODEV;
 		goto out_pci_release_regions;
@@ -3669,7 +3669,7 @@
 	 * PCI Tx retries from interfering with C3 CPU state */
 	pci_write_config_byte(pdev, 0x41, 0x00);
 
-	/* these spin locks will be used in apm_ops.init and EEPROM access
+	/* these spin locks will be used in apm_init and EEPROM access
 	 * we should init now
 	 */
 	spin_lock_init(&il->reg_lock);
@@ -3780,14 +3780,13 @@
 out_eeprom_free:
 	il_eeprom_free(il);
 out_iounmap:
-	pci_iounmap(pdev, il->hw_base);
+	iounmap(il->hw_base);
 out_pci_release_regions:
 	pci_release_regions(pdev);
 out_pci_disable_device:
 	pci_set_drvdata(pdev, NULL);
 	pci_disable_device(pdev);
 out_ieee80211_free_hw:
-	il_free_traffic_mem(il);
 	ieee80211_free_hw(il->hw);
 out:
 	return err;
@@ -3855,12 +3854,11 @@
 	 * until now... */
 	destroy_workqueue(il->workqueue);
 	il->workqueue = NULL;
-	il_free_traffic_mem(il);
 
 	free_irq(pdev->irq, il);
 	pci_disable_msi(pdev);
 
-	pci_iounmap(pdev, il->hw_base);
+	iounmap(il->hw_base);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index 6c1ae5f..456f32d 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -57,10 +57,6 @@
 	return il_send_cmd(il, &cmd);
 }
 
-const struct il_led_ops il3945_led_ops = {
-	.cmd = il3945_send_led_cmd,
-};
-
 #define IL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
 	[RATE_##r##M_IDX] = { RATE_##r##M_PLCP,   \
 				    RATE_##r##M_IEEE,   \
@@ -303,7 +299,7 @@
 		skb = txq->skbs[txq->q.read_ptr];
 		ieee80211_tx_status_irqsafe(il->hw, skb);
 		txq->skbs[txq->q.read_ptr] = NULL;
-		il->ops->lib->txq_free_tfd(il, txq);
+		il->ops->txq_free_tfd(il, txq);
 	}
 
 	if (il_queue_space(q) > q->low_mark && txq_id >= 0 &&
@@ -577,8 +573,6 @@
 		network_packet ? '*' : ' ', le16_to_cpu(rx_hdr->channel),
 		rx_status.signal, rx_status.signal, rx_status.rate_idx);
 
-	il_dbg_log_rx_data_frame(il, le16_to_cpu(rx_hdr->len), header);
-
 	if (network_packet) {
 		il->_3945.last_beacon_time =
 		    le32_to_cpu(rx_end->beacon_timestamp);
@@ -796,7 +790,6 @@
 static int
 il3945_tx_reset(struct il_priv *il)
 {
-
 	/* bypass mode */
 	il_wr_prph(il, ALM_SCD_MODE_REG, 0x2);
 
@@ -833,8 +826,7 @@
 static int
 il3945_txq_ctx_reset(struct il_priv *il)
 {
-	int rc;
-	int txq_id, slots_num;
+	int rc, txq_id;
 
 	il3945_hw_txq_ctx_free(il);
 
@@ -850,10 +842,7 @@
 
 	/* Tx queue(s) */
 	for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
-		slots_num =
-		    (txq_id ==
-		     IL39_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		rc = il_tx_queue_init(il, &il->txq[txq_id], slots_num, txq_id);
+		rc = il_tx_queue_init(il, txq_id);
 		if (rc) {
 			IL_ERR("Tx %d queue init failed\n", txq_id);
 			goto error;
@@ -958,12 +947,11 @@
 	struct il_rx_queue *rxq = &il->rxq;
 
 	spin_lock_irqsave(&il->lock, flags);
-	il->ops->lib->apm_ops.init(il);
+	il3945_apm_init(il);
 	spin_unlock_irqrestore(&il->lock, flags);
 
 	il3945_set_pwr_vmain(il);
-
-	il->ops->lib->apm_ops.config(il);
+	il3945_nic_config(il);
 
 	/* Allocate the RX queue, or reset if it is already allocated */
 	if (!rxq->bd) {
@@ -1014,7 +1002,7 @@
 				il_tx_queue_free(il, txq_id);
 
 	/* free tx queue structure */
-	il_txq_mem(il);
+	il_free_txq_mem(il);
 }
 
 void
@@ -1023,18 +1011,17 @@
 	int txq_id;
 
 	/* stop SCD */
-	il_wr_prph(il, ALM_SCD_MODE_REG, 0);
-	il_wr_prph(il, ALM_SCD_TXFACT_REG, 0);
+	_il_wr_prph(il, ALM_SCD_MODE_REG, 0);
+	_il_wr_prph(il, ALM_SCD_TXFACT_REG, 0);
 
 	/* reset TFD queues */
 	for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
-		il_wr(il, FH39_TCSR_CONFIG(txq_id), 0x0);
-		il_poll_bit(il, FH39_TSSR_TX_STATUS,
-			    FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
-			    1000);
+		_il_wr(il, FH39_TCSR_CONFIG(txq_id), 0x0);
+		_il_poll_bit(il, FH39_TSSR_TX_STATUS,
+			     FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
+			     FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
+			     1000);
 	}
-
-	il3945_hw_txq_ctx_free(il);
 }
 
 /**
@@ -1613,7 +1600,7 @@
 	}
 
 	/* send Txpower command for current channel to ucode */
-	return il->ops->lib->send_tx_power(il);
+	return il->ops->send_tx_power(il);
 }
 
 int
@@ -2183,12 +2170,14 @@
 int
 il3945_hw_rxq_stop(struct il_priv *il)
 {
-	int rc;
+	int ret;
 
-	il_wr(il, FH39_RCSR_CONFIG(0), 0);
-	rc = il_poll_bit(il, FH39_RSSR_STATUS,
-			 FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-	if (rc < 0)
+	_il_wr(il, FH39_RCSR_CONFIG(0), 0);
+	ret = _il_poll_bit(il, FH39_RSSR_STATUS,
+			   FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+			   FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+			   1000);
+	if (ret < 0)
 		IL_ERR("Can't stop Rx DMA.\n");
 
 	return 0;
@@ -2630,65 +2619,31 @@
 	return 0;
 }
 
-static struct il_hcmd_ops il3945_hcmd = {
-	.rxon_assoc = il3945_send_rxon_assoc,
-	.commit_rxon = il3945_commit_rxon,
-};
-
-static struct il_lib_ops il3945_lib = {
+const struct il_ops il3945_ops = {
 	.txq_attach_buf_to_tfd = il3945_hw_txq_attach_buf_to_tfd,
 	.txq_free_tfd = il3945_hw_txq_free_tfd,
 	.txq_init = il3945_hw_tx_queue_init,
 	.load_ucode = il3945_load_bsm,
 	.dump_nic_error_log = il3945_dump_nic_error_log,
-	.apm_ops = {
-		    .init = il3945_apm_init,
-		    .config = il3945_nic_config,
-		    },
-	.eeprom_ops = {
-		       .regulatory_bands = {
-					    EEPROM_REGULATORY_BAND_1_CHANNELS,
-					    EEPROM_REGULATORY_BAND_2_CHANNELS,
-					    EEPROM_REGULATORY_BAND_3_CHANNELS,
-					    EEPROM_REGULATORY_BAND_4_CHANNELS,
-					    EEPROM_REGULATORY_BAND_5_CHANNELS,
-					    EEPROM_REGULATORY_BAND_NO_HT40,
-					    EEPROM_REGULATORY_BAND_NO_HT40,
-					    },
-		       .acquire_semaphore = il3945_eeprom_acquire_semaphore,
-		       .release_semaphore = il3945_eeprom_release_semaphore,
-		       },
+	.apm_init = il3945_apm_init,
 	.send_tx_power = il3945_send_tx_power,
 	.is_valid_rtc_data_addr = il3945_hw_valid_rtc_data_addr,
+	.eeprom_acquire_semaphore = il3945_eeprom_acquire_semaphore,
+	.eeprom_release_semaphore = il3945_eeprom_release_semaphore,
 
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-	.debugfs_ops = {
-			.rx_stats_read = il3945_ucode_rx_stats_read,
-			.tx_stats_read = il3945_ucode_tx_stats_read,
-			.general_stats_read = il3945_ucode_general_stats_read,
-			},
-#endif
-};
+	.rxon_assoc = il3945_send_rxon_assoc,
+	.commit_rxon = il3945_commit_rxon,
 
-static const struct il_legacy_ops il3945_legacy_ops = {
-	.post_associate = il3945_post_associate,
-	.config_ap = il3945_config_ap,
-	.manage_ibss_station = il3945_manage_ibss_station,
-};
-
-static struct il_hcmd_utils_ops il3945_hcmd_utils = {
 	.get_hcmd_size = il3945_get_hcmd_size,
 	.build_addsta_hcmd = il3945_build_addsta_hcmd,
 	.request_scan = il3945_request_scan,
 	.post_scan = il3945_post_scan,
-};
 
-const struct il_ops il3945_ops = {
-	.lib = &il3945_lib,
-	.hcmd = &il3945_hcmd,
-	.utils = &il3945_hcmd_utils,
-	.led = &il3945_led_ops,
-	.legacy = &il3945_legacy_ops,
+	.post_associate = il3945_post_associate,
+	.config_ap = il3945_config_ap,
+	.manage_ibss_station = il3945_manage_ibss_station,
+
+	.send_led_cmd = il3945_send_led_cmd,
 };
 
 static struct il_cfg il3945_bg_cfg = {
@@ -2707,7 +2662,17 @@
 	.set_l0s = false,
 	.use_bsm = true,
 	.led_compensation = 64,
-	.wd_timeout = IL_DEF_WD_TIMEOUT
+	.wd_timeout = IL_DEF_WD_TIMEOUT,
+
+	.regulatory_bands = {
+		EEPROM_REGULATORY_BAND_1_CHANNELS,
+		EEPROM_REGULATORY_BAND_2_CHANNELS,
+		EEPROM_REGULATORY_BAND_3_CHANNELS,
+		EEPROM_REGULATORY_BAND_4_CHANNELS,
+		EEPROM_REGULATORY_BAND_5_CHANNELS,
+		EEPROM_REGULATORY_BAND_NO_HT40,
+		EEPROM_REGULATORY_BAND_NO_HT40,
+	},
 };
 
 static struct il_cfg il3945_abg_cfg = {
@@ -2726,7 +2691,17 @@
 	.set_l0s = false,
 	.use_bsm = true,
 	.led_compensation = 64,
-	.wd_timeout = IL_DEF_WD_TIMEOUT
+	.wd_timeout = IL_DEF_WD_TIMEOUT,
+
+	.regulatory_bands = {
+		EEPROM_REGULATORY_BAND_1_CHANNELS,
+		EEPROM_REGULATORY_BAND_2_CHANNELS,
+		EEPROM_REGULATORY_BAND_3_CHANNELS,
+		EEPROM_REGULATORY_BAND_4_CHANNELS,
+		EEPROM_REGULATORY_BAND_5_CHANNELS,
+		EEPROM_REGULATORY_BAND_NO_HT40,
+		EEPROM_REGULATORY_BAND_NO_HT40,
+	},
 };
 
 DEFINE_PCI_DEVICE_TABLE(il3945_hw_card_ids) = {
diff --git a/drivers/net/wireless/iwlegacy/3945.h b/drivers/net/wireless/iwlegacy/3945.h
index c00a8d3..1d45075 100644
--- a/drivers/net/wireless/iwlegacy/3945.h
+++ b/drivers/net/wireless/iwlegacy/3945.h
@@ -595,13 +595,7 @@
 } __packed;
 
 #ifdef CONFIG_IWLEGACY_DEBUGFS
-ssize_t il3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
-				   size_t count, loff_t *ppos);
-ssize_t il3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
-				   size_t count, loff_t *ppos);
-ssize_t il3945_ucode_general_stats_read(struct file *file,
-					char __user *user_buf, size_t count,
-					loff_t *ppos);
+extern const struct il_debugfs_ops il3945_debugfs_ops;
 #endif
 
 #endif
diff --git a/drivers/net/wireless/iwlegacy/4965-calib.c b/drivers/net/wireless/iwlegacy/4965-calib.c
index fe91715..e78bdef 100644
--- a/drivers/net/wireless/iwlegacy/4965-calib.c
+++ b/drivers/net/wireless/iwlegacy/4965-calib.c
@@ -79,18 +79,6 @@
 	u32 beacon_energy_c;
 };
 
-void
-il4965_calib_free_results(struct il_priv *il)
-{
-	int i;
-
-	for (i = 0; i < IL_CALIB_MAX; i++) {
-		kfree(il->calib_results[i].buf);
-		il->calib_results[i].buf = NULL;
-		il->calib_results[i].buf_len = 0;
-	}
-}
-
 /*****************************************************************************
  * RUNTIME calibrations framework
  *****************************************************************************/
@@ -923,8 +911,8 @@
 	/* Some power changes may have been made during the calibration.
 	 * Update and commit the RXON
 	 */
-	if (il->ops->lib->update_chain_flags)
-		il->ops->lib->update_chain_flags(il);
+	if (il->ops->update_chain_flags)
+		il->ops->update_chain_flags(il);
 
 	data->state = IL_CHAIN_NOISE_DONE;
 	il_power_update_mode(il, false);
diff --git a/drivers/net/wireless/iwlegacy/4965-debug.c b/drivers/net/wireless/iwlegacy/4965-debug.c
index 98ec39f..c8153fc 100644
--- a/drivers/net/wireless/iwlegacy/4965-debug.c
+++ b/drivers/net/wireless/iwlegacy/4965-debug.c
@@ -744,3 +744,9 @@
 	kfree(buf);
 	return ret;
 }
+
+const struct il_debugfs_ops il4965_debugfs_ops = {
+	.rx_stats_read = il4965_ucode_rx_stats_read,
+	.tx_stats_read = il4965_ucode_tx_stats_read,
+	.general_stats_read = il4965_ucode_general_stats_read,
+};
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 235812a..7b54dbb 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -199,18 +199,14 @@
 	struct il_rx_queue *rxq = &il->rxq;
 	int ret;
 
-	/* nic_init */
 	spin_lock_irqsave(&il->lock, flags);
-	il->ops->lib->apm_ops.init(il);
-
+	il_apm_init(il);
 	/* Set interrupt coalescing calibration timer to default (512 usecs) */
 	il_write8(il, CSR_INT_COALESCING, IL_HOST_INT_CALIB_TIMEOUT_DEF);
-
 	spin_unlock_irqrestore(&il->lock, flags);
 
 	il4965_set_pwr_vmain(il);
-
-	il->ops->lib->apm_ops.config(il);
+	il4965_nic_config(il);
 
 	/* Allocate the RX queue, or reset if it is already allocated */
 	if (!rxq->bd) {
@@ -445,11 +441,15 @@
 int
 il4965_rxq_stop(struct il_priv *il)
 {
+	int ret;
 
-	/* stop Rx DMA */
-	il_wr(il, FH49_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-	il_poll_bit(il, FH49_MEM_RSSR_RX_STATUS_REG,
-		    FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+	_il_wr(il, FH49_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+	ret = _il_poll_bit(il, FH49_MEM_RSSR_RX_STATUS_REG,
+			   FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+			   FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+			   1000);
+	if (ret < 0)
+		IL_ERR("Can't stop Rx DMA.\n");
 
 	return 0;
 }
@@ -692,7 +692,6 @@
 	/* Find max signal strength (dBm) among 3 antenna/receiver chains */
 	rx_status.signal = il4965_calc_rssi(il, phy_res);
 
-	il_dbg_log_rx_data_frame(il, len, header);
 	D_STATS("Rssi %d, TSF %llu\n", rx_status.signal,
 		(unsigned long long)rx_status.mactime);
 
@@ -1343,12 +1342,11 @@
 }
 #endif
 
-#define REG_RECALIB_PERIOD (60)
-
 void
 il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
 {
-	int change;
+	const int recalib_seconds = 60;
+	bool change;
 	struct il_rx_pkt *pkt = rxb_addr(rxb);
 
 	D_RX("Statistics notification received (%d vs %d).\n",
@@ -1369,20 +1367,21 @@
 
 	set_bit(S_STATS, &il->status);
 
-	/* Reschedule the stats timer to occur in
-	 * REG_RECALIB_PERIOD seconds to ensure we get a
-	 * thermal update even if the uCode doesn't give
-	 * us one */
+	/*
+	 * Reschedule the stats timer to occur in recalib_seconds to ensure
+	 * we get a thermal update even if the uCode doesn't give us one
+	 */
 	mod_timer(&il->stats_periodic,
-		  jiffies + msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+		  jiffies + msecs_to_jiffies(recalib_seconds * 1000));
 
 	if (unlikely(!test_bit(S_SCANNING, &il->status)) &&
 	    (pkt->hdr.cmd == N_STATS)) {
 		il4965_rx_calc_noise(il);
 		queue_work(il->workqueue, &il->run_time_calib_work);
 	}
-	if (il->ops->lib->temp_ops.temperature && change)
-		il->ops->lib->temp_ops.temperature(il);
+
+	if (change)
+		il4965_temperature_calib(il);
 }
 
 void
@@ -1694,7 +1693,7 @@
 		sta_priv = (void *)sta->drv_priv;
 
 	if (sta_priv && sta_priv->asleep &&
-	    (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
+	    (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
 		/*
 		 * This sends an asynchronous command to the device,
 		 * but we can rely on it being processed before the
@@ -1785,7 +1784,6 @@
 
 	/* TODO need this for burst mode later on */
 	il4965_tx_cmd_build_basic(il, skb, tx_cmd, info, hdr, sta_id);
-	il_dbg_log_tx_data_frame(il, len, hdr);
 
 	il4965_tx_cmd_build_rate(il, tx_cmd, info, fc);
 
@@ -1815,7 +1813,7 @@
 	dma_unmap_len_set(out_meta, len, firstlen);
 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 	 * first entry */
-	il->ops->lib->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
+	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
 
 	if (!ieee80211_has_morefrags(hdr->frame_control)) {
 		txq->need_update = 1;
@@ -1831,8 +1829,8 @@
 		phys_addr =
 		    pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,
 				   PCI_DMA_TODEVICE);
-		il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr,
-						    secondlen, 0, 0);
+		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen,
+					       0, 0);
 	}
 
 	scratch_phys =
@@ -1852,8 +1850,7 @@
 
 	/* Set up entry for this TFD in Tx byte-count array */
 	if (info->flags & IEEE80211_TX_CTL_AMPDU)
-		il->ops->lib->txq_update_byte_cnt_tbl(il, txq,
-						      le16_to_cpu(tx_cmd->len));
+		il->ops->txq_update_byte_cnt_tbl(il, txq, le16_to_cpu(tx_cmd->len));
 
 	pci_dma_sync_single_for_device(il->pci_dev, txcmd_phys, firstlen,
 				       PCI_DMA_BIDIRECTIONAL);
@@ -1942,7 +1939,7 @@
 	il4965_free_dma_ptr(il, &il->scd_bc_tbls);
 
 	/* free tx queue structure */
-	il_txq_mem(il);
+	il_free_txq_mem(il);
 }
 
 /**
@@ -1955,8 +1952,7 @@
 int
 il4965_txq_ctx_alloc(struct il_priv *il)
 {
-	int ret;
-	int txq_id, slots_num;
+	int ret, txq_id;
 	unsigned long flags;
 
 	/* Free all tx/cmd queues and keep-warm buffer */
@@ -1993,10 +1989,7 @@
 
 	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
 	for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
-		slots_num =
-		    (txq_id ==
-		     il->cmd_queue) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		ret = il_tx_queue_init(il, &il->txq[txq_id], slots_num, txq_id);
+		ret = il_tx_queue_init(il, txq_id);
 		if (ret) {
 			IL_ERR("Tx %d queue init failed\n", txq_id);
 			goto error;
@@ -2017,52 +2010,27 @@
 void
 il4965_txq_ctx_reset(struct il_priv *il)
 {
-	int txq_id, slots_num;
+	int txq_id;
 	unsigned long flags;
 
 	spin_lock_irqsave(&il->lock, flags);
 
 	/* Turn off all Tx DMA fifos */
 	il4965_txq_set_sched(il, 0);
-
 	/* Tell NIC where to find the "keep warm" buffer */
 	il_wr(il, FH49_KW_MEM_ADDR_REG, il->kw.dma >> 4);
 
 	spin_unlock_irqrestore(&il->lock, flags);
 
 	/* Alloc and init all Tx queues, including the command queue (#4) */
-	for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
-		slots_num =
-		    txq_id == il->cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		il_tx_queue_reset(il, &il->txq[txq_id], slots_num, txq_id);
-	}
+	for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++)
+		il_tx_queue_reset(il, txq_id);
 }
 
-/**
- * il4965_txq_ctx_stop - Stop all Tx DMA channels
- */
 void
-il4965_txq_ctx_stop(struct il_priv *il)
+il4965_txq_ctx_unmap(struct il_priv *il)
 {
-	int ch, txq_id;
-	unsigned long flags;
-
-	/* Turn off all Tx DMA fifos */
-	spin_lock_irqsave(&il->lock, flags);
-
-	il4965_txq_set_sched(il, 0);
-
-	/* Stop each Tx DMA channel, and wait for it to be idle */
-	for (ch = 0; ch < il->hw_params.dma_chnl_num; ch++) {
-		il_wr(il, FH49_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-		if (il_poll_bit
-		    (il, FH49_TSSR_TX_STATUS_REG,
-		     FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000))
-			IL_ERR("Failing on timeout while stopping"
-			       " DMA channel %d [0x%08x]", ch,
-			       il_rd(il, FH49_TSSR_TX_STATUS_REG));
-	}
-	spin_unlock_irqrestore(&il->lock, flags);
+	int txq_id;
 
 	if (!il->txq)
 		return;
@@ -2075,6 +2043,30 @@
 			il_tx_queue_unmap(il, txq_id);
 }
 
+/**
+ * il4965_txq_ctx_stop - Stop all Tx DMA channels
+ */
+void
+il4965_txq_ctx_stop(struct il_priv *il)
+{
+	int ch, ret;
+
+	_il_wr_prph(il, IL49_SCD_TXFACT, 0);
+
+	/* Stop each Tx DMA channel, and wait for it to be idle */
+	for (ch = 0; ch < il->hw_params.dma_chnl_num; ch++) {
+		_il_wr(il, FH49_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+		ret =
+		    _il_poll_bit(il, FH49_TSSR_TX_STATUS_REG,
+				 FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+				 FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+				 1000);
+		if (ret < 0)
+			IL_ERR("Timeout stopping DMA channel %d [0x%08x]",
+			       ch, _il_rd(il, FH49_TSSR_TX_STATUS_REG));
+	}
+}
+
 /*
  * Find first available (lowest unused) Tx Queue, mark it "active".
  * Called only when finding queue for aggregation.
@@ -2474,7 +2466,7 @@
 		il4965_tx_status(il, skb, txq_id >= IL4965_FIRST_AMPDU_QUEUE);
 
 		txq->skbs[txq->q.read_ptr] = NULL;
-		il->ops->lib->txq_free_tfd(il, txq);
+		il->ops->txq_free_tfd(il, txq);
 	}
 	return nfreed;
 }
@@ -2548,6 +2540,308 @@
 	return 0;
 }
 
+static inline bool
+il4965_is_tx_success(u32 status)
+{
+	status &= TX_STATUS_MSK;
+	return (status == TX_STATUS_SUCCESS || status == TX_STATUS_DIRECT_DONE);
+}
+
+static u8
+il4965_find_station(struct il_priv *il, const u8 *addr)
+{
+	int i;
+	int start = 0;
+	int ret = IL_INVALID_STATION;
+	unsigned long flags;
+
+	if (il->iw_mode == NL80211_IFTYPE_ADHOC)
+		start = IL_STA_ID;
+
+	if (is_broadcast_ether_addr(addr))
+		return il->hw_params.bcast_id;
+
+	spin_lock_irqsave(&il->sta_lock, flags);
+	for (i = start; i < il->hw_params.max_stations; i++)
+		if (il->stations[i].used &&
+		    (!compare_ether_addr(il->stations[i].sta.sta.addr, addr))) {
+			ret = i;
+			goto out;
+		}
+
+	D_ASSOC("can not find STA %pM total %d\n", addr, il->num_stations);
+
+out:
+	/*
+	 * It may be possible that more commands interacting with stations
+	 * arrive before we completed processing the adding of
+	 * station
+	 */
+	if (ret != IL_INVALID_STATION &&
+	    (!(il->stations[ret].used & IL_STA_UCODE_ACTIVE) ||
+	     ((il->stations[ret].used & IL_STA_UCODE_ACTIVE) &&
+	      (il->stations[ret].used & IL_STA_UCODE_INPROGRESS)))) {
+		IL_ERR("Requested station info for sta %d before ready.\n",
+		       ret);
+		ret = IL_INVALID_STATION;
+	}
+	spin_unlock_irqrestore(&il->sta_lock, flags);
+	return ret;
+}
+
+static int
+il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
+{
+	if (il->iw_mode == NL80211_IFTYPE_STATION)
+		return IL_AP_ID;
+	else {
+		u8 *da = ieee80211_get_DA(hdr);
+
+		return il4965_find_station(il, da);
+	}
+}
+
+static inline u32
+il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
+{
+	return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
+}
+
+static inline u32
+il4965_tx_status_to_mac80211(u32 status)
+{
+	status &= TX_STATUS_MSK;
+
+	switch (status) {
+	case TX_STATUS_SUCCESS:
+	case TX_STATUS_DIRECT_DONE:
+		return IEEE80211_TX_STAT_ACK;
+	case TX_STATUS_FAIL_DEST_PS:
+		return IEEE80211_TX_STAT_TX_FILTERED;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * il4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
+ */
+static int
+il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
+			  struct il4965_tx_resp *tx_resp, int txq_id,
+			  u16 start_idx)
+{
+	u16 status;
+	struct agg_tx_status *frame_status = tx_resp->u.agg_status;
+	struct ieee80211_tx_info *info = NULL;
+	struct ieee80211_hdr *hdr = NULL;
+	u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+	int i, sh, idx;
+	u16 seq;
+	if (agg->wait_for_ba)
+		D_TX_REPLY("got tx response w/o block-ack\n");
+
+	agg->frame_count = tx_resp->frame_count;
+	agg->start_idx = start_idx;
+	agg->rate_n_flags = rate_n_flags;
+	agg->bitmap = 0;
+
+	/* num frames attempted by Tx command */
+	if (agg->frame_count == 1) {
+		/* Only one frame was attempted; no block-ack will arrive */
+		status = le16_to_cpu(frame_status[0].status);
+		idx = start_idx;
+
+		D_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
+			   agg->frame_count, agg->start_idx, idx);
+
+		info = IEEE80211_SKB_CB(il->txq[txq_id].skbs[idx]);
+		info->status.rates[0].count = tx_resp->failure_frame + 1;
+		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+		info->flags |= il4965_tx_status_to_mac80211(status);
+		il4965_hwrate_to_tx_control(il, rate_n_flags, info);
+
+		D_TX_REPLY("1 Frame 0x%x failure :%d\n", status & 0xff,
+			   tx_resp->failure_frame);
+		D_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags);
+
+		agg->wait_for_ba = 0;
+	} else {
+		/* Two or more frames were attempted; expect block-ack */
+		u64 bitmap = 0;
+		int start = agg->start_idx;
+		struct sk_buff *skb;
+
+		/* Construct bit-map of pending frames within Tx win */
+		for (i = 0; i < agg->frame_count; i++) {
+			u16 sc;
+			status = le16_to_cpu(frame_status[i].status);
+			seq = le16_to_cpu(frame_status[i].sequence);
+			idx = SEQ_TO_IDX(seq);
+			txq_id = SEQ_TO_QUEUE(seq);
+
+			if (status &
+			    (AGG_TX_STATE_FEW_BYTES_MSK |
+			     AGG_TX_STATE_ABORT_MSK))
+				continue;
+
+			D_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+				   agg->frame_count, txq_id, idx);
+
+			skb = il->txq[txq_id].skbs[idx];
+			if (WARN_ON_ONCE(skb == NULL))
+				return -1;
+			hdr = (struct ieee80211_hdr *) skb->data;
+
+			sc = le16_to_cpu(hdr->seq_ctrl);
+			if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+				IL_ERR("BUG_ON idx doesn't match seq control"
+				       " idx=%d, seq_idx=%d, seq=%d\n", idx,
+				       SEQ_TO_SN(sc), hdr->seq_ctrl);
+				return -1;
+			}
+
+			D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
+				   SEQ_TO_SN(sc));
+
+			sh = idx - start;
+			if (sh > 64) {
+				sh = (start - idx) + 0xff;
+				bitmap = bitmap << sh;
+				sh = 0;
+				start = idx;
+			} else if (sh < -64)
+				sh = 0xff - (start - idx);
+			else if (sh < 0) {
+				sh = start - idx;
+				start = idx;
+				bitmap = bitmap << sh;
+				sh = 0;
+			}
+			bitmap |= 1ULL << sh;
+			D_TX_REPLY("start=%d bitmap=0x%llx\n", start,
+				   (unsigned long long)bitmap);
+		}
+
+		agg->bitmap = bitmap;
+		agg->start_idx = start;
+		D_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
+			   agg->frame_count, agg->start_idx,
+			   (unsigned long long)agg->bitmap);
+
+		if (bitmap)
+			agg->wait_for_ba = 1;
+	}
+	return 0;
+}
+
+/**
+ * il4965_hdl_tx - Handle standard (non-aggregation) Tx response
+ */
+static void
+il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
+{
+	struct il_rx_pkt *pkt = rxb_addr(rxb);
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int idx = SEQ_TO_IDX(sequence);
+	struct il_tx_queue *txq = &il->txq[txq_id];
+	struct sk_buff *skb;
+	struct ieee80211_hdr *hdr;
+	struct ieee80211_tx_info *info;
+	struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+	u32 status = le32_to_cpu(tx_resp->u.status);
+	int uninitialized_var(tid);
+	int sta_id;
+	int freed;
+	u8 *qc = NULL;
+	unsigned long flags;
+
+	if (idx >= txq->q.n_bd || il_queue_used(&txq->q, idx) == 0) {
+		IL_ERR("Read idx for DMA queue txq_id (%d) idx %d "
+		       "is out of range [0-%d] %d %d\n", txq_id, idx,
+		       txq->q.n_bd, txq->q.write_ptr, txq->q.read_ptr);
+		return;
+	}
+
+	txq->time_stamp = jiffies;
+
+	skb = txq->skbs[txq->q.read_ptr];
+	info = IEEE80211_SKB_CB(skb);
+	memset(&info->status, 0, sizeof(info->status));
+
+	hdr = (struct ieee80211_hdr *) skb->data;
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		qc = ieee80211_get_qos_ctl(hdr);
+		tid = qc[0] & 0xf;
+	}
+
+	sta_id = il4965_get_ra_sta_id(il, hdr);
+	if (txq->sched_retry && unlikely(sta_id == IL_INVALID_STATION)) {
+		IL_ERR("Station not known\n");
+		return;
+	}
+
+	spin_lock_irqsave(&il->sta_lock, flags);
+	if (txq->sched_retry) {
+		const u32 scd_ssn = il4965_get_scd_ssn(tx_resp);
+		struct il_ht_agg *agg = NULL;
+		WARN_ON(!qc);
+
+		agg = &il->stations[sta_id].tid[tid].agg;
+
+		il4965_tx_status_reply_tx(il, agg, tx_resp, txq_id, idx);
+
+		/* check if BAR is needed */
+		if (tx_resp->frame_count == 1 &&
+		    !il4965_is_tx_success(status))
+			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+
+		if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+			idx = il_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+			D_TX_REPLY("Retry scheduler reclaim scd_ssn "
+				   "%d idx %d\n", scd_ssn, idx);
+			freed = il4965_tx_queue_reclaim(il, txq_id, idx);
+			if (qc)
+				il4965_free_tfds_in_queue(il, sta_id, tid,
+							  freed);
+
+			if (il->mac80211_registered &&
+			    il_queue_space(&txq->q) > txq->q.low_mark &&
+			    agg->state != IL_EMPTYING_HW_QUEUE_DELBA)
+				il_wake_queue(il, txq);
+		}
+	} else {
+		info->status.rates[0].count = tx_resp->failure_frame + 1;
+		info->flags |= il4965_tx_status_to_mac80211(status);
+		il4965_hwrate_to_tx_control(il,
+					    le32_to_cpu(tx_resp->rate_n_flags),
+					    info);
+
+		D_TX_REPLY("TXQ %d status %s (0x%08x) "
+			   "rate_n_flags 0x%x retries %d\n", txq_id,
+			   il4965_get_tx_fail_reason(status), status,
+			   le32_to_cpu(tx_resp->rate_n_flags),
+			   tx_resp->failure_frame);
+
+		freed = il4965_tx_queue_reclaim(il, txq_id, idx);
+		if (qc && likely(sta_id != IL_INVALID_STATION))
+			il4965_free_tfds_in_queue(il, sta_id, tid, freed);
+		else if (sta_id == IL_INVALID_STATION)
+			D_TX_REPLY("Station not known\n");
+
+		if (il->mac80211_registered &&
+		    il_queue_space(&txq->q) > txq->q.low_mark)
+			il_wake_queue(il, txq);
+	}
+	if (qc && likely(sta_id != IL_INVALID_STATION))
+		il4965_txq_check_empty(il, sta_id, tid, txq_id);
+
+	il4965_check_abort_status(il, tx_resp->frame_count, status);
+
+	spin_unlock_irqrestore(&il->sta_lock, flags);
+}
+
 /**
  * translate ucode response to mac80211 tx status control values
  */
@@ -3352,8 +3646,8 @@
 void
 il4965_update_chain_flags(struct il_priv *il)
 {
-	if (il->ops->hcmd->set_rxon_chain) {
-		il->ops->hcmd->set_rxon_chain(il);
+	if (il->ops->set_rxon_chain) {
+		il->ops->set_rxon_chain(il);
 		if (il->active.rx_chain != il->staging.rx_chain)
 			il_commit_rxon(il);
 	}
@@ -3726,9 +4020,9 @@
  * This callback is provided in order to send a stats request.
  *
  * This timer function is continually reset to execute within
- * REG_RECALIB_PERIOD seconds since the last N_STATS
- * was received.  We need to ensure we receive the stats in order
- * to update the temperature used for calibrating the TXPOWER.
+ * 60 seconds since the last N_STATS was received.  We need to
+ * ensure we receive the stats in order to update the temperature
+ * used for calibrating the TXPOWER.
  */
 static void
 il4965_bg_stats_periodic(unsigned long data)
@@ -3778,7 +4072,7 @@
 	_il_rd(il, CSR_UCODE_DRV_GP1);
 
 	spin_lock_irqsave(&il->reg_lock, flags);
-	if (!_il_grab_nic_access(il))
+	if (likely(_il_grab_nic_access(il)))
 		_il_release_nic_access(il);
 	spin_unlock_irqrestore(&il->reg_lock, flags);
 }
@@ -3816,17 +4110,17 @@
 		il4965_perform_ct_kill_task(il);
 
 	if (flags & HW_CARD_DISABLED)
-		set_bit(S_RF_KILL_HW, &il->status);
+		set_bit(S_RFKILL, &il->status);
 	else
-		clear_bit(S_RF_KILL_HW, &il->status);
+		clear_bit(S_RFKILL, &il->status);
 
 	if (!(flags & RXON_CARD_DISABLED))
 		il_scan_cancel(il);
 
-	if ((test_bit(S_RF_KILL_HW, &status) !=
-	     test_bit(S_RF_KILL_HW, &il->status)))
+	if ((test_bit(S_RFKILL, &status) !=
+	     test_bit(S_RFKILL, &il->status)))
 		wiphy_rfkill_set_hw_state(il->hw->wiphy,
-					  test_bit(S_RF_KILL_HW, &il->status));
+					  test_bit(S_RFKILL, &il->status));
 	else
 		wake_up(&il->wait_command_queue);
 }
@@ -3868,10 +4162,11 @@
 	/* Rx handlers */
 	il->handlers[N_RX_PHY] = il4965_hdl_rx_phy;
 	il->handlers[N_RX_MPDU] = il4965_hdl_rx;
+	il->handlers[N_RX] = il4965_hdl_rx;
 	/* block ack */
 	il->handlers[N_COMPRESSED_BA] = il4965_hdl_compressed_ba;
-	/* Set up hardware specific Rx handlers */
-	il->ops->lib->handler_setup(il);
+	/* Tx response */
+	il->handlers[C_TX] = il4965_hdl_tx;
 }
 
 /**
@@ -4101,9 +4396,8 @@
 	/* HW RF KILL switch toggled */
 	if (inta & CSR_INT_BIT_RF_KILL) {
 		int hw_rf_kill = 0;
-		if (!
-		    (_il_rd(il, CSR_GP_CNTRL) &
-		     CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+
+		if (!(_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
 			hw_rf_kill = 1;
 
 		IL_WARN("RF_KILL bit toggled to %s.\n",
@@ -4118,9 +4412,9 @@
 		 */
 		if (!test_bit(S_ALIVE, &il->status)) {
 			if (hw_rf_kill)
-				set_bit(S_RF_KILL_HW, &il->status);
+				set_bit(S_RFKILL, &il->status);
 			else
-				clear_bit(S_RF_KILL_HW, &il->status);
+				clear_bit(S_RFKILL, &il->status);
 			wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill);
 		}
 
@@ -4244,11 +4538,9 @@
 	ret = strict_strtoul(buf, 0, &val);
 	if (ret)
 		IL_ERR("%s is not in hex or decimal form.\n", buf);
-	else {
+	else
 		il->debug_level = val;
-		if (il_alloc_traffic_mem(il))
-			IL_ERR("Not enough memory to generate traffic log\n");
-	}
+
 	return strnlen(buf, count);
 }
 
@@ -4773,7 +5065,7 @@
 	else
 		base = le32_to_cpu(il->card_alive.error_event_table_ptr);
 
-	if (!il->ops->lib->is_valid_rtc_data_addr(base)) {
+	if (!il->ops->is_valid_rtc_data_addr(base)) {
 		IL_ERR("Not valid error log pointer 0x%08X for %s uCode\n",
 		       base, (il->ucode_type == UCODE_INIT) ? "Init" : "RT");
 		return;
@@ -5002,8 +5294,8 @@
 		/* Initialize our rx_config data */
 		il_connection_init_rx_config(il);
 
-		if (il->ops->hcmd->set_rxon_chain)
-			il->ops->hcmd->set_rxon_chain(il);
+		if (il->ops->set_rxon_chain)
+			il->ops->set_rxon_chain(il);
 	}
 
 	/* Configure bluetooth coexistence if enabled */
@@ -5091,12 +5383,8 @@
 	 * clear all bits but the RF Kill bit and return */
 	if (!il_is_init(il)) {
 		il->status =
-		    test_bit(S_RF_KILL_HW,
-			     &il->
-			     status) << S_RF_KILL_HW |
-		    test_bit(S_GEO_CONFIGURED,
-			     &il->
-			     status) << S_GEO_CONFIGURED |
+		    test_bit(S_RFKILL, &il->status) << S_RFKILL |
+		    test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
 		    test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
 		goto exit;
 	}
@@ -5104,28 +5392,32 @@
 	/* ...otherwise clear out all the status bits but the RF Kill
 	 * bit and continue taking the NIC down. */
 	il->status &=
-	    test_bit(S_RF_KILL_HW,
-		     &il->status) << S_RF_KILL_HW | test_bit(S_GEO_CONFIGURED,
-							     &il->
-							     status) <<
-	    S_GEO_CONFIGURED | test_bit(S_FW_ERROR,
-					&il->
-					status) << S_FW_ERROR |
+	    test_bit(S_RFKILL, &il->status) << S_RFKILL |
+	    test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
+	    test_bit(S_FW_ERROR, &il->status) << S_FW_ERROR |
 	    test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
 
+	/*
+	 * We disabled and synchronized interrupt, and priv->mutex is taken, so
+	 * here is the only thread which will program device registers, but
+	 * still have lockdep assertions, so we are taking reg_lock.
+	 */
+	spin_lock_irq(&il->reg_lock);
+	/* FIXME: il_grab_nic_access if rfkill is off ? */
+
 	il4965_txq_ctx_stop(il);
 	il4965_rxq_stop(il);
-
 	/* Power-down device's busmaster DMA clocks */
-	il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+	_il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
 	udelay(5);
-
 	/* Make sure (redundant) we've released our request to stay awake */
-	il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
+	_il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 	/* Stop the device, and put it in low power state */
-	il_apm_stop(il);
+	_il_apm_stop(il);
 
+	spin_unlock_irq(&il->reg_lock);
+
+	il4965_txq_ctx_unmap(il);
 exit:
 	memset(&il->card_alive, 0, sizeof(struct il_alive_resp));
 
@@ -5146,40 +5438,36 @@
 	il4965_cancel_deferred_work(il);
 }
 
-#define HW_READY_TIMEOUT (50)
 
-static int
+static void
 il4965_set_hw_ready(struct il_priv *il)
 {
-	int ret = 0;
+	int ret;
 
 	il_set_bit(il, CSR_HW_IF_CONFIG_REG,
 		   CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
 
 	/* See if we got it */
-	ret =
-	    _il_poll_bit(il, CSR_HW_IF_CONFIG_REG,
-			 CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
-			 CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT);
-	if (ret != -ETIMEDOUT)
+	ret = _il_poll_bit(il, CSR_HW_IF_CONFIG_REG,
+			   CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+			   CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+			   100);
+	if (ret >= 0)
 		il->hw_ready = true;
-	else
-		il->hw_ready = false;
 
-	D_INFO("hardware %s\n", (il->hw_ready == 1) ? "ready" : "not ready");
-	return ret;
+	D_INFO("hardware %s ready\n", (il->hw_ready) ? "" : "not");
 }
 
-static int
+static void
 il4965_prepare_card_hw(struct il_priv *il)
 {
-	int ret = 0;
+	int ret;
 
-	D_INFO("il4965_prepare_card_hw enter\n");
+	il->hw_ready = false;
 
-	ret = il4965_set_hw_ready(il);
+	il4965_set_hw_ready(il);
 	if (il->hw_ready)
-		return ret;
+		return;
 
 	/* If HW is not ready, prepare the conditions to check again */
 	il_set_bit(il, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PREPARE);
@@ -5192,8 +5480,6 @@
 	/* HW should be ready by now, check again. */
 	if (ret != -ETIMEDOUT)
 		il4965_set_hw_ready(il);
-
-	return ret;
 }
 
 #define MAX_HW_RESTARTS 5
@@ -5221,22 +5507,19 @@
 	}
 
 	il4965_prepare_card_hw(il);
-
 	if (!il->hw_ready) {
-		IL_WARN("Exit HW not ready\n");
+		IL_ERR("HW not ready\n");
 		return -EIO;
 	}
 
 	/* If platform's RF_KILL switch is NOT set to KILL */
 	if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-		clear_bit(S_RF_KILL_HW, &il->status);
-	else
-		set_bit(S_RF_KILL_HW, &il->status);
-
-	if (il_is_rfkill(il)) {
+		clear_bit(S_RFKILL, &il->status);
+	else {
+		set_bit(S_RFKILL, &il->status);
 		wiphy_rfkill_set_hw_state(il->hw->wiphy, true);
 
-		il_enable_interrupts(il);
+		il_enable_rfkill_int(il);
 		IL_WARN("Radio disabled by HW RF Kill switch\n");
 		return 0;
 	}
@@ -5275,7 +5558,7 @@
 		/* load bootstrap state machine,
 		 * load bootstrap program into processor's memory,
 		 * prepare to load the "initialize" uCode */
-		ret = il->ops->lib->load_ucode(il);
+		ret = il->ops->load_ucode(il);
 
 		if (ret) {
 			IL_ERR("Unable to set up bootstrap uCode: %d\n", ret);
@@ -5316,7 +5599,7 @@
 	if (test_bit(S_EXIT_PENDING, &il->status))
 		goto out;
 
-	il->ops->lib->init_alive_start(il);
+	il->ops->init_alive_start(il);
 out:
 	mutex_unlock(&il->mutex);
 }
@@ -5748,7 +6031,7 @@
 	if (!il_is_associated(il))
 		goto out;
 
-	if (!il->ops->lib->set_channel_switch)
+	if (!il->ops->set_channel_switch)
 		goto out;
 
 	ch = channel->hw_value;
@@ -5800,7 +6083,7 @@
 	 */
 	set_bit(S_CHANNEL_SWITCH_PENDING, &il->status);
 	il->switch_channel = cpu_to_le16(ch);
-	if (il->ops->lib->set_channel_switch(il, ch_switch)) {
+	if (il->ops->set_channel_switch(il, ch_switch)) {
 		clear_bit(S_CHANNEL_SWITCH_PENDING, &il->status);
 		il->switch_channel = 0;
 		ieee80211_chswitch_done(il->vif, false);
@@ -5883,7 +6166,7 @@
 	/* Regardless of if we are associated, we must reconfigure the
 	 * TX power since frames can be sent on non-radar channels while
 	 * not associated */
-	il->ops->lib->send_tx_power(il);
+	il->ops->send_tx_power(il);
 
 	/* Update last_temperature to keep is_calib_needed from running
 	 * when it isn't needed... */
@@ -6035,8 +6318,8 @@
 	il->force_reset.reset_duration = IL_DELAY_NEXT_FORCE_FW_RELOAD;
 
 	/* Choose which receivers/antennas to use */
-	if (il->ops->hcmd->set_rxon_chain)
-		il->ops->hcmd->set_rxon_chain(il);
+	if (il->ops->set_rxon_chain)
+		il->ops->set_rxon_chain(il);
 
 	il_init_scan_params(il);
 
@@ -6064,7 +6347,6 @@
 static void
 il4965_uninit_drv(struct il_priv *il)
 {
-	il4965_calib_free_results(il);
 	il_free_geos(il);
 	il_free_channel_map(il);
 	kfree(il->scan_cmd);
@@ -6180,12 +6462,12 @@
 	D_INFO("*** LOAD DRIVER ***\n");
 	il->cfg = cfg;
 	il->ops = &il4965_ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+	il->debugfs_ops = &il4965_debugfs_ops;
+#endif
 	il->pci_dev = pdev;
 	il->inta_mask = CSR_INI_SET_MASK;
 
-	if (il_alloc_traffic_mem(il))
-		IL_ERR("Not enough memory to generate traffic log\n");
-
 	/**************************
 	 * 2. Initializing PCI bus
 	 **************************/
@@ -6224,7 +6506,7 @@
 	/***********************
 	 * 3. Read REV register
 	 ***********************/
-	il->hw_base = pci_iomap(pdev, 0, 0);
+	il->hw_base = pci_ioremap_bar(pdev, 0);
 	if (!il->hw_base) {
 		err = -ENODEV;
 		goto out_pci_release_regions;
@@ -6329,12 +6611,12 @@
 
 	/* If platform's RF_KILL switch is NOT set to KILL */
 	if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-		clear_bit(S_RF_KILL_HW, &il->status);
+		clear_bit(S_RFKILL, &il->status);
 	else
-		set_bit(S_RF_KILL_HW, &il->status);
+		set_bit(S_RFKILL, &il->status);
 
 	wiphy_rfkill_set_hw_state(il->hw->wiphy,
-				  test_bit(S_RF_KILL_HW, &il->status));
+				  test_bit(S_RFKILL, &il->status));
 
 	il_power_initialize(il);
 
@@ -6356,14 +6638,13 @@
 out_free_eeprom:
 	il_eeprom_free(il);
 out_iounmap:
-	pci_iounmap(pdev, il->hw_base);
+	iounmap(il->hw_base);
 out_pci_release_regions:
 	pci_set_drvdata(pdev, NULL);
 	pci_release_regions(pdev);
 out_pci_disable_device:
 	pci_disable_device(pdev);
 out_ieee80211_free_hw:
-	il_free_traffic_mem(il);
 	ieee80211_free_hw(il->hw);
 out:
 	return err;
@@ -6434,11 +6715,10 @@
 	 * until now... */
 	destroy_workqueue(il->workqueue);
 	il->workqueue = NULL;
-	il_free_traffic_mem(il);
 
 	free_irq(il->pci_dev->irq, il);
 	pci_disable_msi(il->pci_dev);
-	pci_iounmap(pdev, il->hw_base);
+	iounmap(il->hw_base);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/wireless/iwlegacy/4965.c b/drivers/net/wireless/iwlegacy/4965.c
index 79e4e79..5db1171 100644
--- a/drivers/net/wireless/iwlegacy/4965.c
+++ b/drivers/net/wireless/iwlegacy/4965.c
@@ -264,10 +264,6 @@
 	_il_wr(il, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
 }
 
-const struct il_led_ops il4965_led_ops = {
-	.cmd = il4965_send_led_cmd,
-};
-
 static int il4965_send_tx_power(struct il_priv *il);
 static int il4965_hw_get_temperature(struct il_priv *il);
 
@@ -508,7 +504,7 @@
 		chan_mod == CHANNEL_MODE_MIXED);
 }
 
-static void
+void
 il4965_nic_config(struct il_priv *il)
 {
 	unsigned long flags;
@@ -1678,7 +1674,7 @@
 	return 1;
 }
 
-static void
+void
 il4965_temperature_calib(struct il_priv *il)
 {
 	s32 temp;
@@ -1737,323 +1733,6 @@
 	return (u16) sizeof(struct il4965_addsta_cmd);
 }
 
-static inline u32
-il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
-{
-	return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
-}
-
-static inline u32
-il4965_tx_status_to_mac80211(u32 status)
-{
-	status &= TX_STATUS_MSK;
-
-	switch (status) {
-	case TX_STATUS_SUCCESS:
-	case TX_STATUS_DIRECT_DONE:
-		return IEEE80211_TX_STAT_ACK;
-	case TX_STATUS_FAIL_DEST_PS:
-		return IEEE80211_TX_STAT_TX_FILTERED;
-	default:
-		return 0;
-	}
-}
-
-static inline bool
-il4965_is_tx_success(u32 status)
-{
-	status &= TX_STATUS_MSK;
-	return (status == TX_STATUS_SUCCESS || status == TX_STATUS_DIRECT_DONE);
-}
-
-/**
- * il4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
- */
-static int
-il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
-			  struct il4965_tx_resp *tx_resp, int txq_id,
-			  u16 start_idx)
-{
-	u16 status;
-	struct agg_tx_status *frame_status = tx_resp->u.agg_status;
-	struct ieee80211_tx_info *info = NULL;
-	struct ieee80211_hdr *hdr = NULL;
-	u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
-	int i, sh, idx;
-	u16 seq;
-	if (agg->wait_for_ba)
-		D_TX_REPLY("got tx response w/o block-ack\n");
-
-	agg->frame_count = tx_resp->frame_count;
-	agg->start_idx = start_idx;
-	agg->rate_n_flags = rate_n_flags;
-	agg->bitmap = 0;
-
-	/* num frames attempted by Tx command */
-	if (agg->frame_count == 1) {
-		/* Only one frame was attempted; no block-ack will arrive */
-		status = le16_to_cpu(frame_status[0].status);
-		idx = start_idx;
-
-		D_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
-			   agg->frame_count, agg->start_idx, idx);
-
-		info = IEEE80211_SKB_CB(il->txq[txq_id].skbs[idx]);
-		info->status.rates[0].count = tx_resp->failure_frame + 1;
-		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-		info->flags |= il4965_tx_status_to_mac80211(status);
-		il4965_hwrate_to_tx_control(il, rate_n_flags, info);
-
-		D_TX_REPLY("1 Frame 0x%x failure :%d\n", status & 0xff,
-			   tx_resp->failure_frame);
-		D_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags);
-
-		agg->wait_for_ba = 0;
-	} else {
-		/* Two or more frames were attempted; expect block-ack */
-		u64 bitmap = 0;
-		int start = agg->start_idx;
-		struct sk_buff *skb;
-
-		/* Construct bit-map of pending frames within Tx win */
-		for (i = 0; i < agg->frame_count; i++) {
-			u16 sc;
-			status = le16_to_cpu(frame_status[i].status);
-			seq = le16_to_cpu(frame_status[i].sequence);
-			idx = SEQ_TO_IDX(seq);
-			txq_id = SEQ_TO_QUEUE(seq);
-
-			if (status &
-			    (AGG_TX_STATE_FEW_BYTES_MSK |
-			     AGG_TX_STATE_ABORT_MSK))
-				continue;
-
-			D_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
-				   agg->frame_count, txq_id, idx);
-
-			skb = il->txq[txq_id].skbs[idx];
-			if (WARN_ON_ONCE(skb == NULL))
-				return -1;
-			hdr = (struct ieee80211_hdr *) skb->data;
-
-			sc = le16_to_cpu(hdr->seq_ctrl);
-			if (idx != (SEQ_TO_SN(sc) & 0xff)) {
-				IL_ERR("BUG_ON idx doesn't match seq control"
-				       " idx=%d, seq_idx=%d, seq=%d\n", idx,
-				       SEQ_TO_SN(sc), hdr->seq_ctrl);
-				return -1;
-			}
-
-			D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
-				   SEQ_TO_SN(sc));
-
-			sh = idx - start;
-			if (sh > 64) {
-				sh = (start - idx) + 0xff;
-				bitmap = bitmap << sh;
-				sh = 0;
-				start = idx;
-			} else if (sh < -64)
-				sh = 0xff - (start - idx);
-			else if (sh < 0) {
-				sh = start - idx;
-				start = idx;
-				bitmap = bitmap << sh;
-				sh = 0;
-			}
-			bitmap |= 1ULL << sh;
-			D_TX_REPLY("start=%d bitmap=0x%llx\n", start,
-				   (unsigned long long)bitmap);
-		}
-
-		agg->bitmap = bitmap;
-		agg->start_idx = start;
-		D_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
-			   agg->frame_count, agg->start_idx,
-			   (unsigned long long)agg->bitmap);
-
-		if (bitmap)
-			agg->wait_for_ba = 1;
-	}
-	return 0;
-}
-
-static u8
-il4965_find_station(struct il_priv *il, const u8 * addr)
-{
-	int i;
-	int start = 0;
-	int ret = IL_INVALID_STATION;
-	unsigned long flags;
-
-	if ((il->iw_mode == NL80211_IFTYPE_ADHOC))
-		start = IL_STA_ID;
-
-	if (is_broadcast_ether_addr(addr))
-		return il->hw_params.bcast_id;
-
-	spin_lock_irqsave(&il->sta_lock, flags);
-	for (i = start; i < il->hw_params.max_stations; i++)
-		if (il->stations[i].used &&
-		    (!compare_ether_addr(il->stations[i].sta.sta.addr, addr))) {
-			ret = i;
-			goto out;
-		}
-
-	D_ASSOC("can not find STA %pM total %d\n", addr, il->num_stations);
-
-out:
-	/*
-	 * It may be possible that more commands interacting with stations
-	 * arrive before we completed processing the adding of
-	 * station
-	 */
-	if (ret != IL_INVALID_STATION &&
-	    (!(il->stations[ret].used & IL_STA_UCODE_ACTIVE) ||
-	     ((il->stations[ret].used & IL_STA_UCODE_ACTIVE) &&
-	      (il->stations[ret].used & IL_STA_UCODE_INPROGRESS)))) {
-		IL_ERR("Requested station info for sta %d before ready.\n",
-		       ret);
-		ret = IL_INVALID_STATION;
-	}
-	spin_unlock_irqrestore(&il->sta_lock, flags);
-	return ret;
-}
-
-static int
-il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
-{
-	if (il->iw_mode == NL80211_IFTYPE_STATION) {
-		return IL_AP_ID;
-	} else {
-		u8 *da = ieee80211_get_DA(hdr);
-		return il4965_find_station(il, da);
-	}
-}
-
-/**
- * il4965_hdl_tx - Handle standard (non-aggregation) Tx response
- */
-static void
-il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
-{
-	struct il_rx_pkt *pkt = rxb_addr(rxb);
-	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-	int txq_id = SEQ_TO_QUEUE(sequence);
-	int idx = SEQ_TO_IDX(sequence);
-	struct il_tx_queue *txq = &il->txq[txq_id];
-	struct sk_buff *skb;
-	struct ieee80211_hdr *hdr;
-	struct ieee80211_tx_info *info;
-	struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
-	u32 status = le32_to_cpu(tx_resp->u.status);
-	int uninitialized_var(tid);
-	int sta_id;
-	int freed;
-	u8 *qc = NULL;
-	unsigned long flags;
-
-	if (idx >= txq->q.n_bd || il_queue_used(&txq->q, idx) == 0) {
-		IL_ERR("Read idx for DMA queue txq_id (%d) idx %d "
-		       "is out of range [0-%d] %d %d\n", txq_id, idx,
-		       txq->q.n_bd, txq->q.write_ptr, txq->q.read_ptr);
-		return;
-	}
-
-	txq->time_stamp = jiffies;
-
-	skb = txq->skbs[txq->q.read_ptr];
-	info = IEEE80211_SKB_CB(skb);
-	memset(&info->status, 0, sizeof(info->status));
-
-	hdr = (struct ieee80211_hdr *) skb->data;
-	if (ieee80211_is_data_qos(hdr->frame_control)) {
-		qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & 0xf;
-	}
-
-	sta_id = il4965_get_ra_sta_id(il, hdr);
-	if (txq->sched_retry && unlikely(sta_id == IL_INVALID_STATION)) {
-		IL_ERR("Station not known\n");
-		return;
-	}
-
-	spin_lock_irqsave(&il->sta_lock, flags);
-	if (txq->sched_retry) {
-		const u32 scd_ssn = il4965_get_scd_ssn(tx_resp);
-		struct il_ht_agg *agg = NULL;
-		WARN_ON(!qc);
-
-		agg = &il->stations[sta_id].tid[tid].agg;
-
-		il4965_tx_status_reply_tx(il, agg, tx_resp, txq_id, idx);
-
-		/* check if BAR is needed */
-		if ((tx_resp->frame_count == 1) &&
-		    !il4965_is_tx_success(status))
-			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-
-		if (txq->q.read_ptr != (scd_ssn & 0xff)) {
-			idx = il_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
-			D_TX_REPLY("Retry scheduler reclaim scd_ssn "
-				   "%d idx %d\n", scd_ssn, idx);
-			freed = il4965_tx_queue_reclaim(il, txq_id, idx);
-			if (qc)
-				il4965_free_tfds_in_queue(il, sta_id, tid,
-							  freed);
-
-			if (il->mac80211_registered &&
-			    il_queue_space(&txq->q) > txq->q.low_mark &&
-			    agg->state != IL_EMPTYING_HW_QUEUE_DELBA)
-				il_wake_queue(il, txq);
-		}
-	} else {
-		info->status.rates[0].count = tx_resp->failure_frame + 1;
-		info->flags |= il4965_tx_status_to_mac80211(status);
-		il4965_hwrate_to_tx_control(il,
-					    le32_to_cpu(tx_resp->rate_n_flags),
-					    info);
-
-		D_TX_REPLY("TXQ %d status %s (0x%08x) "
-			   "rate_n_flags 0x%x retries %d\n", txq_id,
-			   il4965_get_tx_fail_reason(status), status,
-			   le32_to_cpu(tx_resp->rate_n_flags),
-			   tx_resp->failure_frame);
-
-		freed = il4965_tx_queue_reclaim(il, txq_id, idx);
-		if (qc && likely(sta_id != IL_INVALID_STATION))
-			il4965_free_tfds_in_queue(il, sta_id, tid, freed);
-		else if (sta_id == IL_INVALID_STATION)
-			D_TX_REPLY("Station not known\n");
-
-		if (il->mac80211_registered &&
-		    il_queue_space(&txq->q) > txq->q.low_mark)
-			il_wake_queue(il, txq);
-	}
-	if (qc && likely(sta_id != IL_INVALID_STATION))
-		il4965_txq_check_empty(il, sta_id, tid, txq_id);
-
-	il4965_check_abort_status(il, tx_resp->frame_count, status);
-
-	spin_unlock_irqrestore(&il->sta_lock, flags);
-}
-
-/* Set up 4965-specific Rx frame reply handlers */
-static void
-il4965_handler_setup(struct il_priv *il)
-{
-	/* Legacy Rx frames */
-	il->handlers[N_RX] = il4965_hdl_rx;
-	/* Tx response */
-	il->handlers[C_TX] = il4965_hdl_tx;
-}
-
-static struct il_hcmd_ops il4965_hcmd = {
-	.rxon_assoc = il4965_send_rxon_assoc,
-	.commit_rxon = il4965_commit_rxon,
-	.set_rxon_chain = il4965_set_rxon_chain,
-};
-
 static void
 il4965_post_scan(struct il_priv *il)
 {
@@ -2093,8 +1772,8 @@
 
 	il_set_rxon_ht(il, &il->current_ht_config);
 
-	if (il->ops->hcmd->set_rxon_chain)
-		il->ops->hcmd->set_rxon_chain(il);
+	if (il->ops->set_rxon_chain)
+		il->ops->set_rxon_chain(il);
 
 	il->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
@@ -2168,8 +1847,8 @@
 		/* AP has all antennas */
 		il->chain_noise_data.active_chains = il->hw_params.valid_rx_ant;
 		il_set_rxon_ht(il, &il->current_ht_config);
-		if (il->ops->hcmd->set_rxon_chain)
-			il->ops->hcmd->set_rxon_chain(il);
+		if (il->ops->set_rxon_chain)
+			il->ops->set_rxon_chain(il);
 
 		il->staging.assoc_id = 0;
 
@@ -2193,68 +1872,38 @@
 	il4965_send_beacon_cmd(il);
 }
 
-static struct il_hcmd_utils_ops il4965_hcmd_utils = {
-	.get_hcmd_size = il4965_get_hcmd_size,
-	.build_addsta_hcmd = il4965_build_addsta_hcmd,
-	.request_scan = il4965_request_scan,
-	.post_scan = il4965_post_scan,
-};
-
-static struct il_lib_ops il4965_lib = {
+const struct il_ops il4965_ops = {
 	.txq_update_byte_cnt_tbl = il4965_txq_update_byte_cnt_tbl,
 	.txq_attach_buf_to_tfd = il4965_hw_txq_attach_buf_to_tfd,
 	.txq_free_tfd = il4965_hw_txq_free_tfd,
 	.txq_init = il4965_hw_tx_queue_init,
-	.handler_setup = il4965_handler_setup,
 	.is_valid_rtc_data_addr = il4965_hw_valid_rtc_data_addr,
 	.init_alive_start = il4965_init_alive_start,
 	.load_ucode = il4965_load_bsm,
 	.dump_nic_error_log = il4965_dump_nic_error_log,
 	.dump_fh = il4965_dump_fh,
 	.set_channel_switch = il4965_hw_channel_switch,
-	.apm_ops = {
-		    .init = il_apm_init,
-		    .config = il4965_nic_config,
-		    },
-	.eeprom_ops = {
-		       .regulatory_bands = {
-					    EEPROM_REGULATORY_BAND_1_CHANNELS,
-					    EEPROM_REGULATORY_BAND_2_CHANNELS,
-					    EEPROM_REGULATORY_BAND_3_CHANNELS,
-					    EEPROM_REGULATORY_BAND_4_CHANNELS,
-					    EEPROM_REGULATORY_BAND_5_CHANNELS,
-					    EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
-					    EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS},
-		       .acquire_semaphore = il4965_eeprom_acquire_semaphore,
-		       .release_semaphore = il4965_eeprom_release_semaphore,
-		       },
+	.apm_init = il_apm_init,
 	.send_tx_power = il4965_send_tx_power,
 	.update_chain_flags = il4965_update_chain_flags,
-	.temp_ops = {
-		     .temperature = il4965_temperature_calib,
-		     },
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-	.debugfs_ops = {
-			.rx_stats_read = il4965_ucode_rx_stats_read,
-			.tx_stats_read = il4965_ucode_tx_stats_read,
-			.general_stats_read = il4965_ucode_general_stats_read,
-			},
-#endif
-};
+	.eeprom_acquire_semaphore = il4965_eeprom_acquire_semaphore,
+	.eeprom_release_semaphore = il4965_eeprom_release_semaphore,
 
-static const struct il_legacy_ops il4965_legacy_ops = {
+	.rxon_assoc = il4965_send_rxon_assoc,
+	.commit_rxon = il4965_commit_rxon,
+	.set_rxon_chain = il4965_set_rxon_chain,
+
+	.get_hcmd_size = il4965_get_hcmd_size,
+	.build_addsta_hcmd = il4965_build_addsta_hcmd,
+	.request_scan = il4965_request_scan,
+	.post_scan = il4965_post_scan,
+
 	.post_associate = il4965_post_associate,
 	.config_ap = il4965_config_ap,
 	.manage_ibss_station = il4965_manage_ibss_station,
 	.update_bcast_stations = il4965_update_bcast_stations,
-};
 
-const struct il_ops il4965_ops = {
-	.lib = &il4965_lib,
-	.hcmd = &il4965_hcmd,
-	.utils = &il4965_hcmd_utils,
-	.led = &il4965_led_ops,
-	.legacy = &il4965_legacy_ops,
+	.send_led_cmd = il4965_send_led_cmd,
 };
 
 struct il_cfg il4965_cfg = {
@@ -2288,6 +1937,17 @@
 	.ucode_tracing = true,
 	.sensitivity_calib_by_driver = true,
 	.chain_noise_calib_by_driver = true,
+
+	.regulatory_bands = {
+		EEPROM_REGULATORY_BAND_1_CHANNELS,
+		EEPROM_REGULATORY_BAND_2_CHANNELS,
+		EEPROM_REGULATORY_BAND_3_CHANNELS,
+		EEPROM_REGULATORY_BAND_4_CHANNELS,
+		EEPROM_REGULATORY_BAND_5_CHANNELS,
+		EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
+		EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS
+	},
+
 };
 
 /* Module firmware */
diff --git a/drivers/net/wireless/iwlegacy/4965.h b/drivers/net/wireless/iwlegacy/4965.h
index 83ab604..1db6776 100644
--- a/drivers/net/wireless/iwlegacy/4965.h
+++ b/drivers/net/wireless/iwlegacy/4965.h
@@ -60,6 +60,8 @@
 int il4965_hw_nic_init(struct il_priv *il);
 int il4965_dump_fh(struct il_priv *il, char **buf, bool display);
 
+void il4965_nic_config(struct il_priv *il);
+
 /* rx */
 void il4965_rx_queue_restock(struct il_priv *il);
 void il4965_rx_replenish(struct il_priv *il);
@@ -67,8 +69,6 @@
 void il4965_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq);
 int il4965_rxq_stop(struct il_priv *il);
 int il4965_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
-void il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb);
-void il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb);
 void il4965_rx_handle(struct il_priv *il);
 
 /* tx */
@@ -84,7 +84,6 @@
 int il4965_tx_agg_stop(struct il_priv *il, struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta, u16 tid);
 int il4965_txq_check_empty(struct il_priv *il, int sta_id, u8 tid, int txq_id);
-void il4965_hdl_compressed_ba(struct il_priv *il, struct il_rx_buf *rxb);
 int il4965_tx_queue_reclaim(struct il_priv *il, int txq_id, int idx);
 void il4965_hw_txq_ctx_free(struct il_priv *il);
 int il4965_txq_ctx_alloc(struct il_priv *il);
@@ -106,12 +105,6 @@
 void il4965_tx_queue_set_status(struct il_priv *il, struct il_tx_queue *txq,
 				int tx_fifo_id, int scd_retry);
 
-/* rx */
-void il4965_hdl_missed_beacon(struct il_priv *il, struct il_rx_buf *rxb);
-bool il4965_good_plcp_health(struct il_priv *il, struct il_rx_pkt *pkt);
-void il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb);
-void il4965_hdl_c_stats(struct il_priv *il, struct il_rx_buf *rxb);
-
 /* scan */
 int il4965_request_scan(struct il_priv *il, struct ieee80211_vif *vif);
 
@@ -275,6 +268,7 @@
 	((t) < IL_TX_POWER_TEMPERATURE_MIN || \
 	 (t) > IL_TX_POWER_TEMPERATURE_MAX)
 
+extern void il4965_temperature_calib(struct il_priv *il);
 /********************* END TEMPERATURE ***************************************/
 
 /********************* START TXPOWER *****************************************/
@@ -933,17 +927,10 @@
 void il4965_sensitivity_calibration(struct il_priv *il, void *resp);
 void il4965_init_sensitivity(struct il_priv *il);
 void il4965_reset_run_time_calib(struct il_priv *il);
-void il4965_calib_free_results(struct il_priv *il);
 
 /* Debug */
 #ifdef CONFIG_IWLEGACY_DEBUGFS
-ssize_t il4965_ucode_rx_stats_read(struct file *file, char __user *user_buf,
-				   size_t count, loff_t *ppos);
-ssize_t il4965_ucode_tx_stats_read(struct file *file, char __user *user_buf,
-				   size_t count, loff_t *ppos);
-ssize_t il4965_ucode_general_stats_read(struct file *file,
-					char __user *user_buf, size_t count,
-					loff_t *ppos);
+extern const struct il_debugfs_ops il4965_debugfs_ops;
 #endif
 
 /****************************/
diff --git a/drivers/net/wireless/iwlegacy/Kconfig b/drivers/net/wireless/iwlegacy/Kconfig
index 05bd375..fb91972 100644
--- a/drivers/net/wireless/iwlegacy/Kconfig
+++ b/drivers/net/wireless/iwlegacy/Kconfig
@@ -6,45 +6,6 @@
 	select LEDS_TRIGGERS
 	select MAC80211_LEDS
 
-menu "Debugging Options"
-	depends on IWLEGACY
-
-config IWLEGACY_DEBUG
-	bool "Enable full debugging output in iwlegacy (iwl 3945/4965) drivers"
-	depends on IWLEGACY
-	---help---
-	  This option will enable debug tracing output for the iwlegacy
-	  drivers.
-
-	  This will result in the kernel module being ~100k larger.  You can
-	  control which debug output is sent to the kernel log by setting the
-	  value in
-
-		/sys/class/net/wlan0/device/debug_level
-
-	  This entry will only exist if this option is enabled.
-
-	  To set a value, simply echo an 8-byte hex value to the same file:
-
-		  % echo 0x43fff > /sys/class/net/wlan0/device/debug_level
-
-	  You can find the list of debug mask values in:
-		  drivers/net/wireless/iwlegacy/common.h
-
-	  If this is your first time using this driver, you should say Y here
-	  as the debug information can assist others in helping you resolve
-	  any problems you may encounter.
-
-config IWLEGACY_DEBUGFS
-        bool "iwlegacy (iwl 3945/4965) debugfs support"
-        depends on IWLEGACY && MAC80211_DEBUGFS
-        ---help---
-	  Enable creation of debugfs files for the iwlegacy drivers. This
-	  is a low-impact option that allows getting insight into the
-	  driver's state at runtime.
-
-endmenu
-
 config IWL4965
 	tristate "Intel Wireless WiFi 4965AGN (iwl4965)"
 	depends on PCI && MAC80211
@@ -98,3 +59,42 @@
 	  inserted in and removed from the running kernel whenever you want),
 	  say M here and read <file:Documentation/kbuild/modules.txt>.  The
 	  module will be called iwl3945.
+
+menu "iwl3945 / iwl4965 Debugging Options"
+	depends on IWLEGACY
+
+config IWLEGACY_DEBUG
+	bool "Enable full debugging output in iwlegacy (iwl 3945/4965) drivers"
+	depends on IWLEGACY
+	---help---
+	  This option will enable debug tracing output for the iwlegacy
+	  drivers.
+
+	  This will result in the kernel module being ~100k larger.  You can
+	  control which debug output is sent to the kernel log by setting the
+	  value in
+
+		/sys/class/net/wlan0/device/debug_level
+
+	  This entry will only exist if this option is enabled.
+
+	  To set a value, simply echo an 8-byte hex value to the same file:
+
+		  % echo 0x43fff > /sys/class/net/wlan0/device/debug_level
+
+	  You can find the list of debug mask values in:
+		  drivers/net/wireless/iwlegacy/common.h
+
+	  If this is your first time using this driver, you should say Y here
+	  as the debug information can assist others in helping you resolve
+	  any problems you may encounter.
+
+config IWLEGACY_DEBUGFS
+        bool "iwlegacy (iwl 3945/4965) debugfs support"
+        depends on IWLEGACY && MAC80211_DEBUGFS
+        ---help---
+	  Enable creation of debugfs files for the iwlegacy drivers. This
+	  is a low-impact option that allows getting insight into the
+	  driver's state at runtime.
+
+endmenu
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index 04ec38e..b42052b 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -81,7 +81,7 @@
 }
 EXPORT_SYMBOL(il_clear_bit);
 
-int
+bool
 _il_grab_nic_access(struct il_priv *il)
 {
 	int ret;
@@ -111,14 +111,15 @@
 	    _il_poll_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
 			 (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
 			  CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
-	if (ret < 0) {
+	if (unlikely(ret < 0)) {
 		val = _il_rd(il, CSR_GP_CNTRL);
-		IL_ERR("MAC is in deep sleep!.  CSR_GP_CNTRL = 0x%08X\n", val);
+		WARN_ONCE(1, "Timeout waiting for ucode processor access "
+			     "(CSR_GP_CNTRL 0x%08x)\n", val);
 		_il_wr(il, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
-		return -EIO;
+		return false;
 	}
 
-	return 0;
+	return true;
 }
 EXPORT_SYMBOL_GPL(_il_grab_nic_access);
 
@@ -160,7 +161,7 @@
 	unsigned long reg_flags;
 
 	spin_lock_irqsave(&il->reg_lock, reg_flags);
-	if (!_il_grab_nic_access(il)) {
+	if (likely(_il_grab_nic_access(il))) {
 		_il_wr_prph(il, addr, val);
 		_il_release_nic_access(il);
 	}
@@ -178,7 +179,6 @@
 	_il_grab_nic_access(il);
 
 	_il_wr(il, HBUS_TARG_MEM_RADDR, addr);
-	rmb();
 	value = _il_rd(il, HBUS_TARG_MEM_RDAT);
 
 	_il_release_nic_access(il);
@@ -193,9 +193,8 @@
 	unsigned long reg_flags;
 
 	spin_lock_irqsave(&il->reg_lock, reg_flags);
-	if (!_il_grab_nic_access(il)) {
+	if (likely(_il_grab_nic_access(il))) {
 		_il_wr(il, HBUS_TARG_MEM_WADDR, addr);
-		wmb();
 		_il_wr(il, HBUS_TARG_MEM_WDAT, val);
 		_il_release_nic_access(il);
 	}
@@ -351,7 +350,7 @@
 		}
 	}
 
-	if (test_bit(S_RF_KILL_HW, &il->status)) {
+	if (test_bit(S_RFKILL, &il->status)) {
 		IL_ERR("Command %s aborted: RF KILL Switch\n",
 		       il_get_cmd_string(cmd->id));
 		ret = -ECANCELED;
@@ -520,7 +519,7 @@
 	    il_blink_compensation(il, off,
 				  il->cfg->led_compensation);
 
-	ret = il->ops->led->cmd(il, &led_cmd);
+	ret = il->ops->send_led_cmd(il, &led_cmd);
 	if (!ret) {
 		il->blink_on = on;
 		il->blink_off = off;
@@ -731,7 +730,7 @@
 	}
 	e = (__le16 *) il->eeprom;
 
-	il->ops->lib->apm_ops.init(il);
+	il->ops->apm_init(il);
 
 	ret = il_eeprom_verify_signature(il);
 	if (ret < 0) {
@@ -741,7 +740,7 @@
 	}
 
 	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
-	ret = il->ops->lib->eeprom_ops.acquire_semaphore(il);
+	ret = il->ops->eeprom_acquire_semaphore(il);
 	if (ret < 0) {
 		IL_ERR("Failed to acquire EEPROM semaphore.\n");
 		ret = -ENOENT;
@@ -773,7 +772,7 @@
 
 	ret = 0;
 done:
-	il->ops->lib->eeprom_ops.release_semaphore(il);
+	il->ops->eeprom_release_semaphore(il);
 
 err:
 	if (ret)
@@ -799,8 +798,8 @@
 		       const struct il_eeprom_channel **eeprom_ch_info,
 		       const u8 **eeprom_ch_idx)
 {
-	u32 offset =
-	    il->ops->lib->eeprom_ops.regulatory_bands[eep_band - 1];
+	u32 offset = il->cfg->regulatory_bands[eep_band - 1];
+
 	switch (eep_band) {
 	case 1:		/* 2.4GHz band */
 		*eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_1);
@@ -1001,10 +1000,8 @@
 	}
 
 	/* Check if we do have HT40 channels */
-	if (il->ops->lib->eeprom_ops.regulatory_bands[5] ==
-	    EEPROM_REGULATORY_BAND_NO_HT40 &&
-	    il->ops->lib->eeprom_ops.regulatory_bands[6] ==
-	    EEPROM_REGULATORY_BAND_NO_HT40)
+	if (il->cfg->regulatory_bands[5] == EEPROM_REGULATORY_BAND_NO_HT40 &&
+	    il->cfg->regulatory_bands[6] == EEPROM_REGULATORY_BAND_NO_HT40)
 		return 0;
 
 	/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
@@ -1158,9 +1155,9 @@
 		if (!(cmd->flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK))
 			clear_bit(S_POWER_PMI, &il->status);
 
-		if (il->ops->lib->update_chain_flags && update_chains)
-			il->ops->lib->update_chain_flags(il);
-		else if (il->ops->lib->update_chain_flags)
+		if (il->ops->update_chain_flags && update_chains)
+			il->ops->update_chain_flags(il);
+		else if (il->ops->update_chain_flags)
 			D_POWER("Cannot update the power, chain noise "
 				"calibration running: %d\n",
 				il->chain_noise_data.state);
@@ -1485,9 +1482,6 @@
 
 	lockdep_assert_held(&il->mutex);
 
-	if (WARN_ON(!il->ops->utils->request_scan))
-		return -EOPNOTSUPP;
-
 	cancel_delayed_work(&il->scan_check);
 
 	if (!il_is_ready_rf(il)) {
@@ -1510,7 +1504,7 @@
 	set_bit(S_SCANNING, &il->status);
 	il->scan_start = jiffies;
 
-	ret = il->ops->utils->request_scan(il, vif);
+	ret = il->ops->request_scan(il, vif);
 	if (ret) {
 		clear_bit(S_SCANNING, &il->status);
 		return ret;
@@ -1529,12 +1523,13 @@
 	struct il_priv *il = hw->priv;
 	int ret;
 
-	D_MAC80211("enter\n");
-
-	if (req->n_channels == 0)
+	if (req->n_channels == 0) {
+		IL_ERR("Can not scan on no channels.\n");
 		return -EINVAL;
+	}
 
 	mutex_lock(&il->mutex);
+	D_MAC80211("enter\n");
 
 	if (test_bit(S_SCANNING, &il->status)) {
 		D_SCAN("Scan already in progress.\n");
@@ -1549,9 +1544,8 @@
 
 	ret = il_scan_initiate(il, vif);
 
-	D_MAC80211("leave\n");
-
 out_unlock:
+	D_MAC80211("leave ret %d\n", ret);
 	mutex_unlock(&il->mutex);
 
 	return ret;
@@ -1672,7 +1666,7 @@
 	il_power_set_mode(il, &il->power_data.sleep_cmd_next, false);
 	il_set_tx_power(il, il->tx_power_next, false);
 
-	il->ops->utils->post_scan(il);
+	il->ops->post_scan(il);
 
 out:
 	mutex_unlock(&il->mutex);
@@ -1814,7 +1808,7 @@
 		might_sleep();
 	}
 
-	cmd.len = il->ops->utils->build_addsta_hcmd(sta, data);
+	cmd.len = il->ops->build_addsta_hcmd(sta, data);
 	ret = il_send_cmd(il, &cmd);
 
 	if (ret || (flags & CMD_ASYNC))
@@ -2419,13 +2413,16 @@
 	struct il_station_priv_common *sta_common = (void *)sta->drv_priv;
 	int ret;
 
-	D_INFO("received request to remove station %pM\n", sta->addr);
 	mutex_lock(&il->mutex);
-	D_INFO("proceeding to remove station %pM\n", sta->addr);
+	D_MAC80211("enter station %pM\n", sta->addr);
+
 	ret = il_remove_station(il, sta_common->sta_id, sta->addr);
 	if (ret)
 		IL_ERR("Error removing station %pM\n", sta->addr);
+
+	D_MAC80211("leave ret %d\n", ret);
 	mutex_unlock(&il->mutex);
+
 	return ret;
 }
 EXPORT_SYMBOL(il_mac_sta_remove);
@@ -2722,7 +2719,7 @@
 		return;
 
 	while (q->write_ptr != q->read_ptr) {
-		il->ops->lib->txq_free_tfd(il, txq);
+		il->ops->txq_free_tfd(il, txq);
 		q->read_ptr = il_queue_inc_wrap(q->read_ptr, q->n_bd);
 	}
 }
@@ -2890,20 +2887,22 @@
  * il_queue_init - Initialize queue's high/low-water and read/write idxes
  */
 static int
-il_queue_init(struct il_priv *il, struct il_queue *q, int count, int slots_num,
-	      u32 id)
+il_queue_init(struct il_priv *il, struct il_queue *q, int slots, u32 id)
 {
-	q->n_bd = count;
-	q->n_win = slots_num;
+	/*
+	 * TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+	 * il_queue_inc_wrap and il_queue_dec_wrap are broken.
+	 */
+	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+	/* FIXME: remove q->n_bd */
+	q->n_bd = TFD_QUEUE_SIZE_MAX;
+
+	q->n_win = slots;
 	q->id = id;
 
-	/* count must be power-of-two size, otherwise il_queue_inc_wrap
-	 * and il_queue_dec_wrap are broken. */
-	BUG_ON(!is_power_of_2(count));
-
-	/* slots_num must be power-of-two size, otherwise
+	/* slots_must be power-of-two size, otherwise
 	 * il_get_cmd_idx is broken. */
-	BUG_ON(!is_power_of_2(slots_num));
+	BUG_ON(!is_power_of_2(slots));
 
 	q->low_mark = q->n_win / 4;
 	if (q->low_mark < 4)
@@ -2962,12 +2961,11 @@
  * il_tx_queue_init - Allocate and initialize one tx/cmd queue
  */
 int
-il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
-		 u32 txq_id)
+il_tx_queue_init(struct il_priv *il, u32 txq_id)
 {
-	int i, len;
-	int ret;
-	int actual_slots = slots_num;
+	int i, len, ret;
+	int slots, actual_slots;
+	struct il_tx_queue *txq = &il->txq[txq_id];
 
 	/*
 	 * Alloc buffer array for commands (Tx or other types of commands).
@@ -2977,8 +2975,13 @@
 	 * For normal Tx queues (all other queues), no super-size command
 	 * space is needed.
 	 */
-	if (txq_id == il->cmd_queue)
-		actual_slots++;
+	if (txq_id == il->cmd_queue) {
+		slots = TFD_CMD_SLOTS;
+		actual_slots = slots + 1;
+	} else {
+		slots = TFD_TX_CMD_SLOTS;
+		actual_slots = slots;
+	}
 
 	txq->meta =
 	    kzalloc(sizeof(struct il_cmd_meta) * actual_slots, GFP_KERNEL);
@@ -2991,7 +2994,7 @@
 	len = sizeof(struct il_device_cmd);
 	for (i = 0; i < actual_slots; i++) {
 		/* only happens for cmd queue */
-		if (i == slots_num)
+		if (i == slots)
 			len = IL_MAX_CMD_SIZE;
 
 		txq->cmd[i] = kmalloc(len, GFP_KERNEL);
@@ -3014,15 +3017,11 @@
 	if (txq_id < 4)
 		il_set_swq_id(txq, txq_id, txq_id);
 
-	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-	 * il_queue_inc_wrap and il_queue_dec_wrap are broken. */
-	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
 	/* Initialize queue's high/low-water marks, and head/tail idxes */
-	il_queue_init(il, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+	il_queue_init(il, &txq->q, slots, txq_id);
 
 	/* Tell device where to find queue */
-	il->ops->lib->txq_init(il, txq);
+	il->ops->txq_init(il, txq);
 
 	return 0;
 err:
@@ -3037,23 +3036,27 @@
 EXPORT_SYMBOL(il_tx_queue_init);
 
 void
-il_tx_queue_reset(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
-		  u32 txq_id)
+il_tx_queue_reset(struct il_priv *il, u32 txq_id)
 {
-	int actual_slots = slots_num;
+	int slots, actual_slots;
+	struct il_tx_queue *txq = &il->txq[txq_id];
 
-	if (txq_id == il->cmd_queue)
-		actual_slots++;
+	if (txq_id == il->cmd_queue) {
+		slots = TFD_CMD_SLOTS;
+		actual_slots = TFD_CMD_SLOTS + 1;
+	} else {
+		slots = TFD_TX_CMD_SLOTS;
+		actual_slots = TFD_TX_CMD_SLOTS;
+	}
 
 	memset(txq->meta, 0, sizeof(struct il_cmd_meta) * actual_slots);
-
 	txq->need_update = 0;
 
 	/* Initialize queue's high/low-water marks, and head/tail idxes */
-	il_queue_init(il, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+	il_queue_init(il, &txq->q, slots, txq_id);
 
 	/* Tell device where to find queue */
-	il->ops->lib->txq_init(il, txq);
+	il->ops->txq_init(il, txq);
 }
 EXPORT_SYMBOL(il_tx_queue_reset);
 
@@ -3081,7 +3084,7 @@
 	u32 idx;
 	u16 fix_size;
 
-	cmd->len = il->ops->utils->get_hcmd_size(cmd->id, cmd->len);
+	cmd->len = il->ops->get_hcmd_size(cmd->id, cmd->len);
 	fix_size = (u16) (cmd->len + sizeof(out_cmd->hdr));
 
 	/* If any of the command structures end up being larger than
@@ -3160,9 +3163,9 @@
 #endif
 	txq->need_update = 1;
 
-	if (il->ops->lib->txq_update_byte_cnt_tbl)
+	if (il->ops->txq_update_byte_cnt_tbl)
 		/* Set up entry in queue's byte count circular buffer */
-		il->ops->lib->txq_update_byte_cnt_tbl(il, txq, 0);
+		il->ops->txq_update_byte_cnt_tbl(il, txq, 0);
 
 	phys_addr =
 	    pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size,
@@ -3170,7 +3173,7 @@
 	dma_unmap_addr_set(out_meta, mapping, phys_addr);
 	dma_unmap_len_set(out_meta, len, fix_size);
 
-	il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
+	il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
 					    U32_PAD(cmd->len));
 
 	/* Increment and update queue's write idx */
@@ -3845,8 +3848,8 @@
 		rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
 	}
 
-	if (il->ops->hcmd->set_rxon_chain)
-		il->ops->hcmd->set_rxon_chain(il);
+	if (il->ops->set_rxon_chain)
+		il->ops->set_rxon_chain(il);
 
 	D_ASSOC("rxon flags 0x%X operation mode :0x%X "
 		"extension channel offset 0x%x\n", le32_to_cpu(rxon->flags),
@@ -4104,9 +4107,9 @@
 
 	IL_ERR("Loaded firmware version: %s\n", il->hw->wiphy->fw_version);
 
-	il->ops->lib->dump_nic_error_log(il);
-	if (il->ops->lib->dump_fh)
-		il->ops->lib->dump_fh(il, NULL, false);
+	il->ops->dump_nic_error_log(il);
+	if (il->ops->dump_fh)
+		il->ops->dump_fh(il, NULL, false);
 #ifdef CONFIG_IWLEGACY_DEBUG
 	if (il_get_debug_level(il) & IL_DL_FW_ERRORS)
 		il_print_rx_config_cmd(il);
@@ -4129,17 +4132,17 @@
 EXPORT_SYMBOL(il_irq_handle_error);
 
 static int
-il_apm_stop_master(struct il_priv *il)
+_il_apm_stop_master(struct il_priv *il)
 {
 	int ret = 0;
 
 	/* stop device's busmaster DMA activity */
-	il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+	_il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
 	ret =
 	    _il_poll_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED,
 			 CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-	if (ret)
+	if (ret < 0)
 		IL_WARN("Master Disable Timed Out, 100 usec\n");
 
 	D_INFO("stop master\n");
@@ -4148,15 +4151,17 @@
 }
 
 void
-il_apm_stop(struct il_priv *il)
+_il_apm_stop(struct il_priv *il)
 {
+	lockdep_assert_held(&il->reg_lock);
+
 	D_INFO("Stop card, put in low power state\n");
 
 	/* Stop device's DMA activity */
-	il_apm_stop_master(il);
+	_il_apm_stop_master(il);
 
 	/* Reset the entire device */
-	il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	_il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
 	udelay(10);
 
@@ -4164,7 +4169,18 @@
 	 * Clear "initialization complete" bit to move adapter from
 	 * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
 	 */
-	il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	_il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+}
+EXPORT_SYMBOL(_il_apm_stop);
+
+void
+il_apm_stop(struct il_priv *il)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&il->reg_lock, flags);
+	_il_apm_stop(il);
+	spin_unlock_irqrestore(&il->reg_lock, flags);
 }
 EXPORT_SYMBOL(il_apm_stop);
 
@@ -4293,7 +4309,7 @@
 	if (il->tx_power_user_lmt == tx_power && !force)
 		return 0;
 
-	if (!il->ops->lib->send_tx_power)
+	if (!il->ops->send_tx_power)
 		return -EOPNOTSUPP;
 
 	/* 0 dBm mean 1 milliwatt */
@@ -4326,7 +4342,7 @@
 	prev_tx_power = il->tx_power_user_lmt;
 	il->tx_power_user_lmt = tx_power;
 
-	ret = il->ops->lib->send_tx_power(il);
+	ret = il->ops->send_tx_power(il);
 
 	/* if fail to set tx_power, restore the orig. tx power */
 	if (ret) {
@@ -4465,8 +4481,14 @@
 il_mac_tx_last_beacon(struct ieee80211_hw *hw)
 {
 	struct il_priv *il = hw->priv;
+	int ret;
 
-	return il->ibss_manager == IL_IBSS_MANAGER;
+	D_MAC80211("enter\n");
+
+	ret = (il->ibss_manager == IL_IBSS_MANAGER);
+
+	D_MAC80211("leave ret %d\n", ret);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(il_mac_tx_last_beacon);
 
@@ -4475,8 +4497,8 @@
 {
 	il_connection_init_rx_config(il);
 
-	if (il->ops->hcmd->set_rxon_chain)
-		il->ops->hcmd->set_rxon_chain(il);
+	if (il->ops->set_rxon_chain)
+		il->ops->set_rxon_chain(il);
 
 	return il_commit_rxon(il);
 }
@@ -4487,9 +4509,8 @@
 	struct il_priv *il = hw->priv;
 	int err;
 
-	D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
-
 	mutex_lock(&il->mutex);
+	D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
 
 	if (!il_is_ready_rf(il)) {
 		IL_WARN("Try to add interface when device not ready\n");
@@ -4512,9 +4533,9 @@
 	}
 
 out:
+	D_MAC80211("leave err %d\n", err);
 	mutex_unlock(&il->mutex);
 
-	D_MAC80211("leave\n");
 	return err;
 }
 EXPORT_SYMBOL(il_mac_add_interface);
@@ -4540,20 +4561,17 @@
 {
 	struct il_priv *il = hw->priv;
 
-	D_MAC80211("enter\n");
-
 	mutex_lock(&il->mutex);
+	D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
 
 	WARN_ON(il->vif != vif);
 	il->vif = NULL;
 
 	il_teardown_interface(il, vif, false);
-
 	memset(il->bssid, 0, ETH_ALEN);
-	mutex_unlock(&il->mutex);
 
 	D_MAC80211("leave\n");
-
+	mutex_unlock(&il->mutex);
 }
 EXPORT_SYMBOL(il_mac_remove_interface);
 
@@ -4573,259 +4591,12 @@
 EXPORT_SYMBOL(il_alloc_txq_mem);
 
 void
-il_txq_mem(struct il_priv *il)
+il_free_txq_mem(struct il_priv *il)
 {
 	kfree(il->txq);
 	il->txq = NULL;
 }
-EXPORT_SYMBOL(il_txq_mem);
-
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-
-#define IL_TRAFFIC_DUMP_SIZE	(IL_TRAFFIC_ENTRY_SIZE * IL_TRAFFIC_ENTRIES)
-
-void
-il_reset_traffic_log(struct il_priv *il)
-{
-	il->tx_traffic_idx = 0;
-	il->rx_traffic_idx = 0;
-	if (il->tx_traffic)
-		memset(il->tx_traffic, 0, IL_TRAFFIC_DUMP_SIZE);
-	if (il->rx_traffic)
-		memset(il->rx_traffic, 0, IL_TRAFFIC_DUMP_SIZE);
-}
-
-int
-il_alloc_traffic_mem(struct il_priv *il)
-{
-	u32 traffic_size = IL_TRAFFIC_DUMP_SIZE;
-
-	if (il_debug_level & IL_DL_TX) {
-		if (!il->tx_traffic) {
-			il->tx_traffic = kzalloc(traffic_size, GFP_KERNEL);
-			if (!il->tx_traffic)
-				return -ENOMEM;
-		}
-	}
-	if (il_debug_level & IL_DL_RX) {
-		if (!il->rx_traffic) {
-			il->rx_traffic = kzalloc(traffic_size, GFP_KERNEL);
-			if (!il->rx_traffic)
-				return -ENOMEM;
-		}
-	}
-	il_reset_traffic_log(il);
-	return 0;
-}
-EXPORT_SYMBOL(il_alloc_traffic_mem);
-
-void
-il_free_traffic_mem(struct il_priv *il)
-{
-	kfree(il->tx_traffic);
-	il->tx_traffic = NULL;
-
-	kfree(il->rx_traffic);
-	il->rx_traffic = NULL;
-}
-EXPORT_SYMBOL(il_free_traffic_mem);
-
-void
-il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
-			 struct ieee80211_hdr *header)
-{
-	__le16 fc;
-	u16 len;
-
-	if (likely(!(il_debug_level & IL_DL_TX)))
-		return;
-
-	if (!il->tx_traffic)
-		return;
-
-	fc = header->frame_control;
-	if (ieee80211_is_data(fc)) {
-		len =
-		    (length >
-		     IL_TRAFFIC_ENTRY_SIZE) ? IL_TRAFFIC_ENTRY_SIZE : length;
-		memcpy((il->tx_traffic +
-			(il->tx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)), header,
-		       len);
-		il->tx_traffic_idx =
-		    (il->tx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES;
-	}
-}
-EXPORT_SYMBOL(il_dbg_log_tx_data_frame);
-
-void
-il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
-			 struct ieee80211_hdr *header)
-{
-	__le16 fc;
-	u16 len;
-
-	if (likely(!(il_debug_level & IL_DL_RX)))
-		return;
-
-	if (!il->rx_traffic)
-		return;
-
-	fc = header->frame_control;
-	if (ieee80211_is_data(fc)) {
-		len =
-		    (length >
-		     IL_TRAFFIC_ENTRY_SIZE) ? IL_TRAFFIC_ENTRY_SIZE : length;
-		memcpy((il->rx_traffic +
-			(il->rx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)), header,
-		       len);
-		il->rx_traffic_idx =
-		    (il->rx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES;
-	}
-}
-EXPORT_SYMBOL(il_dbg_log_rx_data_frame);
-
-const char *
-il_get_mgmt_string(int cmd)
-{
-	switch (cmd) {
-		IL_CMD(MANAGEMENT_ASSOC_REQ);
-		IL_CMD(MANAGEMENT_ASSOC_RESP);
-		IL_CMD(MANAGEMENT_REASSOC_REQ);
-		IL_CMD(MANAGEMENT_REASSOC_RESP);
-		IL_CMD(MANAGEMENT_PROBE_REQ);
-		IL_CMD(MANAGEMENT_PROBE_RESP);
-		IL_CMD(MANAGEMENT_BEACON);
-		IL_CMD(MANAGEMENT_ATIM);
-		IL_CMD(MANAGEMENT_DISASSOC);
-		IL_CMD(MANAGEMENT_AUTH);
-		IL_CMD(MANAGEMENT_DEAUTH);
-		IL_CMD(MANAGEMENT_ACTION);
-	default:
-		return "UNKNOWN";
-
-	}
-}
-
-const char *
-il_get_ctrl_string(int cmd)
-{
-	switch (cmd) {
-		IL_CMD(CONTROL_BACK_REQ);
-		IL_CMD(CONTROL_BACK);
-		IL_CMD(CONTROL_PSPOLL);
-		IL_CMD(CONTROL_RTS);
-		IL_CMD(CONTROL_CTS);
-		IL_CMD(CONTROL_ACK);
-		IL_CMD(CONTROL_CFEND);
-		IL_CMD(CONTROL_CFENDACK);
-	default:
-		return "UNKNOWN";
-
-	}
-}
-
-void
-il_clear_traffic_stats(struct il_priv *il)
-{
-	memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
-	memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
-}
-
-/*
- * if CONFIG_IWLEGACY_DEBUGFS defined,
- * il_update_stats function will
- * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass
- * Use debugFs to display the rx/rx_stats
- * if CONFIG_IWLEGACY_DEBUGFS not being defined, then no MGMT and CTRL
- * information will be recorded, but DATA pkt still will be recorded
- * for the reason of il_led.c need to control the led blinking based on
- * number of tx and rx data.
- *
- */
-void
-il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
-{
-	struct traffic_stats *stats;
-
-	if (is_tx)
-		stats = &il->tx_stats;
-	else
-		stats = &il->rx_stats;
-
-	if (ieee80211_is_mgmt(fc)) {
-		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
-			stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
-			stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
-			stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
-			stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
-			stats->mgmt[MANAGEMENT_PROBE_REQ]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
-			stats->mgmt[MANAGEMENT_PROBE_RESP]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_BEACON):
-			stats->mgmt[MANAGEMENT_BEACON]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_ATIM):
-			stats->mgmt[MANAGEMENT_ATIM]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
-			stats->mgmt[MANAGEMENT_DISASSOC]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_AUTH):
-			stats->mgmt[MANAGEMENT_AUTH]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
-			stats->mgmt[MANAGEMENT_DEAUTH]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_ACTION):
-			stats->mgmt[MANAGEMENT_ACTION]++;
-			break;
-		}
-	} else if (ieee80211_is_ctl(fc)) {
-		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-		case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
-			stats->ctrl[CONTROL_BACK_REQ]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_BACK):
-			stats->ctrl[CONTROL_BACK]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
-			stats->ctrl[CONTROL_PSPOLL]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_RTS):
-			stats->ctrl[CONTROL_RTS]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_CTS):
-			stats->ctrl[CONTROL_CTS]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_ACK):
-			stats->ctrl[CONTROL_ACK]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_CFEND):
-			stats->ctrl[CONTROL_CFEND]++;
-			break;
-		case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
-			stats->ctrl[CONTROL_CFENDACK]++;
-			break;
-		}
-	} else {
-		/* data */
-		stats->data_cnt++;
-		stats->data_bytes += len;
-	}
-}
-EXPORT_SYMBOL(il_update_stats);
-#endif
+EXPORT_SYMBOL(il_free_txq_mem);
 
 int
 il_force_reset(struct il_priv *il, bool external)
@@ -4886,10 +4657,14 @@
 	struct il_priv *il = hw->priv;
 	int err;
 
-	if (newp2p)
-		return -EOPNOTSUPP;
-
 	mutex_lock(&il->mutex);
+	D_MAC80211("enter: type %d, addr %pM newtype %d newp2p %d\n",
+		    vif->type, vif->addr, newtype, newp2p);
+
+	if (newp2p) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
 
 	if (!il->vif || !il_is_ready_rf(il)) {
 		/*
@@ -4916,7 +4691,9 @@
 	err = 0;
 
 out:
+	D_MAC80211("leave err %d\n", err);
 	mutex_unlock(&il->mutex);
+
 	return err;
 }
 EXPORT_SYMBOL(il_mac_change_interface);
@@ -5113,9 +4890,9 @@
 		hw_rfkill = true;
 
 	if (hw_rfkill)
-		set_bit(S_RF_KILL_HW, &il->status);
+		set_bit(S_RFKILL, &il->status);
 	else
-		clear_bit(S_RF_KILL_HW, &il->status);
+		clear_bit(S_RFKILL, &il->status);
 
 	wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rfkill);
 
@@ -5174,12 +4951,8 @@
 	int scan_active = 0;
 	bool ht_changed = false;
 
-	if (WARN_ON(!il->ops->legacy))
-		return -EOPNOTSUPP;
-
 	mutex_lock(&il->mutex);
-
-	D_MAC80211("enter to channel %d changed 0x%X\n", channel->hw_value,
+	D_MAC80211("enter: channel %d changed 0x%X\n", channel->hw_value,
 		   changed);
 
 	if (unlikely(test_bit(S_SCANNING, &il->status))) {
@@ -5199,8 +4972,8 @@
 		 * set up the SM PS mode to OFF if an HT channel is
 		 * configured.
 		 */
-		if (il->ops->hcmd->set_rxon_chain)
-			il->ops->hcmd->set_rxon_chain(il);
+		if (il->ops->set_rxon_chain)
+			il->ops->set_rxon_chain(il);
 	}
 
 	/* during scanning mac80211 will delay channel setting until
@@ -5269,8 +5042,8 @@
 
 		spin_unlock_irqrestore(&il->lock, flags);
 
-		if (il->ops->legacy->update_bcast_stations)
-			ret = il->ops->legacy->update_bcast_stations(il);
+		if (il->ops->update_bcast_stations)
+			ret = il->ops->update_bcast_stations(il);
 
 set_ch_out:
 		/* The list of supported rates and rate mask can be different
@@ -5308,8 +5081,9 @@
 		il_update_qos(il);
 
 out:
-	D_MAC80211("leave\n");
+	D_MAC80211("leave ret %d\n", ret);
 	mutex_unlock(&il->mutex);
+
 	return ret;
 }
 EXPORT_SYMBOL(il_mac_config);
@@ -5320,24 +5094,17 @@
 	struct il_priv *il = hw->priv;
 	unsigned long flags;
 
-	if (WARN_ON(!il->ops->legacy))
-		return;
-
 	mutex_lock(&il->mutex);
-	D_MAC80211("enter\n");
+	D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
 
 	spin_lock_irqsave(&il->lock, flags);
+
 	memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));
-	spin_unlock_irqrestore(&il->lock, flags);
-
-	spin_lock_irqsave(&il->lock, flags);
 
 	/* new association get rid of ibss beacon skb */
 	if (il->beacon_skb)
 		dev_kfree_skb(il->beacon_skb);
-
 	il->beacon_skb = NULL;
-
 	il->timestamp = 0;
 
 	spin_unlock_irqrestore(&il->lock, flags);
@@ -5349,17 +5116,14 @@
 		return;
 	}
 
-	/* we are restarting association process
-	 * clear RXON_FILTER_ASSOC_MSK bit
-	 */
+	/* we are restarting association process */
 	il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 	il_commit_rxon(il);
 
 	il_set_rate(il);
 
-	mutex_unlock(&il->mutex);
-
 	D_MAC80211("leave\n");
+	mutex_unlock(&il->mutex);
 }
 EXPORT_SYMBOL(il_mac_reset_tsf);
 
@@ -5475,7 +5239,7 @@
 		return;
 	}
 
-	il->ops->legacy->post_associate(il);
+	il->ops->post_associate(il);
 }
 
 void
@@ -5485,14 +5249,11 @@
 	struct il_priv *il = hw->priv;
 	int ret;
 
-	if (WARN_ON(!il->ops->legacy))
-		return;
-
-	D_MAC80211("changes = 0x%X\n", changes);
-
 	mutex_lock(&il->mutex);
+	D_MAC80211("enter: changes 0x%x\n", changes);
 
 	if (!il_is_alive(il)) {
+		D_MAC80211("leave - not alive\n");
 		mutex_unlock(&il->mutex);
 		return;
 	}
@@ -5523,8 +5284,7 @@
 		 * below/in post_associate will fail.
 		 */
 		if (il_scan_cancel_timeout(il, 100)) {
-			IL_WARN("Aborted scan still in progress after 100ms\n");
-			D_MAC80211("leaving - scan abort failed.\n");
+			D_MAC80211("leave - scan abort failed\n");
 			mutex_unlock(&il->mutex);
 			return;
 		}
@@ -5536,10 +5296,8 @@
 
 			/* currently needed in a few places */
 			memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
-		} else {
+		} else
 			il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		}
-
 	}
 
 	/*
@@ -5590,8 +5348,8 @@
 	if (changes & BSS_CHANGED_HT) {
 		il_ht_conf(il, vif);
 
-		if (il->ops->hcmd->set_rxon_chain)
-			il->ops->hcmd->set_rxon_chain(il);
+		if (il->ops->set_rxon_chain)
+			il->ops->set_rxon_chain(il);
 	}
 
 	if (changes & BSS_CHANGED_ASSOC) {
@@ -5600,7 +5358,7 @@
 			il->timestamp = bss_conf->timestamp;
 
 			if (!il_is_rfkill(il))
-				il->ops->legacy->post_associate(il);
+				il->ops->post_associate(il);
 		} else
 			il_set_no_assoc(il, vif);
 	}
@@ -5620,24 +5378,22 @@
 			memcpy(il->staging.bssid_addr, bss_conf->bssid,
 			       ETH_ALEN);
 			memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
-			il->ops->legacy->config_ap(il);
+			il->ops->config_ap(il);
 		} else
 			il_set_no_assoc(il, vif);
 	}
 
 	if (changes & BSS_CHANGED_IBSS) {
-		ret =
-		    il->ops->legacy->manage_ibss_station(il, vif,
-							 bss_conf->ibss_joined);
+		ret = il->ops->manage_ibss_station(il, vif,
+						   bss_conf->ibss_joined);
 		if (ret)
 			IL_ERR("failed to %s IBSS station %pM\n",
 			       bss_conf->ibss_joined ? "add" : "remove",
 			       bss_conf->bssid);
 	}
 
-	mutex_unlock(&il->mutex);
-
 	D_MAC80211("leave\n");
+	mutex_unlock(&il->mutex);
 }
 EXPORT_SYMBOL(il_mac_bss_info_changed);
 
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index 7080956..5f50177 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -425,12 +425,6 @@
 
 #define EEPROM_REGULATORY_BAND_NO_HT40			(0)
 
-struct il_eeprom_ops {
-	const u32 regulatory_bands[7];
-	int (*acquire_semaphore) (struct il_priv *il);
-	void (*release_semaphore) (struct il_priv *il);
-};
-
 int il_eeprom_init(struct il_priv *il);
 void il_eeprom_free(struct il_priv *il);
 const u8 *il_eeprom_query_addr(const struct il_priv *il, size_t offset);
@@ -962,26 +956,6 @@
 	IL_CHAIN_NOISE_DONE,
 };
 
-enum il4965_calib_enabled_state {
-	IL_CALIB_DISABLED = 0,	/* must be 0 */
-	IL_CALIB_ENABLED = 1,
-};
-
-/*
- * enum il_calib
- * defines the order in which results of initial calibrations
- * should be sent to the runtime uCode
- */
-enum il_calib {
-	IL_CALIB_MAX,
-};
-
-/* Opaque calibration results */
-struct il_calib_result {
-	void *buf;
-	size_t buf_len;
-};
-
 enum ucode_type {
 	UCODE_NONE = 0,
 	UCODE_INIT,
@@ -1156,13 +1130,15 @@
 };
 
 struct il_priv {
-
-	/* ieee device used by generic ieee processing code */
 	struct ieee80211_hw *hw;
 	struct ieee80211_channel *ieee_channels;
 	struct ieee80211_rate *ieee_rates;
+
 	struct il_cfg *cfg;
 	const struct il_ops *ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+	const struct il_debugfs_ops *debugfs_ops;
+#endif
 
 	/* temporary frame storage list */
 	struct list_head free_frames;
@@ -1199,9 +1175,6 @@
 	s32 temperature;	/* degrees Kelvin */
 	s32 last_temperature;
 
-	/* init calibration results */
-	struct il_calib_result calib_results[IL_CALIB_MAX];
-
 	/* Scan related variables */
 	unsigned long scan_start;
 	unsigned long scan_start_tsf;
@@ -1557,24 +1530,6 @@
 #define IL_RX_BUF_SIZE_4K (4 * 1024)
 #define IL_RX_BUF_SIZE_8K (8 * 1024)
 
-struct il_hcmd_ops {
-	int (*rxon_assoc) (struct il_priv *il);
-	int (*commit_rxon) (struct il_priv *il);
-	void (*set_rxon_chain) (struct il_priv *il);
-};
-
-struct il_hcmd_utils_ops {
-	u16(*get_hcmd_size) (u8 cmd_id, u16 len);
-	u16(*build_addsta_hcmd) (const struct il_addsta_cmd *cmd, u8 *data);
-	int (*request_scan) (struct il_priv *il, struct ieee80211_vif *vif);
-	void (*post_scan) (struct il_priv *il);
-};
-
-struct il_apm_ops {
-	int (*init) (struct il_priv *il);
-	void (*config) (struct il_priv *il);
-};
-
 #ifdef CONFIG_IWLEGACY_DEBUGFS
 struct il_debugfs_ops {
 	ssize_t(*rx_stats_read) (struct file *file, char __user *user_buf,
@@ -1587,11 +1542,7 @@
 };
 #endif
 
-struct il_temp_ops {
-	void (*temperature) (struct il_priv *il);
-};
-
-struct il_lib_ops {
+struct il_ops {
 	/* Handling TX */
 	void (*txq_update_byte_cnt_tbl) (struct il_priv *il,
 					 struct il_tx_queue *txq,
@@ -1601,8 +1552,6 @@
 				      u16 len, u8 reset, u8 pad);
 	void (*txq_free_tfd) (struct il_priv *il, struct il_tx_queue *txq);
 	int (*txq_init) (struct il_priv *il, struct il_tx_queue *txq);
-	/* setup Rx handler */
-	void (*handler_setup) (struct il_priv *il);
 	/* alive notification after init uCode load */
 	void (*init_alive_start) (struct il_priv *il);
 	/* check validity of rtc data address */
@@ -1615,44 +1564,33 @@
 	int (*set_channel_switch) (struct il_priv *il,
 				   struct ieee80211_channel_switch *ch_switch);
 	/* power management */
-	struct il_apm_ops apm_ops;
+	int (*apm_init) (struct il_priv *il);
 
-	/* power */
+	/* tx power */
 	int (*send_tx_power) (struct il_priv *il);
 	void (*update_chain_flags) (struct il_priv *il);
 
 	/* eeprom operations */
-	struct il_eeprom_ops eeprom_ops;
+	int (*eeprom_acquire_semaphore) (struct il_priv *il);
+	void (*eeprom_release_semaphore) (struct il_priv *il);
 
-	/* temperature */
-	struct il_temp_ops temp_ops;
+	int (*rxon_assoc) (struct il_priv *il);
+	int (*commit_rxon) (struct il_priv *il);
+	void (*set_rxon_chain) (struct il_priv *il);
 
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-	struct il_debugfs_ops debugfs_ops;
-#endif
+	u16(*get_hcmd_size) (u8 cmd_id, u16 len);
+	u16(*build_addsta_hcmd) (const struct il_addsta_cmd *cmd, u8 *data);
 
-};
-
-struct il_led_ops {
-	int (*cmd) (struct il_priv *il, struct il_led_cmd *led_cmd);
-};
-
-struct il_legacy_ops {
+	int (*request_scan) (struct il_priv *il, struct ieee80211_vif *vif);
+	void (*post_scan) (struct il_priv *il);
 	void (*post_associate) (struct il_priv *il);
 	void (*config_ap) (struct il_priv *il);
 	/* station management */
 	int (*update_bcast_stations) (struct il_priv *il);
 	int (*manage_ibss_station) (struct il_priv *il,
 				    struct ieee80211_vif *vif, bool add);
-};
 
-struct il_ops {
-	const struct il_lib_ops *lib;
-	const struct il_hcmd_ops *hcmd;
-	const struct il_hcmd_utils_ops *utils;
-	const struct il_led_ops *led;
-	const struct il_nic_ops *nic;
-	const struct il_legacy_ops *legacy;
+	int (*send_led_cmd) (struct il_priv *il, struct il_led_cmd *led_cmd);
 };
 
 struct il_mod_params {
@@ -1665,22 +1603,6 @@
 	int restart_fw;		/* def: 1 = restart firmware */
 };
 
-/*
- * @led_compensation: compensate on the led on/off time per HW according
- *	to the deviation to achieve the desired led frequency.
- *	The detail algorithm is described in common.c
- * @chain_noise_num_beacons: number of beacons used to compute chain noise
- * @wd_timeout: TX queues watchdog timeout
- * @temperature_kelvin: temperature report by uCode in kelvin
- * @ucode_tracing: support ucode continuous tracing
- * @sensitivity_calib_by_driver: driver has the capability to perform
- *	sensitivity calibration operation
- * @chain_noise_calib_by_driver: driver has the capability to perform
- *	chain noise calibration operation
- */
-struct il_base_params {
-};
-
 #define IL_LED_SOLID 11
 #define IL_DEF_LED_INTRVL cpu_to_le32(1000)
 
@@ -1769,6 +1691,8 @@
 	const bool ucode_tracing;
 	const bool sensitivity_calib_by_driver;
 	const bool chain_noise_calib_by_driver;
+
+	const u32 regulatory_bands[7];
 };
 
 /***************************
@@ -1800,60 +1724,24 @@
 int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			    enum nl80211_iftype newtype, bool newp2p);
 int il_alloc_txq_mem(struct il_priv *il);
-void il_txq_mem(struct il_priv *il);
+void il_free_txq_mem(struct il_priv *il);
 
 #ifdef CONFIG_IWLEGACY_DEBUGFS
-int il_alloc_traffic_mem(struct il_priv *il);
-void il_free_traffic_mem(struct il_priv *il);
-void il_reset_traffic_log(struct il_priv *il);
-void il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
-			      struct ieee80211_hdr *header);
-void il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
-			      struct ieee80211_hdr *header);
-const char *il_get_mgmt_string(int cmd);
-const char *il_get_ctrl_string(int cmd);
-void il_clear_traffic_stats(struct il_priv *il);
-void il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len);
+extern void il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len);
 #else
-static inline int
-il_alloc_traffic_mem(struct il_priv *il)
-{
-	return 0;
-}
-
-static inline void
-il_free_traffic_mem(struct il_priv *il)
-{
-}
-
-static inline void
-il_reset_traffic_log(struct il_priv *il)
-{
-}
-
-static inline void
-il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
-			 struct ieee80211_hdr *header)
-{
-}
-
-static inline void
-il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
-			 struct ieee80211_hdr *header)
-{
-}
-
 static inline void
 il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
 {
 }
 #endif
+
 /*****************************************************
- * RX handlers.
- * **************************************************/
+ * Handlers
+ ***************************************************/
 void il_hdl_pm_sleep(struct il_priv *il, struct il_rx_buf *rxb);
 void il_hdl_pm_debug_stats(struct il_priv *il, struct il_rx_buf *rxb);
 void il_hdl_error(struct il_priv *il, struct il_rx_buf *rxb);
+void il_hdl_csa(struct il_priv *il, struct il_rx_buf *rxb);
 
 /*****************************************************
 * RX
@@ -1864,25 +1752,20 @@
 void il_rx_queue_update_write_ptr(struct il_priv *il, struct il_rx_queue *q);
 int il_rx_queue_space(const struct il_rx_queue *q);
 void il_tx_cmd_complete(struct il_priv *il, struct il_rx_buf *rxb);
-/* Handlers */
+
 void il_hdl_spectrum_measurement(struct il_priv *il, struct il_rx_buf *rxb);
 void il_recover_from_stats(struct il_priv *il, struct il_rx_pkt *pkt);
 void il_chswitch_done(struct il_priv *il, bool is_success);
-void il_hdl_csa(struct il_priv *il, struct il_rx_buf *rxb);
-
-/* TX helpers */
 
 /*****************************************************
 * TX
 ******************************************************/
-void il_txq_update_write_ptr(struct il_priv *il, struct il_tx_queue *txq);
-int il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
-		     u32 txq_id);
-void il_tx_queue_reset(struct il_priv *il, struct il_tx_queue *txq,
-		       int slots_num, u32 txq_id);
-void il_tx_queue_unmap(struct il_priv *il, int txq_id);
-void il_tx_queue_free(struct il_priv *il, int txq_id);
-void il_setup_watchdog(struct il_priv *il);
+extern void il_txq_update_write_ptr(struct il_priv *il, struct il_tx_queue *txq);
+extern int il_tx_queue_init(struct il_priv *il, u32 txq_id);
+extern void il_tx_queue_reset(struct il_priv *il, u32 txq_id);
+extern void il_tx_queue_unmap(struct il_priv *il, int txq_id);
+extern void il_tx_queue_free(struct il_priv *il, int txq_id);
+extern void il_setup_watchdog(struct il_priv *il);
 /*****************************************************
  * TX power
  ****************************************************/
@@ -2000,7 +1883,7 @@
 #define S_HCMD_ACTIVE	0	/* host command in progress */
 /* 1 is unused (used to be S_HCMD_SYNC_ACTIVE) */
 #define S_INT_ENABLED	2
-#define S_RF_KILL_HW	3
+#define S_RFKILL	3
 #define S_CT_KILL		4
 #define S_INIT		5
 #define S_ALIVE		6
@@ -2039,15 +1922,9 @@
 }
 
 static inline int
-il_is_rfkill_hw(struct il_priv *il)
-{
-	return test_bit(S_RF_KILL_HW, &il->status);
-}
-
-static inline int
 il_is_rfkill(struct il_priv *il)
 {
-	return il_is_rfkill_hw(il);
+	return test_bit(S_RFKILL, &il->status);
 }
 
 static inline int
@@ -2068,7 +1945,9 @@
 
 extern void il_send_bt_config(struct il_priv *il);
 extern int il_send_stats_request(struct il_priv *il, u8 flags, bool clear);
-void il_apm_stop(struct il_priv *il);
+extern void il_apm_stop(struct il_priv *il);
+extern void _il_apm_stop(struct il_priv *il);
+
 int il_apm_init(struct il_priv *il);
 
 int il_send_rxon_timing(struct il_priv *il);
@@ -2076,13 +1955,13 @@
 static inline int
 il_send_rxon_assoc(struct il_priv *il)
 {
-	return il->ops->hcmd->rxon_assoc(il);
+	return il->ops->rxon_assoc(il);
 }
 
 static inline int
 il_commit_rxon(struct il_priv *il)
 {
-	return il->ops->hcmd->commit_rxon(il);
+	return il->ops->commit_rxon(il);
 }
 
 static inline const struct ieee80211_supported_band *
@@ -2103,7 +1982,7 @@
 
 extern void il_set_bit(struct il_priv *p, u32 r, u32 m);
 extern void il_clear_bit(struct il_priv *p, u32 r, u32 m);
-extern int _il_grab_nic_access(struct il_priv *il);
+extern bool _il_grab_nic_access(struct il_priv *il);
 extern int _il_poll_bit(struct il_priv *il, u32 addr, u32 bits, u32 mask, int timeout);
 extern int il_poll_bit(struct il_priv *il, u32 addr, u32 mask, int timeout);
 extern u32 il_rd_prph(struct il_priv *il, u32 reg);
@@ -2114,20 +1993,20 @@
 static inline void
 _il_write8(struct il_priv *il, u32 ofs, u8 val)
 {
-	iowrite8(val, il->hw_base + ofs);
+	writeb(val, il->hw_base + ofs);
 }
 #define il_write8(il, ofs, val) _il_write8(il, ofs, val)
 
 static inline void
 _il_wr(struct il_priv *il, u32 ofs, u32 val)
 {
-	iowrite32(val, il->hw_base + ofs);
+	writel(val, il->hw_base + ofs);
 }
 
 static inline u32
 _il_rd(struct il_priv *il, u32 ofs)
 {
-	return ioread32(il->hw_base + ofs);
+	return readl(il->hw_base + ofs);
 }
 
 static inline void
@@ -2146,6 +2025,13 @@
 _il_release_nic_access(struct il_priv *il)
 {
 	_il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	/*
+	 * In above we are reading CSR_GP_CNTRL register, what will flush any
+	 * previous writes, but still want write, which clear MAC_ACCESS_REQ
+	 * bit, be performed on PCI bus before any other writes scheduled on
+	 * different CPUs (after we drop reg_lock).
+	 */
+	mmiowb();
 }
 
 static inline u32
@@ -2168,7 +2054,7 @@
 	unsigned long reg_flags;
 
 	spin_lock_irqsave(&il->reg_lock, reg_flags);
-	if (!_il_grab_nic_access(il)) {
+	if (likely(_il_grab_nic_access(il))) {
 		_il_wr(il, reg, value);
 		_il_release_nic_access(il);
 	}
@@ -2179,7 +2065,6 @@
 _il_rd_prph(struct il_priv *il, u32 reg)
 {
 	_il_wr(il, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
-	rmb();
 	return _il_rd(il, HBUS_TARG_PRPH_RDAT);
 }
 
@@ -2187,7 +2072,6 @@
 _il_wr_prph(struct il_priv *il, u32 addr, u32 val)
 {
 	_il_wr(il, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24)));
-	wmb();
 	_il_wr(il, HBUS_TARG_PRPH_WDAT, val);
 }
 
@@ -2197,9 +2081,10 @@
 	unsigned long reg_flags;
 
 	spin_lock_irqsave(&il->reg_lock, reg_flags);
-	_il_grab_nic_access(il);
-	_il_wr_prph(il, reg, (_il_rd_prph(il, reg) | mask));
-	_il_release_nic_access(il);
+	if (likely(_il_grab_nic_access(il))) {
+		_il_wr_prph(il, reg, (_il_rd_prph(il, reg) | mask));
+		_il_release_nic_access(il);
+	}
 	spin_unlock_irqrestore(&il->reg_lock, reg_flags);
 }
 
@@ -2209,9 +2094,10 @@
 	unsigned long reg_flags;
 
 	spin_lock_irqsave(&il->reg_lock, reg_flags);
-	_il_grab_nic_access(il);
-	_il_wr_prph(il, reg, ((_il_rd_prph(il, reg) & mask) | bits));
-	_il_release_nic_access(il);
+	if (likely(_il_grab_nic_access(il))) {
+		_il_wr_prph(il, reg, ((_il_rd_prph(il, reg) & mask) | bits));
+		_il_release_nic_access(il);
+	}
 	spin_unlock_irqrestore(&il->reg_lock, reg_flags);
 }
 
@@ -2222,10 +2108,11 @@
 	u32 val;
 
 	spin_lock_irqsave(&il->reg_lock, reg_flags);
-	_il_grab_nic_access(il);
-	val = _il_rd_prph(il, reg);
-	_il_wr_prph(il, reg, (val & ~mask));
-	_il_release_nic_access(il);
+	if (likely(_il_grab_nic_access(il))) {
+		val = _il_rd_prph(il, reg);
+		_il_wr_prph(il, reg, (val & ~mask));
+		_il_release_nic_access(il);
+	}
 	spin_unlock_irqrestore(&il->reg_lock, reg_flags);
 }
 
@@ -2487,10 +2374,10 @@
 	__le32 __unused;	/* 3945 only */
 } __packed;
 
-#define TFD_QUEUE_SIZE_MAX      (256)
-#define TFD_QUEUE_SIZE_BC_DUP	(64)
+#define TFD_QUEUE_SIZE_MAX      256
+#define TFD_QUEUE_SIZE_BC_DUP	64
 #define TFD_QUEUE_BC_SIZE	(TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
-#define IL_TX_DMA_MASK        DMA_BIT_MASK(36)
+#define IL_TX_DMA_MASK		DMA_BIT_MASK(36)
 #define IL_NUM_OF_TBS		20
 
 static inline u8
diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c
index bb7c956..2298491 100644
--- a/drivers/net/wireless/iwlegacy/debug.c
+++ b/drivers/net/wireless/iwlegacy/debug.c
@@ -31,6 +31,101 @@
 
 #include "common.h"
 
+void
+il_clear_traffic_stats(struct il_priv *il)
+{
+	memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
+	memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
+}
+
+/*
+ * il_update_stats function record all the MGMT, CTRL and DATA pkt for
+ * both TX and Rx . Use debugfs to display the rx/rx_stats
+ */
+void
+il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
+{
+	struct traffic_stats *stats;
+
+	if (is_tx)
+		stats = &il->tx_stats;
+	else
+		stats = &il->rx_stats;
+
+	if (ieee80211_is_mgmt(fc)) {
+		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+			stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+			stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+			stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
+			stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
+			stats->mgmt[MANAGEMENT_PROBE_REQ]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
+			stats->mgmt[MANAGEMENT_PROBE_RESP]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_BEACON):
+			stats->mgmt[MANAGEMENT_BEACON]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_ATIM):
+			stats->mgmt[MANAGEMENT_ATIM]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+			stats->mgmt[MANAGEMENT_DISASSOC]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_AUTH):
+			stats->mgmt[MANAGEMENT_AUTH]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+			stats->mgmt[MANAGEMENT_DEAUTH]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_ACTION):
+			stats->mgmt[MANAGEMENT_ACTION]++;
+			break;
+		}
+	} else if (ieee80211_is_ctl(fc)) {
+		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+		case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
+			stats->ctrl[CONTROL_BACK_REQ]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_BACK):
+			stats->ctrl[CONTROL_BACK]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
+			stats->ctrl[CONTROL_PSPOLL]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_RTS):
+			stats->ctrl[CONTROL_RTS]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_CTS):
+			stats->ctrl[CONTROL_CTS]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_ACK):
+			stats->ctrl[CONTROL_ACK]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_CFEND):
+			stats->ctrl[CONTROL_CFEND]++;
+			break;
+		case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
+			stats->ctrl[CONTROL_CFENDACK]++;
+			break;
+		}
+	} else {
+		/* data */
+		stats->data_cnt++;
+		stats->data_bytes += len;
+	}
+}
+EXPORT_SYMBOL(il_update_stats);
+
 /* create and remove of files */
 #define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
 	if (!debugfs_create_file(#name, mode, parent, il,		\
@@ -98,6 +193,46 @@
 	.llseek = generic_file_llseek,				\
 };
 
+static const char *
+il_get_mgmt_string(int cmd)
+{
+	switch (cmd) {
+	IL_CMD(MANAGEMENT_ASSOC_REQ);
+	IL_CMD(MANAGEMENT_ASSOC_RESP);
+	IL_CMD(MANAGEMENT_REASSOC_REQ);
+	IL_CMD(MANAGEMENT_REASSOC_RESP);
+	IL_CMD(MANAGEMENT_PROBE_REQ);
+	IL_CMD(MANAGEMENT_PROBE_RESP);
+	IL_CMD(MANAGEMENT_BEACON);
+	IL_CMD(MANAGEMENT_ATIM);
+	IL_CMD(MANAGEMENT_DISASSOC);
+	IL_CMD(MANAGEMENT_AUTH);
+	IL_CMD(MANAGEMENT_DEAUTH);
+	IL_CMD(MANAGEMENT_ACTION);
+	default:
+		return "UNKNOWN";
+
+	}
+}
+
+static const char *
+il_get_ctrl_string(int cmd)
+{
+	switch (cmd) {
+	IL_CMD(CONTROL_BACK_REQ);
+	IL_CMD(CONTROL_BACK);
+	IL_CMD(CONTROL_PSPOLL);
+	IL_CMD(CONTROL_RTS);
+	IL_CMD(CONTROL_CTS);
+	IL_CMD(CONTROL_ACK);
+	IL_CMD(CONTROL_CFEND);
+	IL_CMD(CONTROL_CFENDACK);
+	default:
+		return "UNKNOWN";
+
+	}
+}
+
 static ssize_t
 il_dbgfs_tx_stats_read(struct file *file, char __user *user_buf, size_t count,
 		       loff_t *ppos)
@@ -495,8 +630,8 @@
 	    scnprintf(buf + pos, bufsz - pos, "S_INT_ENABLED:\t %d\n",
 		      test_bit(S_INT_ENABLED, &il->status));
 	pos +=
-	    scnprintf(buf + pos, bufsz - pos, "S_RF_KILL_HW:\t %d\n",
-		      test_bit(S_RF_KILL_HW, &il->status));
+	    scnprintf(buf + pos, bufsz - pos, "S_RFKILL:\t %d\n",
+		      test_bit(S_RFKILL, &il->status));
 	pos +=
 	    scnprintf(buf + pos, bufsz - pos, "S_CT_KILL:\t\t %d\n",
 		      test_bit(S_CT_KILL, &il->status));
@@ -715,112 +850,6 @@
 DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
 
 static ssize_t
-il_dbgfs_traffic_log_read(struct file *file, char __user *user_buf,
-			  size_t count, loff_t *ppos)
-{
-	struct il_priv *il = file->private_data;
-	int pos = 0, ofs = 0;
-	int cnt = 0, entry;
-	struct il_tx_queue *txq;
-	struct il_queue *q;
-	struct il_rx_queue *rxq = &il->rxq;
-	char *buf;
-	int bufsz =
-	    ((IL_TRAFFIC_ENTRIES * IL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
-	    (il->cfg->num_of_queues * 32 * 8) + 400;
-	const u8 *ptr;
-	ssize_t ret;
-
-	if (!il->txq) {
-		IL_ERR("txq not ready\n");
-		return -EAGAIN;
-	}
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf) {
-		IL_ERR("Can not allocate buffer\n");
-		return -ENOMEM;
-	}
-	pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
-	for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
-		txq = &il->txq[cnt];
-		q = &txq->q;
-		pos +=
-		    scnprintf(buf + pos, bufsz - pos,
-			      "q[%d]: read_ptr: %u, write_ptr: %u\n", cnt,
-			      q->read_ptr, q->write_ptr);
-	}
-	if (il->tx_traffic && (il_debug_level & IL_DL_TX)) {
-		ptr = il->tx_traffic;
-		pos +=
-		    scnprintf(buf + pos, bufsz - pos, "Tx Traffic idx: %u\n",
-			      il->tx_traffic_idx);
-		for (cnt = 0, ofs = 0; cnt < IL_TRAFFIC_ENTRIES; cnt++) {
-			for (entry = 0; entry < IL_TRAFFIC_ENTRY_SIZE / 16;
-			     entry++, ofs += 16) {
-				pos +=
-				    scnprintf(buf + pos, bufsz - pos, "0x%.4x ",
-					      ofs);
-				hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
-						   buf + pos, bufsz - pos, 0);
-				pos += strlen(buf + pos);
-				if (bufsz - pos > 0)
-					buf[pos++] = '\n';
-			}
-		}
-	}
-
-	pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
-	pos +=
-	    scnprintf(buf + pos, bufsz - pos, "read: %u, write: %u\n",
-		      rxq->read, rxq->write);
-
-	if (il->rx_traffic && (il_debug_level & IL_DL_RX)) {
-		ptr = il->rx_traffic;
-		pos +=
-		    scnprintf(buf + pos, bufsz - pos, "Rx Traffic idx: %u\n",
-			      il->rx_traffic_idx);
-		for (cnt = 0, ofs = 0; cnt < IL_TRAFFIC_ENTRIES; cnt++) {
-			for (entry = 0; entry < IL_TRAFFIC_ENTRY_SIZE / 16;
-			     entry++, ofs += 16) {
-				pos +=
-				    scnprintf(buf + pos, bufsz - pos, "0x%.4x ",
-					      ofs);
-				hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
-						   buf + pos, bufsz - pos, 0);
-				pos += strlen(buf + pos);
-				if (bufsz - pos > 0)
-					buf[pos++] = '\n';
-			}
-		}
-	}
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t
-il_dbgfs_traffic_log_write(struct file *file, const char __user *user_buf,
-			   size_t count, loff_t *ppos)
-{
-	struct il_priv *il = file->private_data;
-	char buf[8];
-	int buf_size;
-	int traffic_log;
-
-	memset(buf, 0, sizeof(buf));
-	buf_size = min(count, sizeof(buf) - 1);
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	if (sscanf(buf, "%d", &traffic_log) != 1)
-		return -EFAULT;
-	if (traffic_log == 0)
-		il_reset_traffic_log(il);
-
-	return count;
-}
-
-static ssize_t
 il_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count,
 		       loff_t *ppos)
 {
@@ -901,7 +930,8 @@
 			     size_t count, loff_t *ppos)
 {
 	struct il_priv *il = file->private_data;
-	return il->ops->lib->debugfs_ops.rx_stats_read(file, user_buf, count, ppos);
+
+	return il->debugfs_ops->rx_stats_read(file, user_buf, count, ppos);
 }
 
 static ssize_t
@@ -909,7 +939,8 @@
 			     size_t count, loff_t *ppos)
 {
 	struct il_priv *il = file->private_data;
-	return il->ops->lib->debugfs_ops.tx_stats_read(file, user_buf, count, ppos);
+
+	return il->debugfs_ops->tx_stats_read(file, user_buf, count, ppos);
 }
 
 static ssize_t
@@ -917,7 +948,8 @@
 				  size_t count, loff_t *ppos)
 {
 	struct il_priv *il = file->private_data;
-	return il->ops->lib->debugfs_ops.general_stats_read(file, user_buf, count, ppos);
+
+	return il->debugfs_ops->general_stats_read(file, user_buf, count, ppos);
 }
 
 static ssize_t
@@ -1175,8 +1207,8 @@
 	int pos = 0;
 	ssize_t ret = -EFAULT;
 
-	if (il->ops->lib->dump_fh) {
-		ret = pos = il->ops->lib->dump_fh(il, &buf, true);
+	if (il->ops->dump_fh) {
+		ret = pos = il->ops->dump_fh(il, &buf, true);
 		if (buf) {
 			ret =
 			    simple_read_from_buffer(user_buf, count, ppos, buf,
@@ -1300,7 +1332,6 @@
 
 DEBUGFS_READ_FILE_OPS(rx_stats);
 DEBUGFS_READ_FILE_OPS(tx_stats);
-DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
 DEBUGFS_READ_FILE_OPS(rx_queue);
 DEBUGFS_READ_FILE_OPS(tx_queue);
 DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
@@ -1354,7 +1385,6 @@
 	DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
 	DEBUGFS_ADD_FILE(rx_stats, dir_debug, S_IRUSR);
 	DEBUGFS_ADD_FILE(tx_stats, dir_debug, S_IRUSR);
-	DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
 	DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
 	DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
 	DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 9dc84a7..afa0bb8 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,7 +1,7 @@
 # WIFI
 obj-$(CONFIG_IWLWIFI)	+= iwlwifi.o
 iwlwifi-objs		:= iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
-iwlwifi-objs		+= iwl-ucode.o iwl-agn-tx.o
+iwlwifi-objs		+= iwl-ucode.o iwl-agn-tx.o iwl-debug.o
 iwlwifi-objs		+= iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
 iwlwifi-objs		+= iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
 
@@ -13,6 +13,7 @@
 iwlwifi-objs		+= iwl-1000.o
 iwlwifi-objs		+= iwl-2000.o
 iwlwifi-objs		+= iwl-pci.o
+iwlwifi-objs		+= iwl-drv.o
 iwlwifi-objs		+= iwl-trans.o
 iwlwifi-objs		+= iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 8c1466c..605ee3d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -120,7 +120,7 @@
 	.nrg_th_cca = 62,
 };
 
-static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 {
 	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
 	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
@@ -128,8 +128,6 @@
 			iwlagn_mod_params.num_of_queues;
 
 	hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-	hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
-	hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
 
 	hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
 
@@ -146,8 +144,6 @@
 
 	/* Set initial sensitivity parameters */
 	hw_params(priv).sens = &iwl1000_sensitivity;
-
-	return 0;
 }
 
 static struct iwl_lib_ops iwl1000_lib = {
@@ -193,6 +189,8 @@
 	.ucode_api_max = IWL1000_UCODE_API_MAX,			\
 	.ucode_api_ok = IWL1000_UCODE_API_OK,			\
 	.ucode_api_min = IWL1000_UCODE_API_MIN,			\
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
 	.lib = &iwl1000_lib,					\
@@ -215,6 +213,8 @@
 	.ucode_api_max = IWL100_UCODE_API_MAX,			\
 	.ucode_api_ok = IWL100_UCODE_API_OK,			\
 	.ucode_api_min = IWL100_UCODE_API_MIN,			\
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
 	.lib = &iwl1000_lib,					\
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index d4f5f3b..e6e8c79 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -116,7 +116,7 @@
 	.nrg_th_cca = 62,
 };
 
-static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
 {
 	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
 	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
@@ -124,8 +124,6 @@
 			iwlagn_mod_params.num_of_queues;
 
 	hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-	hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE;
-	hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE;
 
 	hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
 
@@ -142,8 +140,6 @@
 
 	/* Set initial sensitivity parameters */
 	hw_params(priv).sens = &iwl2000_sensitivity;
-
-	return 0;
 }
 
 static struct iwl_lib_ops iwl2000_lib = {
@@ -242,6 +238,8 @@
 	.ucode_api_max = IWL2000_UCODE_API_MAX,			\
 	.ucode_api_ok = IWL2000_UCODE_API_OK,			\
 	.ucode_api_min = IWL2000_UCODE_API_MIN,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
 	.lib = &iwl2000_lib,					\
@@ -268,6 +266,8 @@
 	.ucode_api_max = IWL2030_UCODE_API_MAX,			\
 	.ucode_api_ok = IWL2030_UCODE_API_OK,			\
 	.ucode_api_min = IWL2030_UCODE_API_MIN,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
 	.lib = &iwl2030_lib,					\
@@ -290,6 +290,8 @@
 	.ucode_api_max = IWL105_UCODE_API_MAX,			\
 	.ucode_api_ok = IWL105_UCODE_API_OK,			\
 	.ucode_api_min = IWL105_UCODE_API_MIN,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
 	.lib = &iwl2000_lib,					\
@@ -318,6 +320,8 @@
 	.ucode_api_max = IWL135_UCODE_API_MAX,			\
 	.ucode_api_ok = IWL135_UCODE_API_OK,			\
 	.ucode_api_min = IWL135_UCODE_API_MIN,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
 	.lib = &iwl2030_lib,					\
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index dc9317d..1527dec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -162,7 +162,7 @@
 	hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
 }
 
-static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 {
 	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
 	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
@@ -170,8 +170,6 @@
 			iwlagn_mod_params.num_of_queues;
 
 	hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-	hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
-	hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
 
 	hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
@@ -185,11 +183,9 @@
 
 	/* Set initial sensitivity parameters */
 	hw_params(priv).sens = &iwl5000_sensitivity;
-
-	return 0;
 }
 
-static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
 {
 	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
 	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
@@ -197,8 +193,6 @@
 			iwlagn_mod_params.num_of_queues;
 
 	hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-	hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
-	hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
 
 	hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
@@ -212,8 +206,6 @@
 
 	/* Set initial sensitivity parameters */
 	hw_params(priv).sens = &iwl5150_sensitivity;
-
-	return 0;
 }
 
 static void iwl5150_temperature(struct iwl_priv *priv)
@@ -356,6 +348,8 @@
 	.fw_name_pre = IWL5000_FW_PRE,				\
 	.ucode_api_max = IWL5000_UCODE_API_MAX,			\
 	.ucode_api_min = IWL5000_UCODE_API_MIN,			\
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,	\
 	.lib = &iwl5000_lib,					\
@@ -399,6 +393,8 @@
 	.fw_name_pre = IWL5000_FW_PRE,
 	.ucode_api_max = IWL5000_UCODE_API_MAX,
 	.ucode_api_min = IWL5000_UCODE_API_MIN,
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,
 	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
 	.lib = &iwl5000_lib,
@@ -412,6 +408,8 @@
 	.fw_name_pre = IWL5150_FW_PRE,				\
 	.ucode_api_max = IWL5150_UCODE_API_MAX,			\
 	.ucode_api_min = IWL5150_UCODE_API_MIN,			\
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,	\
 	.lib = &iwl5150_lib,					\
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index c36fb85..223e60a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -137,7 +137,7 @@
 	.nrg_th_cca = 62,
 };
 
-static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 {
 	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
 	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
@@ -145,8 +145,6 @@
 			iwlagn_mod_params.num_of_queues;
 
 	hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-	hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE;
-	hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE;
 
 	hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
@@ -165,7 +163,6 @@
 	/* Set initial sensitivity parameters */
 	hw_params(priv).sens = &iwl6000_sensitivity;
 
-	return 0;
 }
 
 static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
@@ -349,6 +346,8 @@
 	.ucode_api_max = IWL6000G2_UCODE_API_MAX,		\
 	.ucode_api_ok = IWL6000G2_UCODE_API_OK,			\
 	.ucode_api_min = IWL6000G2_UCODE_API_MIN,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_6005_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION,	\
 	.lib = &iwl6000_lib,					\
@@ -384,11 +383,24 @@
 	.ht_params = &iwl6000_ht_params,
 };
 
+struct iwl_cfg iwl6005_2agn_mow1_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6206 AGN",
+	IWL_DEVICE_6005,
+	.ht_params = &iwl6000_ht_params,
+};
+struct iwl_cfg iwl6005_2agn_mow2_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6207 AGN",
+	IWL_DEVICE_6005,
+	.ht_params = &iwl6000_ht_params,
+};
+
 #define IWL_DEVICE_6030						\
 	.fw_name_pre = IWL6030_FW_PRE,				\
 	.ucode_api_max = IWL6000G2_UCODE_API_MAX,		\
 	.ucode_api_ok = IWL6000G2_UCODE_API_OK,			\
 	.ucode_api_min = IWL6000G2_UCODE_API_MIN,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.eeprom_ver = EEPROM_6030_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,	\
 	.lib = &iwl6030_lib,					\
@@ -458,6 +470,8 @@
 	.ucode_api_max = IWL6000_UCODE_API_MAX,			\
 	.ucode_api_ok = IWL6000_UCODE_API_OK,			\
 	.ucode_api_min = IWL6000_UCODE_API_MIN,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.valid_tx_ant = ANT_BC,		/* .cfg overwrite */	\
 	.valid_rx_ant = ANT_BC,		/* .cfg overwrite */	\
 	.eeprom_ver = EEPROM_6000_EEPROM_VERSION,		\
@@ -487,6 +501,8 @@
 	.fw_name_pre = IWL6050_FW_PRE,				\
 	.ucode_api_max = IWL6050_UCODE_API_MAX,			\
 	.ucode_api_min = IWL6050_UCODE_API_MIN,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.valid_tx_ant = ANT_AB,		/* .cfg overwrite */	\
 	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */	\
 	.lib = &iwl6000_lib,					\
@@ -512,6 +528,8 @@
 	.fw_name_pre = IWL6050_FW_PRE,				\
 	.ucode_api_max = IWL6050_UCODE_API_MAX,			\
 	.ucode_api_min = IWL6050_UCODE_API_MIN,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.lib = &iwl6000_lib,					\
 	.additional_nic_config = iwl6150_additional_nic_config,	\
 	.eeprom_ver = EEPROM_6150_EEPROM_VERSION,		\
@@ -537,6 +555,8 @@
 	.ucode_api_max = IWL6000_UCODE_API_MAX,
 	.ucode_api_ok = IWL6000_UCODE_API_OK,
 	.ucode_api_min = IWL6000_UCODE_API_MIN,
+	.max_inst_size = IWL60_RTC_INST_SIZE,
+	.max_data_size = IWL60_RTC_DATA_SIZE,
 	.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
 	.lib = &iwl6000_lib,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 6aa0098..988ee45 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -68,6 +68,8 @@
 #include "iwl-agn-calib.h"
 #include "iwl-trans.h"
 #include "iwl-agn.h"
+#include "iwl-wifi.h"
+#include "iwl-ucode.h"
 
 /*****************************************************************************
  * INIT calibrations framework
@@ -634,7 +636,7 @@
 	data->last_bad_plcp_cnt_cck = 0;
 	data->last_fa_cnt_cck = 0;
 
-	if (priv->enhance_sensitivity_table)
+	if (nic(priv)->fw.enhance_sensitivity_table)
 		ret |= iwl_enhance_sensitivity_write(priv);
 	else
 		ret |= iwl_sensitivity_write(priv);
@@ -745,7 +747,7 @@
 
 	iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
 	iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
-	if (priv->enhance_sensitivity_table)
+	if (nic(priv)->fw.enhance_sensitivity_table)
 		iwl_enhance_sensitivity_write(priv);
 	else
 		iwl_sensitivity_write(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index a8f7689..5be0d36 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -77,7 +77,7 @@
 	tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
 	tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
 
-	if (IWL_UCODE_API(priv->ucode_ver) == 1)
+	if (IWL_UCODE_API(nic(priv)->fw.ucode_ver) == 1)
 		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
 	else
 		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
@@ -700,7 +700,7 @@
 		priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
 
 		/* schedule to send runtime bt_config */
-		queue_work(priv->shrd->workqueue, &priv->bt_runtime_config);
+		queue_work(priv->workqueue, &priv->bt_runtime_config);
 	}
 }
 
@@ -745,7 +745,7 @@
 					IWL_BT_COEX_TRAFFIC_LOAD_NONE;
 			}
 			priv->bt_status = coex->bt_status;
-			queue_work(priv->shrd->workqueue,
+			queue_work(priv->workqueue,
 				   &priv->bt_traffic_change_work);
 		}
 	}
@@ -959,7 +959,7 @@
 			       struct ieee80211_key_conf *key,
 			       void *_data)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct wowlan_key_data *data = _data;
 	struct iwl_rxon_context *ctx = data->ctx;
 	struct aes_sc *aes_sc, *aes_tx_sc = NULL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index b9ba404..a7d6713 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -38,6 +38,7 @@
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-agn.h"
+#include "iwl-op-mode.h"
 
 #define RS_NAME "iwl-agn-rs"
 
@@ -892,7 +893,7 @@
 		rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
 		iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
 
-		queue_work(priv->shrd->workqueue, &priv->bt_full_concurrency);
+		queue_work(priv->workqueue, &priv->bt_full_concurrency);
 	}
 }
 
@@ -909,7 +910,8 @@
 	struct iwl_lq_sta *lq_sta = priv_sta;
 	struct iwl_link_quality_cmd *table;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+	struct iwl_op_mode *op_mode = (struct iwl_op_mode *)priv_r;
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	enum mac80211_rate_control_flags mac_flags;
 	u32 tx_rate;
@@ -2737,7 +2739,9 @@
 
 	struct sk_buff *skb = txrc->skb;
 	struct ieee80211_supported_band *sband = txrc->sband;
-	struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r;
+	struct iwl_op_mode *op_mode __maybe_unused =
+			(struct iwl_op_mode *)priv_r;
+	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct iwl_lq_sta *lq_sta = priv_sta;
 	int rate_idx;
@@ -2805,9 +2809,10 @@
 			  gfp_t gfp)
 {
 	struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
-	struct iwl_priv *priv;
+	struct iwl_op_mode *op_mode __maybe_unused =
+			(struct iwl_op_mode *)priv_rate;
+	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
 
-	priv = (struct iwl_priv *)priv_rate;
 	IWL_DEBUG_RATE(priv, "create station rate scale window\n");
 
 	return &sta_priv->lq_sta;
@@ -3074,7 +3079,8 @@
 static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
 			void *priv_sta)
 {
-	struct iwl_priv *priv __maybe_unused = priv_r;
+	struct iwl_op_mode *op_mode __maybe_unused = priv_r;
+	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
 
 	IWL_DEBUG_RATE(priv, "enter\n");
 	IWL_DEBUG_RATE(priv, "leave\n");
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index a14ddab..30bb5bb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -581,7 +581,7 @@
 	if (unlikely(!test_bit(STATUS_SCANNING, &priv->shrd->status)) &&
 	    (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
 		iwlagn_rx_calc_noise(priv);
-		queue_work(priv->shrd->workqueue, &priv->run_time_calib_work);
+		queue_work(priv->workqueue, &priv->run_time_calib_work);
 	}
 	if (cfg(priv)->lib->temperature && change)
 		cfg(priv)->lib->temperature(priv);
@@ -1141,10 +1141,11 @@
 
 }
 
-int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_mem_buffer *rxb,
 		     struct iwl_device_cmd *cmd)
 {
 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 	int err = 0;
 
 	/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index 8ca9570..73653a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -549,7 +549,7 @@
 
 int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_rxon_context *ctx;
 	struct ieee80211_conf *conf = &hw->conf;
 	struct ieee80211_channel *channel = conf->channel;
@@ -805,7 +805,7 @@
 			     struct ieee80211_bss_conf *bss_conf,
 			     u32 changes)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 	int ret;
 	bool force = false;
@@ -900,6 +900,22 @@
 		}
 	}
 
+	/*
+	 * If the ucode decides to do beacon filtering before
+	 * association, it will lose beacons that are needed
+	 * before sending frames out on passive channels. This
+	 * causes association failures on those channels. Enable
+	 * receiving beacons in such cases.
+	 */
+
+	if (vif->type == NL80211_IFTYPE_STATION) {
+		if (!bss_conf->assoc)
+			ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+		else
+			ctx->staging.filter_flags &=
+						    ~RXON_FILTER_BCON_AWARE_MSK;
+	}
+
 	if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
 		iwlagn_commit_rxon(priv, ctx);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
index c728ed7..56d7c0e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
@@ -568,7 +568,7 @@
 		return;
 
 	IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
-	queue_work(priv->shrd->workqueue, &priv->ct_enter);
+	queue_work(priv->workqueue, &priv->ct_enter);
 }
 
 void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
@@ -577,7 +577,7 @@
 		return;
 
 	IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
-	queue_work(priv->shrd->workqueue, &priv->ct_exit);
+	queue_work(priv->workqueue, &priv->ct_exit);
 }
 
 static void iwl_bg_tt_work(struct work_struct *work)
@@ -600,7 +600,7 @@
 		return;
 
 	IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
-	queue_work(priv->shrd->workqueue, &priv->tt_work);
+	queue_work(priv->workqueue, &priv->tt_work);
 }
 
 /* Thermal throttling initialization
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 64f8db6..5f78567 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -322,7 +322,7 @@
 		sta_priv = (void *)info->control.sta->drv_priv;
 
 	if (sta_priv && sta_priv->asleep &&
-	    (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
+	    (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
 		/*
 		 * This sends an asynchronous command to the device,
 		 * but we can rely on it being processed before the
@@ -331,6 +331,10 @@
 		 * counter.
 		 * For now set the counter to just 1 since we do not
 		 * support uAPSD yet.
+		 *
+		 * FIXME: If we get two non-bufferable frames one
+		 * after the other, we might only send out one of
+		 * them because this is racy.
 		 */
 		iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
 	}
@@ -983,7 +987,7 @@
 	if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
 		IWL_ERR(priv, "Tx flush command to flush out all frames\n");
 		if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-			queue_work(priv->shrd->workqueue, &priv->tx_flush);
+			queue_work(priv->workqueue, &priv->tx_flush);
 	}
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 8837171..e0fef9f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -50,8 +50,8 @@
 #include "iwl-agn-calib.h"
 #include "iwl-agn.h"
 #include "iwl-shared.h"
-#include "iwl-bus.h"
 #include "iwl-trans.h"
+#include "iwl-op-mode.h"
 
 /******************************************************************************
  *
@@ -618,7 +618,7 @@
 	  .valid = cpu_to_le32(valid_tx_ant),
 	};
 
-	if (IWL_UCODE_API(priv->ucode_ver) > 1) {
+	if (IWL_UCODE_API(nic(priv)->fw.ucode_ver) > 1) {
 		IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
 		return iwl_trans_send_cmd_pdu(trans(priv),
 					TX_ANT_CONFIGURATION_CMD,
@@ -738,14 +738,14 @@
 	return iwl_power_update_mode(priv, true);
 }
 
-static void iwl_cancel_deferred_work(struct iwl_priv *priv);
-
-void __iwl_down(struct iwl_priv *priv)
+void iwl_down(struct iwl_priv *priv)
 {
 	int exit_pending;
 
 	IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
 
+	lockdep_assert_held(&priv->shrd->mutex);
+
 	iwl_scan_cancel_timeout(priv, 200);
 
 	/*
@@ -803,15 +803,6 @@
 	priv->beacon_skb = NULL;
 }
 
-void iwl_down(struct iwl_priv *priv)
-{
-	mutex_lock(&priv->shrd->mutex);
-	__iwl_down(priv);
-	mutex_unlock(&priv->shrd->mutex);
-
-	iwl_cancel_deferred_work(priv);
-}
-
 /*****************************************************************************
  *
  * Workqueue callbacks
@@ -869,7 +860,7 @@
 	bt_status = priv->bt_status;
 	bt_is_sco = priv->bt_is_sco;
 
-	__iwl_down(priv);
+	iwl_down(priv);
 
 	priv->bt_full_concurrent = bt_full_concurrent;
 	priv->bt_ci_compliance = bt_ci_compliance;
@@ -939,7 +930,7 @@
 
 static void iwl_setup_deferred_work(struct iwl_priv *priv)
 {
-	priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
+	priv->workqueue = create_singlethread_workqueue(DRV_NAME);
 
 	init_waitqueue_head(&priv->shrd->wait_command_queue);
 
@@ -970,7 +961,7 @@
 	priv->watchdog.function = iwl_bg_watchdog;
 }
 
-static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+void iwl_cancel_deferred_work(struct iwl_priv *priv)
 {
 	if (cfg(priv)->lib->cancel_deferred_work)
 		cfg(priv)->lib->cancel_deferred_work(priv);
@@ -1091,7 +1082,7 @@
 #define IWL_RX_BUF_SIZE_4K (4 * 1024)
 #define IWL_RX_BUF_SIZE_8K (8 * 1024)
 
-static int iwl_set_hw_params(struct iwl_priv *priv)
+static void iwl_set_hw_params(struct iwl_priv *priv)
 {
 	if (iwlagn_mod_params.amsdu_size_8K)
 		hw_params(priv).rx_page_order =
@@ -1111,7 +1102,7 @@
 	hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout;
 
 	/* Device-specific setup */
-	return cfg(priv)->lib->set_hw_params(priv);
+	cfg(priv)->lib->set_hw_params(priv);
 }
 
 
@@ -1151,37 +1142,43 @@
 #endif
 }
 
-int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
-		struct iwl_cfg *cfg)
+static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans)
 {
+	struct iwl_fw *fw = &nic(trans)->fw;
 	int err = 0;
 	struct iwl_priv *priv;
 	struct ieee80211_hw *hw;
+	struct iwl_op_mode *op_mode;
 	u16 num_mac;
+	u32 ucode_flags;
 
 	/************************
 	 * 1. Allocating HW data
 	 ************************/
 	hw = iwl_alloc_all();
 	if (!hw) {
-		pr_err("%s: Cannot allocate network device\n", cfg->name);
+		pr_err("%s: Cannot allocate network device\n",
+				cfg(trans)->name);
 		err = -ENOMEM;
 		goto out;
 	}
 
-	priv = hw->priv;
-	priv->shrd = bus->shrd;
+	op_mode = hw->priv;
+	op_mode->ops = &iwl_dvm_ops;
+	priv = IWL_OP_MODE_GET_DVM(op_mode);
+	priv->shrd = trans->shrd;
 	priv->shrd->priv = priv;
 
+	iwl_trans_configure(trans(priv), op_mode);
+
 	/* At this point both hw and priv are allocated. */
 
-	SET_IEEE80211_DEV(hw, trans(priv)->dev);
+	SET_IEEE80211_DEV(priv->hw, trans(priv)->dev);
 
 	/* show what debugging capabilities we have */
 	iwl_debug_config(priv);
 
 	IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
-	cfg(priv) = cfg;
 
 	/* is antenna coupling more than 35dB ? */
 	priv->bt_ant_couple_ok =
@@ -1217,7 +1214,7 @@
 	 * 4. Read EEPROM
 	 *****************/
 	/* Read the EEPROM */
-	err = iwl_eeprom_init(priv, trans(priv)->hw_rev);
+	err = iwl_eeprom_init(trans(priv), trans(priv)->hw_rev);
 	/* Reset chip to save power until we load uCode during "up". */
 	iwl_trans_stop_hw(trans(priv));
 	if (err) {
@@ -1248,11 +1245,23 @@
 	/************************
 	 * 5. Setup HW constants
 	 ************************/
-	if (iwl_set_hw_params(priv)) {
-		err = -ENOENT;
-		IWL_ERR(priv, "failed to set hw parameters\n");
-		goto out_free_eeprom;
-	}
+	iwl_set_hw_params(priv);
+
+	ucode_flags = fw->ucode_capa.flags;
+
+#ifndef CONFIG_IWLWIFI_P2P
+	ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
+#endif
+	if (!(hw_params(priv).sku & EEPROM_SKU_CAP_IPAN_ENABLE))
+		ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
+
+	/*
+	 * if not PAN, then don't support P2P -- might be a uCode
+	 * packaging bug or due to the eeprom check above
+	 */
+	if (!(ucode_flags & IWL_UCODE_TLV_FLAGS_PAN))
+		ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
+
 
 	/*******************
 	 * 6. Setup priv
@@ -1273,17 +1282,49 @@
 	iwl_power_initialize(priv);
 	iwl_tt_initialize(priv);
 
-	init_completion(&priv->firmware_loading_complete);
+	snprintf(priv->hw->wiphy->fw_version,
+		 sizeof(priv->hw->wiphy->fw_version),
+		 "%s", fw->fw_version);
 
-	err = iwl_request_firmware(priv, true);
+	priv->new_scan_threshold_behaviour =
+		!!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
+
+	if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
+		priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
+		priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+	} else {
+		priv->sta_key_max_num = STA_KEY_MAX_NUM;
+		priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+	}
+
+	priv->phy_calib_chain_noise_reset_cmd =
+		fw->ucode_capa.standard_phy_calibration_size;
+	priv->phy_calib_chain_noise_gain_cmd =
+		fw->ucode_capa.standard_phy_calibration_size + 1;
+
+	/* initialize all valid contexts */
+	iwl_init_context(priv, ucode_flags);
+
+	/**************************************************
+	 * This is still part of probe() in a sense...
+	 *
+	 * 9. Setup and register with mac80211 and debugfs
+	 **************************************************/
+	err = iwlagn_mac_setup_register(priv, &fw->ucode_capa);
 	if (err)
 		goto out_destroy_workqueue;
 
-	return 0;
+	err = iwl_dbgfs_register(priv, DRV_NAME);
+	if (err)
+		IWL_ERR(priv,
+			"failed to create debugfs files. Ignoring error: %d\n",
+			err);
+
+	return op_mode;
 
 out_destroy_workqueue:
-	destroy_workqueue(priv->shrd->workqueue);
-	priv->shrd->workqueue = NULL;
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
 	iwl_uninit_drv(priv);
 out_free_eeprom:
 	iwl_eeprom_free(priv->shrd);
@@ -1291,12 +1332,15 @@
 	iwl_free_traffic_mem(priv);
 	ieee80211_free_hw(priv->hw);
 out:
-	return err;
+	op_mode = NULL;
+	return op_mode;
 }
 
-void __devexit iwl_remove(struct iwl_priv * priv)
+static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
 {
-	wait_for_completion(&priv->firmware_loading_complete);
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+	wait_for_completion(&nic(priv)->request_firmware_complete);
 
 	IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
 
@@ -1316,18 +1360,18 @@
 	/*This will stop the queues, move the device to low power state */
 	iwl_trans_stop_device(trans(priv));
 
-	iwl_dealloc_ucode(trans(priv));
+	iwl_dealloc_ucode(nic(priv));
 
 	iwl_eeprom_free(priv->shrd);
 
 	/*netif_stop_queue(dev); */
-	flush_workqueue(priv->shrd->workqueue);
+	flush_workqueue(priv->workqueue);
 
 	/* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes
-	 * priv->shrd->workqueue... so we can't take down the workqueue
+	 * priv->workqueue... so we can't take down the workqueue
 	 * until now... */
-	destroy_workqueue(priv->shrd->workqueue);
-	priv->shrd->workqueue = NULL;
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
 	iwl_free_traffic_mem(priv);
 
 	iwl_uninit_drv(priv);
@@ -1337,6 +1381,16 @@
 	ieee80211_free_hw(priv->hw);
 }
 
+const struct iwl_op_mode_ops iwl_dvm_ops = {
+	.start = iwl_op_mode_dvm_start,
+	.stop = iwl_op_mode_dvm_stop,
+	.rx = iwl_rx_dispatch,
+	.queue_full = iwl_stop_sw_queue,
+	.queue_not_full = iwl_wake_sw_queue,
+	.hw_rf_kill = iwl_set_hw_rfkill_state,
+	.free_skb = iwl_free_skb,
+	.nic_error = iwl_nic_error,
+};
 
 /*****************************************************************************
  *
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 37c325f..cb484e2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -65,11 +65,7 @@
 
 #include "iwl-dev.h"
 
-struct iwlagn_ucode_capabilities {
-	u32 max_probe_length;
-	u32 standard_phy_calibration_size;
-	u32 flags;
-};
+struct iwl_ucode_capabilities;
 
 extern struct ieee80211_ops iwlagn_hw_ops;
 
@@ -81,14 +77,23 @@
 	hdr->data_valid = 1;
 }
 
-void __iwl_down(struct iwl_priv *priv);
 void iwl_down(struct iwl_priv *priv);
+void iwl_cancel_deferred_work(struct iwl_priv *priv);
 void iwlagn_prepare_restart(struct iwl_priv *priv);
+void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
+int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode,
+				 struct iwl_rx_mem_buffer *rxb,
+				 struct iwl_device_cmd *cmd);
+void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac);
+void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac);
+void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state);
+void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac);
+void iwl_nic_error(struct iwl_op_mode *op_mode);
 
 /* MAC80211 */
 struct ieee80211_hw *iwl_alloc_all(void);
 int iwlagn_mac_setup_register(struct iwl_priv *priv,
-			      struct iwlagn_ucode_capabilities *capa);
+			      struct iwl_ucode_capabilities *capa);
 void iwlagn_mac_unregister(struct iwl_priv *priv);
 
 /* RXON */
@@ -387,4 +392,14 @@
 }
 #endif
 
+#ifdef CONFIG_IWLWIFI_DEBUG
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+			     enum iwl_rxon_context_id ctxid);
+#else
+static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+					   enum iwl_rxon_context_id ctxid)
+{
+}
+#endif
+
 #endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-bus.h b/drivers/net/wireless/iwlwifi/iwl-bus.h
deleted file mode 100644
index 30965e0..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-bus.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#ifndef __iwl_bus_h__
-#define __iwl_bus_h__
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-/**
- * DOC: Bus layer - role and goal
- *
- * iwl-bus.h defines the API to the bus layer of the iwlwifi driver.
- * The bus layer is responsible for doing very basic bus operations that are
- * listed in the iwl_bus_ops structure.
- * The bus layer registers to the bus driver, advertises the supported HW and
- * gets notifications about enumeration, suspend, resume.
- * For the moment, the bus layer is not a linux kernel module as itself, and
- * the module_init function of the driver must call the bus specific
- * registration functions. These functions are listed at the end of this file.
- * For the moment, there is only one implementation of this interface: PCI-e.
- * This implementation is iwl-pci.c
- */
-
-/**
- * DOC: encapsulation and type safety
- *
- * The iwl_bus describes the data that is shared amongst all the bus layer
- * implementations. This data is visible to other layers. Data in the bus
- * specific area is not visible outside the bus specific implementation.
- * iwl_bus holds a pointer to iwl_shared which holds pointer to all the other
- * layers of the driver (iwl_priv, iwl_trans). In fact, this is the way to go
- * when the transport layer needs to call a function of another layer.
- *
- * In order to achieve encapsulation, iwl_priv cannot be dereferenced from the
- * bus layer. Type safety is still kept since functions that gets iwl_priv gets
- * a typed pointer (as opposed to void *).
- */
-
-/**
- * DOC: probe flow
- *
- * The module_init calls the bus specific registration function. The
- * registration to the bus layer will trigger an enumeration of the bus which
- * will call the bus specific probe function.
- * The first thing this function must do is to allocate the memory needed by
- * iwl_bus + the bus_specific data.
- * Once the bus specific probe function has configured the hardware, it
- * chooses the appropriate transport layer and calls iwl_probe that will run
- * the bus independent probe flow.
- *
- * Note: The bus specific code must set the following data in iwl_bus before it
- *       calls iwl_probe:
- *	* bus->dev
- *	* bus->irq
- *	* bus->ops
- */
-
-struct iwl_shared;
-struct iwl_bus;
-
-/**
- * struct iwl_bus - bus common data
- *
- * This data is common to all bus layer implementations.
- *
- * @ops - pointer to iwl_bus_ops
- * @shrd - pointer to iwl_shared which holds shared data from the upper layer
- *	NB: for the time being this needs to be set by the upper layer since
- *	it allocates the shared data
- */
-struct iwl_bus {
-	struct iwl_shared *shrd;
-
-	/* pointer to bus specific struct */
-	/*Ensure that this pointer will always be aligned to sizeof pointer */
-	char bus_specific[0] __attribute__((__aligned__(sizeof(void *))));
-};
-
-/*****************************************************
-* Bus layer registration functions
-******************************************************/
-int __must_check iwl_pci_register_driver(void);
-void iwl_pci_unregister_driver(void);
-
-#endif /* __iwl_bus_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-cfg.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h
index 957bc00..1ad14bb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-cfg.h
+++ b/drivers/net/wireless/iwlwifi/iwl-cfg.h
@@ -80,6 +80,8 @@
 extern struct iwl_cfg iwl6005_2bg_cfg;
 extern struct iwl_cfg iwl6005_2agn_sff_cfg;
 extern struct iwl_cfg iwl6005_2agn_d_cfg;
+extern struct iwl_cfg iwl6005_2agn_mow1_cfg;
+extern struct iwl_cfg iwl6005_2agn_mow2_cfg;
 extern struct iwl_cfg iwl1030_bgn_cfg;
 extern struct iwl_cfg iwl1030_bg_cfg;
 extern struct iwl_cfg iwl6030_2agn_cfg;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 0677b3d..275e089 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -38,10 +38,10 @@
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-power.h"
-#include "iwl-agn.h"
 #include "iwl-shared.h"
 #include "iwl-agn.h"
 #include "iwl-trans.h"
+#include "iwl-wifi.h"
 
 const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
@@ -643,7 +643,7 @@
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
  * in the staging RXON flag structure based on the ch->band
  */
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
 			 struct iwl_rxon_context *ctx)
 {
 	enum ieee80211_band band = ch->band;
@@ -651,7 +651,7 @@
 
 	if ((le16_to_cpu(ctx->staging.channel) == channel) &&
 	    (priv->band == band))
-		return 0;
+		return;
 
 	ctx->staging.channel = cpu_to_le16(channel);
 	if (band == IEEE80211_BAND_5GHZ)
@@ -663,7 +663,6 @@
 
 	IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
 
-	return 0;
 }
 
 void iwl_set_flags_for_band(struct iwl_priv *priv,
@@ -831,11 +830,16 @@
 }
 #endif
 
-void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
+static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
 {
 	unsigned int reload_msec;
 	unsigned long reload_jiffies;
 
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS)
+		iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
+#endif
+
 	/* Set the FW error flag -- cleared on iwl_down */
 	set_bit(STATUS_FW_ERROR, &priv->shrd->status);
 
@@ -875,7 +879,7 @@
 		if (iwlagn_mod_params.restart_fw) {
 			IWL_DEBUG_FW_ERRORS(priv,
 				  "Restarting adapter due to uCode error.\n");
-			queue_work(priv->shrd->workqueue, &priv->restart);
+			queue_work(priv->workqueue, &priv->restart);
 		} else
 			IWL_DEBUG_FW_ERRORS(priv,
 				  "Detected FW error, but not restarting\n");
@@ -1456,8 +1460,17 @@
 	return cpu_to_le32(res);
 }
 
-void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state)
+void iwl_nic_error(struct iwl_op_mode *op_mode)
 {
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+	iwlagn_fw_error(priv, false);
+}
+
+void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
 	wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
 }
 
@@ -1466,8 +1479,9 @@
 	cfg(priv)->lib->nic_config(priv);
 }
 
-void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb)
+void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
 {
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 	struct ieee80211_tx_info *info;
 
 	info = IEEE80211_SKB_CB(skb);
@@ -1475,12 +1489,16 @@
 	dev_kfree_skb_any(skb);
 }
 
-void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac)
+void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
 {
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
 	ieee80211_stop_queue(priv->hw, ac);
 }
 
-void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac)
+void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
 {
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
 	ieee80211_wake_queue(priv->hw, ac);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 8d60dcf..42630f5e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -76,7 +76,7 @@
 
 struct iwl_lib_ops {
 	/* set hw dependent parameters */
-	int (*set_hw_params)(struct iwl_priv *priv);
+	void (*set_hw_params)(struct iwl_priv *priv);
 	/* setup BT Rx handler */
 	void (*bt_rx_handler_setup)(struct iwl_priv *priv);
 	/* setup BT related deferred work */
@@ -169,7 +169,7 @@
 			   int hw_decrypt);
 int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
 int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
 			 struct iwl_rxon_context *ctx);
 void iwl_set_flags_for_band(struct iwl_priv *priv,
 			    struct iwl_rxon_context *ctx,
@@ -197,6 +197,8 @@
 void iwl_clear_traffic_stats(struct iwl_priv *priv);
 void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
 		      u16 len);
+void iwl_reset_traffic_log(struct iwl_priv *priv);
+
 #else
 static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c
new file mode 100644
index 0000000..4bc2e70
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.c
@@ -0,0 +1,127 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <linux/interrupt.h>
+#include "iwl-debug.h"
+
+#define __iwl_fn(fn)						\
+void __iwl_ ##fn(struct device *dev, const char *fmt, ...)	\
+{								\
+	struct va_format vaf = {				\
+		.fmt = fmt,					\
+	};							\
+	va_list args;						\
+								\
+	va_start(args, fmt);					\
+	vaf.va = &args;						\
+	dev_ ##fn(dev, "%pV", &vaf);				\
+	trace_iwlwifi_ ##fn(&vaf);				\
+	va_end(args);						\
+}
+
+__iwl_fn(warn)
+__iwl_fn(info)
+__iwl_fn(crit)
+
+void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
+		const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+	if (!trace_only) {
+		if (rfkill_prefix)
+			dev_err(dev, "(RFKILL) %pV", &vaf);
+		else
+			dev_err(dev, "%pV", &vaf);
+	}
+	trace_iwlwifi_err(&vaf);
+	va_end(args);
+}
+
+#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
+void __iwl_dbg(struct iwl_shared *shared, struct device *dev,
+	       u32 level, bool limit, const char *function,
+	       const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_get_debug_level(shared) & level &&
+	    (!limit || net_ratelimit()))
+		dev_err(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U',
+			function, &vaf);
+#endif
+	trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
+	va_end(args);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 351b41d..01b2330 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -29,16 +29,34 @@
 #ifndef __iwl_debug_h__
 #define __iwl_debug_h__
 
-#include "iwl-bus.h"
 #include "iwl-shared.h"
+#include "iwl-devtrace.h"
 
 struct iwl_priv;
 
-/*No matter what is m (priv, bus, trans), this will work */
-#define IWL_ERR(m, f, a...) dev_err(trans(m)->dev, f, ## a)
-#define IWL_WARN(m, f, a...) dev_warn(trans(m)->dev, f, ## a)
-#define IWL_INFO(m, f, a...) dev_info(trans(m)->dev, f, ## a)
-#define IWL_CRIT(m, f, a...) dev_crit(trans(m)->dev, f, ## a)
+void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace,
+		const char *fmt, ...);
+void __iwl_warn(struct device *dev, const char *fmt, ...);
+void __iwl_info(struct device *dev, const char *fmt, ...);
+void __iwl_crit(struct device *dev, const char *fmt, ...);
+
+/* No matter what is m (priv, bus, trans), this will work */
+#define IWL_ERR(m, f, a...) __iwl_err(trans(m)->dev, false, false, f, ## a)
+#define IWL_WARN(m, f, a...) __iwl_warn(trans(m)->dev, f, ## a)
+#define IWL_INFO(m, f, a...) __iwl_info(trans(m)->dev, f, ## a)
+#define IWL_CRIT(m, f, a...) __iwl_crit(trans(m)->dev, f, ## a)
+
+#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
+void __iwl_dbg(struct iwl_shared *shared, struct device *dev,
+	       u32 level, bool limit, const char *function,
+	       const char *fmt, ...);
+#else
+static inline void
+__iwl_dbg(struct iwl_shared *shared, struct device *dev,
+	  u32 level, bool limit, const char *function,
+	  const char *fmt, ...)
+{}
+#endif
 
 #define iwl_print_hex_error(m, p, len)					\
 do {									\
@@ -46,53 +64,35 @@
 		       DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);		\
 } while (0)
 
+#define IWL_DEBUG(m, level, fmt, args...)				\
+	__iwl_dbg((m)->shrd, trans(m)->dev, level, false, __func__, fmt, ##args)
+#define IWL_DEBUG_LIMIT(m, level, fmt, args...)				\
+	__iwl_dbg((m)->shrd, trans(m)->dev, level, true, __func__, fmt, ##args)
+
 #ifdef CONFIG_IWLWIFI_DEBUG
-#define IWL_DEBUG(m, level, fmt, ...)					\
-do {									\
-	if (iwl_get_debug_level((m)->shrd) & (level))			\
-		dev_err(trans(m)->dev, "%c %s " fmt,			\
-			in_interrupt() ? 'I' : 'U', __func__,		\
-			##__VA_ARGS__);					\
-} while (0)
-
-#define IWL_DEBUG_LIMIT(m, level, fmt, ...)				\
-do {									\
-	if (iwl_get_debug_level((m)->shrd) & (level) &&			\
-	    net_ratelimit())						\
-		dev_err(trans(m)->dev, "%c %s " fmt,			\
-			in_interrupt() ? 'I' : 'U', __func__,		\
-			##__VA_ARGS__);					\
-} while (0)
-
 #define iwl_print_hex_dump(m, level, p, len)				\
 do {                                            			\
 	if (iwl_get_debug_level((m)->shrd) & level)			\
 		print_hex_dump(KERN_DEBUG, "iwl data: ",		\
 			       DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);	\
 } while (0)
-
-#define IWL_DEBUG_QUIET_RFKILL(p, fmt, ...)				\
+#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)	\
 do {									\
-	if (!iwl_is_rfkill(p->shrd))					\
-		dev_err(trans(p)->dev, "%s%c %s " fmt,			\
-			"",						\
-			in_interrupt() ? 'I' : 'U', __func__,		\
-			##__VA_ARGS__);					\
-	else if	(iwl_get_debug_level(p->shrd) & IWL_DL_RADIO)		\
-		dev_err(trans(p)->dev, "%s%c %s " fmt,			\
-			"(RFKILL) ",					\
-			in_interrupt() ? 'I' : 'U', __func__,		\
-			##__VA_ARGS__);					\
+	if (!iwl_is_rfkill((m)->shrd))					\
+		IWL_ERR(m, fmt, ##args);				\
+	else								\
+		__iwl_err(trans(m)->dev, true,				\
+			  !(iwl_get_debug_level((m)->shrd) & IWL_DL_RADIO),\
+			  fmt, ##args);					\
 } while (0)
-
 #else
-#define IWL_DEBUG(m, level, fmt, args...)
-#define IWL_DEBUG_LIMIT(m, level, fmt, args...)
 #define iwl_print_hex_dump(m, level, p, len)
-#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...)	\
-do {							\
-	if (!iwl_is_rfkill(p->shrd))			\
-		IWL_ERR(p, fmt, ##args);		\
+#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)	\
+do {									\
+	if (!iwl_is_rfkill((m)->shrd))					\
+		IWL_ERR(m, fmt, ##args);				\
+	else								\
+		__iwl_err(trans(m)->dev, true, true, fmt, ##args);	\
 } while (0)
 #endif				/* CONFIG_IWLWIFI_DEBUG */
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 136de6f..ad74138e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -40,6 +40,7 @@
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-agn.h"
+#include "iwl-wifi.h"
 
 /* create and remove of files */
 #define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
@@ -234,12 +235,12 @@
 
 	/* default is to dump the entire data segment */
 	if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
-		struct iwl_trans *trans = trans(priv);
+		struct iwl_nic *nic = nic(priv);
 		priv->dbgfs_sram_offset = 0x800000;
-		if (trans->shrd->ucode_type == IWL_UCODE_INIT)
-			priv->dbgfs_sram_len = trans->ucode_init.data.len;
+		if (nic->shrd->ucode_type == IWL_UCODE_INIT)
+			priv->dbgfs_sram_len = nic->fw.ucode_init.data.len;
 		else
-			priv->dbgfs_sram_len = trans->ucode_rt.data.len;
+			priv->dbgfs_sram_len = nic->fw.ucode_rt.data.len;
 	}
 	len = priv->dbgfs_sram_len;
 
@@ -342,7 +343,7 @@
 
 	return simple_read_from_buffer(user_buf, count, ppos,
 				       priv->wowlan_sram,
-				       trans(priv)->ucode_wowlan.data.len);
+				       nic(priv)->fw.ucode_wowlan.data.len);
 }
 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
 					size_t count, loff_t *ppos)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index aa99457..6e5bf0a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -47,9 +47,9 @@
 #include "iwl-power.h"
 #include "iwl-agn-rs.h"
 #include "iwl-agn-tt.h"
-#include "iwl-bus.h"
 #include "iwl-trans.h"
 #include "iwl-shared.h"
+#include "iwl-op-mode.h"
 
 struct iwl_tx_queue;
 
@@ -442,9 +442,6 @@
 	u8 state;
 };
 
-#define	EEPROM_SEM_TIMEOUT 10		/* milliseconds */
-#define EEPROM_SEM_RETRY_LIMIT 1000	/* number of attempts (not time) */
-
 enum {
 	MEASUREMENT_READY = (1 << 0),
 	MEASUREMENT_ACTIVE = (1 << 1),
@@ -696,11 +693,11 @@
 	dma_addr_t dma_addr;
 	bool trace_enabled;
 };
-struct iwl_testmode_sram {
+struct iwl_testmode_mem {
 	u32 buff_size;
 	u32 num_chunks;
 	u8 *buff_addr;
-	bool sram_readed;
+	bool read_in_progress;
 };
 #endif
 
@@ -710,6 +707,13 @@
 	u8 data[];
 };
 
+#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \
+	((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific))
+
+#define IWL_MAC80211_GET_DVM(_hw) \
+	((struct iwl_priv *) ((struct iwl_op_mode *) \
+	(_hw)->priv)->op_mode_specific)
+
 struct iwl_priv {
 
 	/*data shared among all the driver's layers */
@@ -721,6 +725,8 @@
 	struct ieee80211_rate *ieee_rates;
 	struct kmem_cache *tx_cmd_pool;
 
+	struct workqueue_struct *workqueue;
+
 	enum ieee80211_band band;
 
 	void (*pre_rx_handler)(struct iwl_priv *priv,
@@ -785,13 +791,6 @@
 	/* EEPROM MAC addresses */
 	struct mac_address addresses[2];
 
-	/* uCode images, save to reload in case of failure */
-	int fw_index;			/* firmware we're trying to load */
-	u32 ucode_ver;			/* version of ucode, copy of
-					   iwl_ucode.ver */
-
-	char firmware_name[25];
-
 	struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
 
 	__le16 switch_channel;
@@ -801,7 +800,6 @@
 	u8 start_calib;
 	struct iwl_sensitivity_data sensitivity_data;
 	struct iwl_chain_noise_data chain_noise_data;
-	bool enhance_sensitivity_table;
 	__le16 sensitivity_tbl[HD_TABLE_SIZE];
 	__le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
 
@@ -869,11 +867,6 @@
 	struct iwl_rx_phy_res last_phy_res;
 	bool last_phy_res_valid;
 
-	struct completion firmware_loading_complete;
-
-	u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
-	u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
-
 	/*
 	 * chain noise reset and gain commands are the
 	 * two extra calibration commands follows the standard
@@ -964,7 +957,7 @@
 	bool led_registered;
 #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
 	struct iwl_testmode_trace testmode_trace;
-	struct iwl_testmode_sram testmode_sram;
+	struct iwl_testmode_mem testmode_mem;
 	u32 tm_fixed_rate;
 #endif
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 4d89221..96e6233 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -34,6 +34,11 @@
 #undef TRACE_EVENT
 #define TRACE_EVENT(name, proto, ...) \
 static inline void trace_ ## name(proto) {}
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(...)
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(evt_class, name, proto, ...) \
+static inline void trace_ ## name(proto) {}
 #endif
 
 #define PRIV_ENTRY	__field(void *, priv)
@@ -164,6 +169,66 @@
 );
 
 #undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi_msg
+
+#define MAX_MSG_LEN	100
+
+DECLARE_EVENT_CLASS(iwlwifi_msg_event,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf),
+	TP_STRUCT__entry(
+		__dynamic_array(char, msg, MAX_MSG_LEN)
+	),
+	TP_fast_assign(
+		WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+				       MAX_MSG_LEN, vaf->fmt,
+				       *vaf->va) >= MAX_MSG_LEN);
+	),
+	TP_printk("%s", (char *)__get_dynamic_array(msg))
+);
+
+DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_err,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_warn,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_info,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_crit,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+TRACE_EVENT(iwlwifi_dbg,
+	TP_PROTO(u32 level, bool in_interrupt, const char *function,
+		 struct va_format *vaf),
+	TP_ARGS(level, in_interrupt, function, vaf),
+	TP_STRUCT__entry(
+		__field(u32, level)
+		__field(u8, in_interrupt)
+		__string(function, function)
+		__dynamic_array(char, msg, MAX_MSG_LEN)
+	),
+	TP_fast_assign(
+		__entry->level = level;
+		__entry->in_interrupt = in_interrupt;
+		__assign_str(function, function);
+		WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+				       MAX_MSG_LEN, vaf->fmt,
+				       *vaf->va) >= MAX_MSG_LEN);
+	),
+	TP_printk("%s", (char *)__get_dynamic_array(msg))
+);
+
+#undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi
 
 TRACE_EVENT(iwlwifi_dev_hcmd,
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
new file mode 100644
index 0000000..8ff5256
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -0,0 +1,103 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/completion.h>
+
+#include "iwl-drv.h"
+#include "iwl-trans.h"
+#include "iwl-wifi.h"
+#include "iwl-op-mode.h"
+
+int iwl_drv_start(struct iwl_shared *shrd,
+		  struct iwl_trans *trans, struct iwl_cfg *cfg)
+{
+	int ret;
+
+	shrd->cfg = cfg;
+
+	shrd->nic = kzalloc(sizeof(*shrd->nic), GFP_KERNEL);
+	if (!shrd->nic) {
+		dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_nic");
+		return -ENOMEM;
+	}
+	shrd->nic->shrd = shrd;
+
+	init_completion(&shrd->nic->request_firmware_complete);
+
+	ret = iwl_request_firmware(shrd->nic, true);
+
+	if (ret) {
+		dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw");
+		kfree(shrd->nic);
+	}
+
+	return ret;
+}
+
+void iwl_drv_stop(struct iwl_shared *shrd)
+{
+	/* op_mode can be NULL if its start failed */
+	if (shrd->nic->op_mode)
+		iwl_op_mode_stop(shrd->nic->op_mode);
+
+	kfree(shrd->nic);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
new file mode 100644
index 0000000..90534a2
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.h
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_drv_h__
+#define __iwl_drv_h__
+
+#include "iwl-shared.h"
+
+/**
+ * DOC: Driver system flows - drv component
+ *
+ * This component implements the system flows such as bus enumeration, bus
+ * removal. Bus dependent parts of system flows (such as iwl_pci_probe) are in
+ * bus specific files (transport files). This is the code that is common among
+ * different buses.
+ *
+ * This component is also in charge of managing the several implementations of
+ * the wifi flows: it will allow to have several fw API implementation. These
+ * different implementations will differ in the way they implement mac80211's
+ * handlers too.
+
+ * The init flow wrt to the drv component looks like this:
+ * 1) The bus specific component is called from module_init
+ * 2) The bus specific component registers the bus driver
+ * 3) The bus driver calls the probe function
+ * 4) The bus specific component configures the bus
+ * 5) The bus specific component calls to the drv bus agnostic part
+ *    (iwl_drv_start)
+ * 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback
+ * 7) iwl_ucode_callback parses the fw file
+ * 8) iwl_ucode_callback starts the wifi implementation to matches the fw
+ */
+
+/**
+ * iwl_drv_start - start the drv
+ *
+ * @shrd: the shrd area
+ * @trans_ops: the ops of the transport
+ * @cfg: device specific constants / virtual functions
+ *
+ * TODO: review the parameters given to this function
+ *
+ * starts the driver: fetches the firmware. This should be called by bus
+ * specific system flows implementations. For example, the bus specific probe
+ * function should do bus related operations only, and then call to this
+ * function.
+ */
+int iwl_drv_start(struct iwl_shared *shrd,
+		  struct iwl_trans *trans, struct iwl_cfg *cfg);
+
+/**
+ * iwl_drv_stop - stop the drv
+ *
+ * @shrd: the shrd area
+ *
+ * TODO: review the parameters given to this function
+ *
+ * Stop the driver. This should be called by bus specific system flows
+ * implementations. For example, the bus specific remove function should first
+ * call this function and then do the bus related operations only.
+ */
+void iwl_drv_stop(struct iwl_shared *shrd);
+
+#endif /* __iwl_drv_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index d1fd1cd..07e93787 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -149,23 +149,27 @@
  * EEPROM chip, not a single event, so even reads could conflict if they
  * weren't arbitrated by the semaphore.
  */
-static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus)
+
+#define	EEPROM_SEM_TIMEOUT 10		/* milliseconds */
+#define EEPROM_SEM_RETRY_LIMIT 1000	/* number of attempts (not time) */
+
+static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
 {
 	u16 count;
 	int ret;
 
 	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
 		/* Request semaphore */
-		iwl_set_bit(trans(bus), CSR_HW_IF_CONFIG_REG,
+		iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
 		/* See if we got it */
-		ret = iwl_poll_bit(trans(bus), CSR_HW_IF_CONFIG_REG,
+		ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
 				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
 				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
 				EEPROM_SEM_TIMEOUT);
 		if (ret >= 0) {
-			IWL_DEBUG_EEPROM(trans(bus),
+			IWL_DEBUG_EEPROM(trans,
 				"Acquired semaphore after %d tries.\n",
 				count+1);
 			return ret;
@@ -175,9 +179,9 @@
 	return ret;
 }
 
-static void iwl_eeprom_release_semaphore(struct iwl_bus *bus)
+static void iwl_eeprom_release_semaphore(struct iwl_trans *trans)
 {
-	iwl_clear_bit(trans(bus), CSR_HW_IF_CONFIG_REG,
+	iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG,
 		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
 }
@@ -304,19 +308,20 @@
  *
 ******************************************************************************/
 
-static void iwl_set_otp_access(struct iwl_bus *bus, enum iwl_access_mode mode)
+static void iwl_set_otp_access(struct iwl_trans *trans,
+			       enum iwl_access_mode mode)
 {
-	iwl_read32(trans(bus), CSR_OTP_GP_REG);
+	iwl_read32(trans, CSR_OTP_GP_REG);
 
 	if (mode == IWL_OTP_ACCESS_ABSOLUTE)
-		iwl_clear_bit(trans(bus), CSR_OTP_GP_REG,
+		iwl_clear_bit(trans, CSR_OTP_GP_REG,
 			      CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 	else
-		iwl_set_bit(trans(bus), CSR_OTP_GP_REG,
+		iwl_set_bit(trans, CSR_OTP_GP_REG,
 			    CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 }
 
-static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev)
+static int iwl_get_nvm_type(struct iwl_trans *trans, u32 hw_rev)
 {
 	u32 otpgp;
 	int nvm_type;
@@ -324,7 +329,7 @@
 	/* OTP only valid for CP/PP and after */
 	switch (hw_rev & CSR_HW_REV_TYPE_MSK) {
 	case CSR_HW_REV_TYPE_NONE:
-		IWL_ERR(bus, "Unknown hardware type\n");
+		IWL_ERR(trans, "Unknown hardware type\n");
 		return -ENOENT;
 	case CSR_HW_REV_TYPE_5300:
 	case CSR_HW_REV_TYPE_5350:
@@ -333,7 +338,7 @@
 		nvm_type = NVM_DEVICE_TYPE_EEPROM;
 		break;
 	default:
-		otpgp = iwl_read32(trans(bus), CSR_OTP_GP_REG);
+		otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
 		if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
 			nvm_type = NVM_DEVICE_TYPE_OTP;
 		else
@@ -343,73 +348,74 @@
 	return  nvm_type;
 }
 
-static int iwl_init_otp_access(struct iwl_bus *bus)
+static int iwl_init_otp_access(struct iwl_trans *trans)
 {
 	int ret;
 
 	/* Enable 40MHz radio clock */
-	iwl_write32(trans(bus), CSR_GP_CNTRL,
-		    iwl_read32(trans(bus), CSR_GP_CNTRL) |
+	iwl_write32(trans, CSR_GP_CNTRL,
+		    iwl_read32(trans, CSR_GP_CNTRL) |
 		    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
 	/* wait for clock to be ready */
-	ret = iwl_poll_bit(trans(bus), CSR_GP_CNTRL,
+	ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
 				 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 				 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 				 25000);
 	if (ret < 0)
-		IWL_ERR(bus, "Time out access OTP\n");
+		IWL_ERR(trans, "Time out access OTP\n");
 	else {
-		iwl_set_bits_prph(trans(bus), APMG_PS_CTRL_REG,
+		iwl_set_bits_prph(trans, APMG_PS_CTRL_REG,
 				  APMG_PS_CTRL_VAL_RESET_REQ);
 		udelay(5);
-		iwl_clear_bits_prph(trans(bus), APMG_PS_CTRL_REG,
+		iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG,
 				    APMG_PS_CTRL_VAL_RESET_REQ);
 
 		/*
 		 * CSR auto clock gate disable bit -
 		 * this is only applicable for HW with OTP shadow RAM
 		 */
-		if (cfg(bus)->base_params->shadow_ram_support)
-			iwl_set_bit(trans(bus), CSR_DBG_LINK_PWR_MGMT_REG,
+		if (cfg(trans)->base_params->shadow_ram_support)
+			iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
 				CSR_RESET_LINK_PWR_MGMT_DISABLED);
 	}
 	return ret;
 }
 
-static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data)
+static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
+			     __le16 *eeprom_data)
 {
 	int ret = 0;
 	u32 r;
 	u32 otpgp;
 
-	iwl_write32(trans(bus), CSR_EEPROM_REG,
+	iwl_write32(trans, CSR_EEPROM_REG,
 		    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-	ret = iwl_poll_bit(trans(bus), CSR_EEPROM_REG,
+	ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
 				 CSR_EEPROM_REG_READ_VALID_MSK,
 				 CSR_EEPROM_REG_READ_VALID_MSK,
 				 IWL_EEPROM_ACCESS_TIMEOUT);
 	if (ret < 0) {
-		IWL_ERR(bus, "Time out reading OTP[%d]\n", addr);
+		IWL_ERR(trans, "Time out reading OTP[%d]\n", addr);
 		return ret;
 	}
-	r = iwl_read32(trans(bus), CSR_EEPROM_REG);
+	r = iwl_read32(trans, CSR_EEPROM_REG);
 	/* check for ECC errors: */
-	otpgp = iwl_read32(trans(bus), CSR_OTP_GP_REG);
+	otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
 	if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
 		/* stop in this case */
 		/* set the uncorrectable OTP ECC bit for acknowledgement */
-		iwl_set_bit(trans(bus), CSR_OTP_GP_REG,
+		iwl_set_bit(trans, CSR_OTP_GP_REG,
 			CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-		IWL_ERR(bus, "Uncorrectable OTP ECC error, abort OTP read\n");
+		IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n");
 		return -EINVAL;
 	}
 	if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
 		/* continue in this case */
 		/* set the correctable OTP ECC bit for acknowledgement */
-		iwl_set_bit(trans(bus), CSR_OTP_GP_REG,
+		iwl_set_bit(trans, CSR_OTP_GP_REG,
 				CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
-		IWL_ERR(bus, "Correctable OTP ECC error, continue read\n");
+		IWL_ERR(trans, "Correctable OTP ECC error, continue read\n");
 	}
 	*eeprom_data = cpu_to_le16(r >> 16);
 	return 0;
@@ -418,20 +424,20 @@
 /*
  * iwl_is_otp_empty: check for empty OTP
  */
-static bool iwl_is_otp_empty(struct iwl_bus *bus)
+static bool iwl_is_otp_empty(struct iwl_trans *trans)
 {
 	u16 next_link_addr = 0;
 	__le16 link_value;
 	bool is_empty = false;
 
 	/* locate the beginning of OTP link list */
-	if (!iwl_read_otp_word(bus, next_link_addr, &link_value)) {
+	if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) {
 		if (!link_value) {
-			IWL_ERR(bus, "OTP is empty\n");
+			IWL_ERR(trans, "OTP is empty\n");
 			is_empty = true;
 		}
 	} else {
-		IWL_ERR(bus, "Unable to read first block of OTP list.\n");
+		IWL_ERR(trans, "Unable to read first block of OTP list.\n");
 		is_empty = true;
 	}
 
@@ -448,7 +454,7 @@
  *   we should read and used to configure the device.
  *   only perform this operation if shadow RAM is disabled
  */
-static int iwl_find_otp_image(struct iwl_bus *bus,
+static int iwl_find_otp_image(struct iwl_trans *trans,
 					u16 *validblockaddr)
 {
 	u16 next_link_addr = 0, valid_addr;
@@ -456,10 +462,10 @@
 	int usedblocks = 0;
 
 	/* set addressing mode to absolute to traverse the link list */
-	iwl_set_otp_access(bus, IWL_OTP_ACCESS_ABSOLUTE);
+	iwl_set_otp_access(trans, IWL_OTP_ACCESS_ABSOLUTE);
 
 	/* checking for empty OTP or error */
-	if (iwl_is_otp_empty(bus))
+	if (iwl_is_otp_empty(trans))
 		return -EINVAL;
 
 	/*
@@ -473,9 +479,9 @@
 		 */
 		valid_addr = next_link_addr;
 		next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
-		IWL_DEBUG_EEPROM(bus, "OTP blocks %d addr 0x%x\n",
+		IWL_DEBUG_EEPROM(trans, "OTP blocks %d addr 0x%x\n",
 			       usedblocks, next_link_addr);
-		if (iwl_read_otp_word(bus, next_link_addr, &link_value))
+		if (iwl_read_otp_word(trans, next_link_addr, &link_value))
 			return -EINVAL;
 		if (!link_value) {
 			/*
@@ -490,10 +496,10 @@
 		}
 		/* more in the link list, continue */
 		usedblocks++;
-	} while (usedblocks <= cfg(bus)->base_params->max_ll_items);
+	} while (usedblocks <= cfg(trans)->base_params->max_ll_items);
 
 	/* OTP has no valid blocks */
-	IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n");
+	IWL_DEBUG_EEPROM(trans, "OTP has no valid blocks\n");
 	return -EINVAL;
 }
 
@@ -653,63 +659,62 @@
  *
  * NOTE:  This routine uses the non-debug IO access functions.
  */
-int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
+int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev)
 {
-	struct iwl_shared *shrd = priv->shrd;
 	__le16 *e;
-	u32 gp = iwl_read32(trans(priv), CSR_EEPROM_GP);
+	u32 gp = iwl_read32(trans, CSR_EEPROM_GP);
 	int sz;
 	int ret;
 	u16 addr;
 	u16 validblockaddr = 0;
 	u16 cache_addr = 0;
 
-	trans(priv)->nvm_device_type = iwl_get_nvm_type(bus(priv), hw_rev);
-	if (trans(priv)->nvm_device_type == -ENOENT)
+	trans->nvm_device_type = iwl_get_nvm_type(trans, hw_rev);
+	if (trans->nvm_device_type == -ENOENT)
 		return -ENOENT;
 	/* allocate eeprom */
-	sz = cfg(priv)->base_params->eeprom_size;
-	IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz);
-	shrd->eeprom = kzalloc(sz, GFP_KERNEL);
-	if (!shrd->eeprom) {
+	sz = cfg(trans)->base_params->eeprom_size;
+	IWL_DEBUG_EEPROM(trans, "NVM size = %d\n", sz);
+	trans->shrd->eeprom = kzalloc(sz, GFP_KERNEL);
+	if (!trans->shrd->eeprom) {
 		ret = -ENOMEM;
 		goto alloc_err;
 	}
-	e = (__le16 *)shrd->eeprom;
+	e = (__le16 *)trans->shrd->eeprom;
 
-	ret = iwl_eeprom_verify_signature(trans(priv));
+	ret = iwl_eeprom_verify_signature(trans);
 	if (ret < 0) {
-		IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
+		IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
 		ret = -ENOENT;
 		goto err;
 	}
 
 	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
-	ret = iwl_eeprom_acquire_semaphore(bus(priv));
+	ret = iwl_eeprom_acquire_semaphore(trans);
 	if (ret < 0) {
-		IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
+		IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n");
 		ret = -ENOENT;
 		goto err;
 	}
 
-	if (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
+	if (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
 
-		ret = iwl_init_otp_access(bus(priv));
+		ret = iwl_init_otp_access(trans);
 		if (ret) {
-			IWL_ERR(priv, "Failed to initialize OTP access.\n");
+			IWL_ERR(trans, "Failed to initialize OTP access.\n");
 			ret = -ENOENT;
 			goto done;
 		}
-		iwl_write32(trans(priv), CSR_EEPROM_GP,
-			    iwl_read32(trans(priv), CSR_EEPROM_GP) &
+		iwl_write32(trans, CSR_EEPROM_GP,
+			    iwl_read32(trans, CSR_EEPROM_GP) &
 			    ~CSR_EEPROM_GP_IF_OWNER_MSK);
 
-		iwl_set_bit(trans(priv), CSR_OTP_GP_REG,
+		iwl_set_bit(trans, CSR_OTP_GP_REG,
 			     CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
 			     CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
 		/* traversing the linked list if no shadow ram supported */
-		if (!cfg(priv)->base_params->shadow_ram_support) {
-			if (iwl_find_otp_image(bus(priv), &validblockaddr)) {
+		if (!cfg(trans)->base_params->shadow_ram_support) {
+			if (iwl_find_otp_image(trans, &validblockaddr)) {
 				ret = -ENOENT;
 				goto done;
 			}
@@ -718,7 +723,7 @@
 		     addr += sizeof(u16)) {
 			__le16 eeprom_data;
 
-			ret = iwl_read_otp_word(bus(priv), addr, &eeprom_data);
+			ret = iwl_read_otp_word(trans, addr, &eeprom_data);
 			if (ret)
 				goto done;
 			e[cache_addr / 2] = eeprom_data;
@@ -729,34 +734,35 @@
 		for (addr = 0; addr < sz; addr += sizeof(u16)) {
 			u32 r;
 
-			iwl_write32(trans(priv), CSR_EEPROM_REG,
+			iwl_write32(trans, CSR_EEPROM_REG,
 				    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
 
-			ret = iwl_poll_bit(trans(priv), CSR_EEPROM_REG,
+			ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
 						  CSR_EEPROM_REG_READ_VALID_MSK,
 						  CSR_EEPROM_REG_READ_VALID_MSK,
 						  IWL_EEPROM_ACCESS_TIMEOUT);
 			if (ret < 0) {
-				IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
+				IWL_ERR(trans,
+					"Time out reading EEPROM[%d]\n", addr);
 				goto done;
 			}
-			r = iwl_read32(trans(priv), CSR_EEPROM_REG);
+			r = iwl_read32(trans, CSR_EEPROM_REG);
 			e[addr / 2] = cpu_to_le16(r >> 16);
 		}
 	}
 
-	IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
-		       (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+	IWL_DEBUG_EEPROM(trans, "NVM Type: %s, version: 0x%x\n",
+		       (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP)
 		       ? "OTP" : "EEPROM",
-		       iwl_eeprom_query16(shrd, EEPROM_VERSION));
+		       iwl_eeprom_query16(trans->shrd, EEPROM_VERSION));
 
 	ret = 0;
 done:
-	iwl_eeprom_release_semaphore(bus(priv));
+	iwl_eeprom_release_semaphore(trans);
 
 err:
 	if (ret)
-		iwl_eeprom_free(priv->shrd);
+		iwl_eeprom_free(trans->shrd);
 alloc_err:
 	return ret;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 13f2d39..cbb8611 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -67,6 +67,7 @@
 
 struct iwl_priv;
 struct iwl_shared;
+struct iwl_trans;
 
 /*
  * EEPROM access time values:
@@ -305,7 +306,7 @@
 };
 
 
-int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev);
+int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev);
 void iwl_eeprom_free(struct iwl_shared *shrd);
 int  iwl_eeprom_check_version(struct iwl_priv *priv);
 int  iwl_eeprom_check_sku(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
index d8025fe..03f7705 100644
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
@@ -51,8 +51,8 @@
 #include "iwl-agn-calib.h"
 #include "iwl-agn.h"
 #include "iwl-shared.h"
-#include "iwl-bus.h"
 #include "iwl-trans.h"
+#include "iwl-op-mode.h"
 
 /*****************************************************************************
  *
@@ -136,7 +136,7 @@
  * other mac80211 functions grouped here.
  */
 int iwlagn_mac_setup_register(struct iwl_priv *priv,
-				  struct iwlagn_ucode_capabilities *capa)
+				  struct iwl_ucode_capabilities *capa)
 {
 	int ret;
 	struct ieee80211_hw *hw = priv->hw;
@@ -195,7 +195,7 @@
 			    WIPHY_FLAG_DISABLE_BEACON_HINTS |
 			    WIPHY_FLAG_IBSS_RSN;
 
-	if (trans(priv)->ucode_wowlan.code.len &&
+	if (nic(priv)->fw.ucode_wowlan.code.len &&
 	    device_can_wakeup(trans(priv)->dev)) {
 		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
 					  WIPHY_WOWLAN_DISCONNECT |
@@ -296,7 +296,7 @@
 
  error:
 	set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-	__iwl_down(priv);
+	iwl_down(priv);
 	clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
 
 	IWL_ERR(priv, "Unable to initialize device.\n");
@@ -305,7 +305,7 @@
 
 static int iwlagn_mac_start(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	int ret;
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -332,7 +332,7 @@
 
 static void iwlagn_mac_stop(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 
@@ -341,9 +341,13 @@
 
 	priv->is_open = 0;
 
+	mutex_lock(&priv->shrd->mutex);
 	iwl_down(priv);
+	mutex_unlock(&priv->shrd->mutex);
 
-	flush_workqueue(priv->shrd->workqueue);
+	iwl_cancel_deferred_work(priv);
+
+	flush_workqueue(priv->workqueue);
 
 	/* User space software may expect getting rfkill changes
 	 * even if interface is down, trans->down will leave the RF
@@ -358,7 +362,7 @@
 				      struct ieee80211_vif *vif,
 				      struct cfg80211_gtk_rekey_data *data)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
 	if (iwlagn_mod_params.sw_crypto)
 		return;
@@ -385,7 +389,7 @@
 static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
 			      struct cfg80211_wowlan *wowlan)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 	int ret;
 
@@ -427,7 +431,7 @@
 
 static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 	struct ieee80211_vif *vif;
 	unsigned long flags;
@@ -453,17 +457,17 @@
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 		if (ret == 0) {
-			struct iwl_trans *trans = trans(priv);
+			struct iwl_nic *nic = nic(priv);
 			if (!priv->wowlan_sram)
 				priv->wowlan_sram =
-					kzalloc(trans->ucode_wowlan.data.len,
+					kzalloc(nic->fw.ucode_wowlan.data.len,
 						GFP_KERNEL);
 
 			if (priv->wowlan_sram)
 				_iwl_read_targ_mem_words(
 					trans(priv), 0x800000,
 					priv->wowlan_sram,
-					trans->ucode_wowlan.data.len / 4);
+					nic->fw.ucode_wowlan.data.len / 4);
 		}
 #endif
 	}
@@ -493,7 +497,7 @@
 
 static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
 	IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
 		     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
@@ -508,7 +512,7 @@
 				       struct ieee80211_sta *sta,
 				       u32 iv32, u16 *phase1key)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
 	iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
 }
@@ -518,7 +522,7 @@
 			      struct ieee80211_sta *sta,
 			      struct ieee80211_key_conf *key)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 	struct iwl_rxon_context *ctx = vif_priv->ctx;
 	int ret;
@@ -622,7 +626,7 @@
 				   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
 				   u8 buf_size)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	int ret = -EINVAL;
 	struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
 
@@ -688,7 +692,7 @@
 			      struct ieee80211_vif *vif,
 			      struct ieee80211_sta *sta)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
 	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 	bool is_ap = vif->type == NL80211_IFTYPE_STATION;
@@ -731,7 +735,7 @@
 static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
 				struct ieee80211_channel_switch *ch_switch)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	const struct iwl_channel_info *ch_info;
 	struct ieee80211_conf *conf = &hw->conf;
 	struct ieee80211_channel *channel = ch_switch->channel;
@@ -818,7 +822,7 @@
 				    unsigned int *total_flags,
 				    u64 multicast)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	__le32 filter_or = 0, filter_nand = 0;
 	struct iwl_rxon_context *ctx;
 
@@ -865,7 +869,7 @@
 
 static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
 	mutex_lock(&priv->shrd->mutex);
 	IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -902,7 +906,7 @@
 				     enum nl80211_channel_type channel_type,
 				     int duration)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
 	int err = 0;
 
@@ -992,7 +996,7 @@
 
 static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
 	if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
 		return -EOPNOTSUPP;
@@ -1012,7 +1016,7 @@
 			      const u8 *bssid,
 			      enum ieee80211_tx_sync_type type)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 	struct iwl_rxon_context *ctx = vif_priv->ctx;
 	int ret;
@@ -1066,7 +1070,7 @@
 				   const u8 *bssid,
 				   enum ieee80211_tx_sync_type type)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 	struct iwl_rxon_context *ctx = vif_priv->ctx;
 
@@ -1090,7 +1094,7 @@
 static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
 			   enum ieee80211_rssi_event rssi_event)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 	mutex_lock(&priv->shrd->mutex);
@@ -1115,9 +1119,9 @@
 static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
 			   struct ieee80211_sta *sta, bool set)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
-	queue_work(priv->shrd->workqueue, &priv->beacon_update);
+	queue_work(priv->workqueue, &priv->beacon_update);
 
 	return 0;
 }
@@ -1126,7 +1130,7 @@
 		    struct ieee80211_vif *vif, u16 queue,
 		    const struct ieee80211_tx_queue_params *params)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 	struct iwl_rxon_context *ctx = vif_priv->ctx;
 	unsigned long flags;
@@ -1169,7 +1173,7 @@
 
 static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
 	return priv->ibss_manager == IWL_IBSS_MANAGER;
 }
@@ -1223,7 +1227,7 @@
 static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 	struct iwl_rxon_context *tmp, *ctx = NULL;
 	int err;
@@ -1320,7 +1324,7 @@
 static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
 			      struct ieee80211_vif *vif)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -1348,7 +1352,7 @@
 				struct ieee80211_vif *vif,
 				enum nl80211_iftype newtype, bool newp2p)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 	struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 	struct iwl_rxon_context *tmp;
@@ -1434,7 +1438,7 @@
 		    struct ieee80211_vif *vif,
 		    struct cfg80211_scan_request *req)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	int ret;
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -1480,7 +1484,7 @@
 		       struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
 	int ret;
 
@@ -1519,7 +1523,7 @@
 			   enum sta_notify_cmd cmd,
 			   struct ieee80211_sta *sta)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
 	int sta_id;
 
@@ -1587,15 +1591,18 @@
 struct ieee80211_hw *iwl_alloc_all(void)
 {
 	struct iwl_priv *priv;
+	struct iwl_op_mode *op_mode;
 	/* mac80211 allocates memory for this device instance, including
 	 *   space for this driver's private structure */
 	struct ieee80211_hw *hw;
 
-	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
+	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv) +
+				sizeof(struct iwl_op_mode), &iwlagn_hw_ops);
 	if (!hw)
 		goto out;
 
-	priv = hw->priv;
+	op_mode = hw->priv;
+	priv = IWL_OP_MODE_GET_DVM(op_mode);
 	priv->hw = hw;
 
 out:
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
new file mode 100644
index 0000000..d4fc9be
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -0,0 +1,198 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#ifndef __iwl_op_mode_h__
+#define __iwl_op_mode_h__
+
+struct iwl_op_mode;
+struct iwl_trans;
+struct sk_buff;
+struct iwl_device_cmd;
+struct iwl_rx_mem_buffer;
+
+/**
+ * DOC: Operational mode - what is it ?
+ *
+ * The operational mode (a.k.a. op_mode) is the layer that implements
+ * mac80211's handlers. It knows two APIs: mac80211's and the fw's. It uses
+ * the transport API to access the HW. The op_mode doesn't need to know how the
+ * underlying HW works, since the transport layer takes care of that.
+ *
+ * There can be several op_mode: i.e. different fw APIs will require two
+ * different op_modes. This is why the op_mode is virtualized.
+ */
+
+/**
+ * DOC: Life cycle of the Operational mode
+ *
+ * The operational mode has a very simple life cycle.
+ *
+ *	1) The driver layer (iwl-drv.c) chooses the op_mode based on the
+ *	   capabilities advertized by the fw file (in TLV format).
+ *	2) The driver layer starts the op_mode (ops->start)
+ *	3) The op_mode registers registers mac80211
+ *	4) The op_mode is governed by mac80211
+ *	5) The driver layer stops the op_mode
+ */
+
+/**
+ * struct iwl_op_mode_ops - op_mode specific operations
+ *
+ * The op_mode exports its ops so that external components can start it and
+ * interact with it. The driver layer typically calls the start and stop
+ * handlers, the transport layer calls the others.
+ *
+ * All the handlers MUST be implemented
+ *
+ * @start: start the op_mode. The transport layer is already allocated.
+ *	May sleep
+ * @stop: stop the op_mode. Must free all the memory allocated.
+ *	May sleep
+ * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
+ *	HCMD the this Rx responds to.
+ *	Must be atomic.
+ * @queue_full: notifies that a HW queue is full. Ac is the ac of the queue
+ *	Must be atomic
+ * @queue_not_full: notifies that a HW queue is not full any more.
+ *	Ac is the ac of the queue. Must be atomic
+ * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
+ *	the radio is killed. Must be atomic.
+ * @free_skb: allows the transport layer to free skbs that haven't been
+ *	reclaimed by the op_mode. This can happen when the driver is freed and
+ *	there are Tx packets pending in the transport layer.
+ *	Must be atomic
+ * @nic_error: error notification. Must be atomic
+ */
+struct iwl_op_mode_ops {
+	struct iwl_op_mode *(*start)(struct iwl_trans *trans);
+	void (*stop)(struct iwl_op_mode *op_mode);
+	int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_mem_buffer *rxb,
+		  struct iwl_device_cmd *cmd);
+	void (*queue_full)(struct iwl_op_mode *op_mode, u8 ac);
+	void (*queue_not_full)(struct iwl_op_mode *op_mode, u8 ac);
+	void (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
+	void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
+	void (*nic_error)(struct iwl_op_mode *op_mode);
+};
+
+/**
+ * struct iwl_op_mode - operational mode
+ *
+ * This holds an implementation of the mac80211 / fw API.
+ *
+ * @ops - pointer to its own ops
+ */
+struct iwl_op_mode {
+	const struct iwl_op_mode_ops *ops;
+	const struct iwl_trans *trans;
+
+	char op_mode_specific[0] __aligned(sizeof(void *));
+};
+
+static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode)
+{
+	might_sleep();
+
+	op_mode->ops->stop(op_mode);
+}
+
+static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode,
+				  struct iwl_rx_mem_buffer *rxb,
+				  struct iwl_device_cmd *cmd)
+{
+	return op_mode->ops->rx(op_mode, rxb, cmd);
+}
+
+static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, u8 ac)
+{
+	op_mode->ops->queue_full(op_mode, ac);
+}
+
+static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode,
+					      u8 ac)
+{
+	op_mode->ops->queue_not_full(op_mode, ac);
+}
+
+static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode,
+					  bool state)
+{
+	op_mode->ops->hw_rf_kill(op_mode, state);
+}
+
+static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode,
+					struct sk_buff *skb)
+{
+	op_mode->ops->free_skb(op_mode, skb);
+}
+
+static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode)
+{
+	op_mode->ops->nic_error(op_mode);
+}
+
+/*****************************************************
+* Op mode layers implementations
+******************************************************/
+extern const struct iwl_op_mode_ops iwl_dvm_ops;
+
+#endif /* __iwl_op_mode_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c
index 3e2fce4..06e0041 100644
--- a/drivers/net/wireless/iwlwifi/iwl-pci.c
+++ b/drivers/net/wireless/iwlwifi/iwl-pci.c
@@ -64,12 +64,13 @@
 #include <linux/pci.h>
 #include <linux/pci-aspm.h>
 
-#include "iwl-bus.h"
 #include "iwl-io.h"
 #include "iwl-shared.h"
 #include "iwl-trans.h"
 #include "iwl-csr.h"
 #include "iwl-cfg.h"
+#include "iwl-drv.h"
+#include "iwl-trans.h"
 
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
 	.vendor = PCI_VENDOR_ID_INTEL,  .device = (dev), \
@@ -157,9 +158,9 @@
 	{IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
 	{IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
 	{IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0x1341, iwl6005_2agn_d_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_cfg)},/* low 5GHz active */
-	{IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_cfg)},/* high 5GHz active */
+	{IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */
+	{IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */
 
 /* 6x30 Series */
 	{IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
@@ -240,6 +241,7 @@
 	{IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
 	{IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
 	{IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
 
 /* 105 Series */
 	{IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
@@ -262,44 +264,40 @@
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
-	struct iwl_bus *bus;
+	struct iwl_shared *shrd;
+	struct iwl_trans *iwl_trans;
 	int err;
 
-	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
-	if (!bus) {
-		dev_printk(KERN_ERR, &pdev->dev,
-			   "Couldn't allocate iwl_pci_bus");
-		return -ENOMEM;
-	}
-
-	bus->shrd = kzalloc(sizeof(*bus->shrd), GFP_KERNEL);
-	if (!bus->shrd) {
+	shrd = kzalloc(sizeof(*iwl_trans->shrd), GFP_KERNEL);
+	if (!shrd) {
 		dev_printk(KERN_ERR, &pdev->dev,
 			   "Couldn't allocate iwl_shared");
 		err = -ENOMEM;
 		goto out_free_bus;
 	}
 
-	bus->shrd->bus = bus;
-
-	pci_set_drvdata(pdev, bus);
-
 #ifdef CONFIG_IWLWIFI_IDI
-	trans(bus) = iwl_trans_idi_alloc(bus->shrd, pdev, ent);
-	if (trans(bus) == NULL) {
+	iwl_trans = iwl_trans_idi_alloc(shrd, pdev, ent);
+	if (iwl_trans == NULL) {
 		err = -ENOMEM;
 		goto out_free_bus;
 	}
 
-	err = iwl_probe(bus, &trans_ops_idi, cfg);
+	shrd->trans = iwl_trans;
+	pci_set_drvdata(pdev, iwl_trans);
+
+	err = iwl_drv_start(shrd, iwl_trans, cfg);
 #else
-	trans(bus) = iwl_trans_pcie_alloc(bus->shrd, pdev, ent);
-	if (trans(bus) == NULL) {
+	iwl_trans = iwl_trans_pcie_alloc(shrd, pdev, ent);
+	if (iwl_trans == NULL) {
 		err = -ENOMEM;
 		goto out_free_bus;
 	}
 
-	err = iwl_probe(bus, &trans_ops_pcie, cfg);
+	shrd->trans = iwl_trans;
+	pci_set_drvdata(pdev, iwl_trans);
+
+	err = iwl_drv_start(shrd, iwl_trans, cfg);
 #endif
 	if (err)
 		goto out_free_trans;
@@ -307,26 +305,24 @@
 	return 0;
 
 out_free_trans:
-	iwl_trans_free(trans(bus));
+	iwl_trans_free(iwl_trans);
 	pci_set_drvdata(pdev, NULL);
 out_free_bus:
-	kfree(bus->shrd);
-	kfree(bus);
+	kfree(shrd);
 	return err;
 }
 
 static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 {
-	struct iwl_bus *bus = pci_get_drvdata(pdev);
-	struct iwl_shared *shrd = bus->shrd;
+	struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
+	struct iwl_shared *shrd = iwl_trans->shrd;
 
-	iwl_remove(shrd->priv);
+	iwl_drv_stop(shrd);
 	iwl_trans_free(shrd->trans);
 
 	pci_set_drvdata(pdev, NULL);
 
-	kfree(bus->shrd);
-	kfree(bus);
+	kfree(shrd);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -334,22 +330,20 @@
 static int iwl_pci_suspend(struct device *device)
 {
 	struct pci_dev *pdev = to_pci_dev(device);
-	struct iwl_bus *bus = pci_get_drvdata(pdev);
-	struct iwl_shared *shrd = bus->shrd;
+	struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
 
 	/* Before you put code here, think about WoWLAN. You cannot check here
 	 * whether WoWLAN is enabled or not, and your code will run even if
 	 * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx.
 	 */
 
-	return iwl_trans_suspend(shrd->trans);
+	return iwl_trans_suspend(iwl_trans);
 }
 
 static int iwl_pci_resume(struct device *device)
 {
 	struct pci_dev *pdev = to_pci_dev(device);
-	struct iwl_bus *bus = pci_get_drvdata(pdev);
-	struct iwl_shared *shrd = bus->shrd;
+	struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
 
 	/* Before you put code here, think about WoWLAN. You cannot check here
 	 * whether WoWLAN is enabled or not, and your code will run even if
@@ -362,7 +356,7 @@
 	 */
 	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
 
-	return iwl_trans_resume(shrd->trans);
+	return iwl_trans_resume(iwl_trans);
 }
 
 static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 7f2e3a1..42ee1c4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -218,7 +218,7 @@
 int iwl_scan_cancel(struct iwl_priv *priv)
 {
 	IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
-	queue_work(priv->shrd->workqueue, &priv->abort_scan);
+	queue_work(priv->workqueue, &priv->abort_scan);
 	return 0;
 }
 
@@ -354,7 +354,7 @@
 	 */
 	set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
 	clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
-	queue_work(priv->shrd->workqueue, &priv->scan_completed);
+	queue_work(priv->workqueue, &priv->scan_completed);
 
 	if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
 	    iwl_advanced_bt_coexist(priv) &&
@@ -374,7 +374,7 @@
 				IWL_BT_COEX_TRAFFIC_LOAD_NONE;
 		}
 		priv->bt_status = scan_notif->bt_status;
-		queue_work(priv->shrd->workqueue,
+		queue_work(priv->workqueue,
 			   &priv->bt_traffic_change_work);
 	}
 	return 0;
@@ -950,7 +950,7 @@
 		return ret;
 	}
 
-	queue_delayed_work(priv->shrd->workqueue, &priv->scan_check,
+	queue_delayed_work(priv->workqueue, &priv->scan_check,
 			   IWL_SCAN_CHECK_WATCHDOG);
 
 	return 0;
@@ -963,7 +963,7 @@
  */
 void iwl_internal_short_hw_scan(struct iwl_priv *priv)
 {
-	queue_work(priv->shrd->workqueue, &priv->start_internal_scan);
+	queue_work(priv->workqueue, &priv->start_internal_scan);
 }
 
 static void iwl_bg_start_internal_scan(struct work_struct *work)
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index 63d4a4f..a644162 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -94,7 +94,6 @@
  * This implementation is iwl-pci.c
  */
 
-struct iwl_bus;
 struct iwl_priv;
 struct iwl_trans;
 struct iwl_sensitivity_ranges;
@@ -173,8 +172,6 @@
  * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX)
  * @sku: sku read from EEPROM
  * @rx_page_order: Rx buffer page order
- * @max_inst_size: for ucode use
- * @max_data_size: for ucode use
  * @ct_kill_threshold: temperature threshold - in hw dependent unit
  * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
  *	relevant for 1000, 6000 and up
@@ -192,8 +189,6 @@
 	bool shadow_reg_enable;
 	u16 sku;
 	u32 rx_page_order;
-	u32 max_inst_size;
-	u32 max_data_size;
 	u32 ct_kill_threshold;
 	u32 ct_kill_exit_threshold;
 	unsigned int wd_timeout;
@@ -283,6 +278,8 @@
  * @ucode_api_ok: oldest version of the uCode API that is OK to load
  *	without a warning, for use in transitions
  * @ucode_api_min: Lowest version of uCode API supported by driver.
+ * @max_inst_size: The maximal length of the fw inst section
+ * @max_data_size: The maximal length of the fw data section
  * @valid_tx_ant: valid transmit antenna
  * @valid_rx_ant: valid receive antenna
  * @sku: sku information from EEPROM
@@ -320,6 +317,8 @@
 	const unsigned int ucode_api_max;
 	const unsigned int ucode_api_ok;
 	const unsigned int ucode_api_min;
+	const u32 max_data_size;
+	const u32 max_inst_size;
 	u8   valid_tx_ant;
 	u8   valid_rx_ant;
 	u16  sku;
@@ -358,8 +357,8 @@
  * @cfg: see struct iwl_cfg
  * @priv: pointer to the upper layer data
  * @trans: pointer to the transport layer data
+ * @nic: pointer to the nic data
  * @hw_params: see struct iwl_hw_params
- * @workqueue: the workqueue used by all the layers of the driver
  * @lock: protect general shared data
  * @sta_lock: protects the station table.
  *	If lock and sta_lock are needed, lock must be acquired first.
@@ -385,13 +384,12 @@
 	bool wowlan;
 	u8 valid_contexts;
 
-	struct iwl_bus *bus;
 	struct iwl_cfg *cfg;
 	struct iwl_priv *priv;
 	struct iwl_trans *trans;
+	struct iwl_nic *nic;
 	struct iwl_hw_params hw_params;
 
-	struct workqueue_struct *workqueue;
 	spinlock_t lock;
 	spinlock_t sta_lock;
 	struct mutex mutex;
@@ -416,10 +414,10 @@
 
 };
 
-/*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */
+/*Whatever _m is (iwl_trans, iwl_priv, these macros will work */
 #define priv(_m)	((_m)->shrd->priv)
 #define cfg(_m)		((_m)->shrd->cfg)
-#define bus(_m)		((_m)->shrd->bus)
+#define nic(_m)		((_m)->shrd->nic)
 #define trans(_m)	((_m)->shrd->trans)
 #define hw_params(_m)	((_m)->shrd->hw_params)
 
@@ -531,24 +529,11 @@
 	NUM_IWL_RXON_CTX
 };
 
-int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
-		struct iwl_cfg *cfg);
-void __devexit iwl_remove(struct iwl_priv * priv);
-struct iwl_device_cmd;
-int __must_check iwl_rx_dispatch(struct iwl_priv *priv,
-				 struct iwl_rx_mem_buffer *rxb,
-				 struct iwl_device_cmd *cmd);
-
 int iwlagn_hw_valid_rtc_data_addr(u32 addr);
-void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state);
 void iwl_nic_config(struct iwl_priv *priv);
-void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb);
-void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
 const char *get_cmd_string(u8 cmd);
 bool iwl_check_for_ct_kill(struct iwl_priv *priv);
 
-void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac);
-void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac);
 
 /* notification wait support */
 void iwl_abort_notification_waits(struct iwl_shared *shrd);
@@ -568,20 +553,6 @@
 iwl_remove_notification(struct iwl_shared *shrd,
 			   struct iwl_notification_wait *wait_entry);
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-void iwl_reset_traffic_log(struct iwl_priv *priv);
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-			     enum iwl_rxon_context_id ctxid);
-#else
-static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-					   enum iwl_rxon_context_id ctxid)
-{
-}
-#endif
-
 #define IWL_CMD(x) case x: return #x
 #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c
index df7ab33..23eea06 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c
@@ -78,9 +78,15 @@
 #include "iwl-agn.h"
 #include "iwl-testmode.h"
 #include "iwl-trans.h"
-#include "iwl-bus.h"
 #include "iwl-fh.h"
 
+
+/* Periphery registers absolute lower bound. This is used in order to
+ * differentiate registery access through HBUS_TARG_PRPH_* and
+ * HBUS_TARG_MEM_* accesses.
+ */
+#define IWL_TM_ABS_PRPH_START (0xA00000)
+
 /* The TLVs used in the gnl message policy between the kernel module and
  * user space application. iwl_testmode_gnl_msg_policy is to be carried
  * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
@@ -110,9 +116,9 @@
 
 	[IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
 
-	[IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, },
+	[IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, },
 
 	[IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, },
 	[IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, },
@@ -172,7 +178,7 @@
 	skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
 								GFP_ATOMIC);
 	if (skb == NULL) {
-		IWL_DEBUG_INFO(priv,
+		IWL_ERR(priv,
 			 "Run out of memory for messages to user space ?\n");
 		return;
 	}
@@ -183,24 +189,24 @@
 
 nla_put_failure:
 	kfree_skb(skb);
-	IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n");
+	IWL_ERR(priv, "Ouch, overran buffer, check allocation!\n");
 }
 
 void iwl_testmode_init(struct iwl_priv *priv)
 {
 	priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
 	priv->testmode_trace.trace_enabled = false;
-	priv->testmode_sram.sram_readed = false;
+	priv->testmode_mem.read_in_progress = false;
 }
 
-static void iwl_sram_cleanup(struct iwl_priv *priv)
+static void iwl_mem_cleanup(struct iwl_priv *priv)
 {
-	if (priv->testmode_sram.sram_readed) {
-		kfree(priv->testmode_sram.buff_addr);
-		priv->testmode_sram.buff_addr = NULL;
-		priv->testmode_sram.buff_size = 0;
-		priv->testmode_sram.num_chunks = 0;
-		priv->testmode_sram.sram_readed = false;
+	if (priv->testmode_mem.read_in_progress) {
+		kfree(priv->testmode_mem.buff_addr);
+		priv->testmode_mem.buff_addr = NULL;
+		priv->testmode_mem.buff_size = 0;
+		priv->testmode_mem.num_chunks = 0;
+		priv->testmode_mem.read_in_progress = false;
 	}
 }
 
@@ -226,9 +232,10 @@
 void iwl_testmode_cleanup(struct iwl_priv *priv)
 {
 	iwl_trace_cleanup(priv);
-	iwl_sram_cleanup(priv);
+	iwl_mem_cleanup(priv);
 }
 
+
 /*
  * This function handles the user application commands to the ucode.
  *
@@ -237,35 +244,80 @@
  * host command to the ucode.
  *
  * If any mandatory field is missing, -ENOMSG is replied to the user space
- * application; otherwise, the actual execution result of the host command to
- * ucode is replied.
+ * application; otherwise, waits for the host command to be sent and checks
+ * the return code. In case or error, it is returned, otherwise a reply is
+ * allocated and the reply RX packet
+ * is returned.
  *
  * @hw: ieee80211_hw object that represents the device
  * @tb: gnl message fields from the user space
  */
 static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_host_cmd cmd;
+	struct iwl_rx_packet *pkt;
+	struct sk_buff *skb;
+	void *reply_buf;
+	u32 reply_len;
+	int ret;
+	bool cmd_want_skb;
 
 	memset(&cmd, 0, sizeof(struct iwl_host_cmd));
 
 	if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
 	    !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
-		IWL_DEBUG_INFO(priv,
-			"Error finding ucode command mandatory fields\n");
+		IWL_ERR(priv, "Missing ucode command mandatory fields\n");
 		return -ENOMSG;
 	}
 
-	cmd.flags = CMD_ON_DEMAND;
+	cmd.flags = CMD_ON_DEMAND | CMD_SYNC;
+	cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]);
+	if (cmd_want_skb)
+		cmd.flags |= CMD_WANT_SKB;
+
 	cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
 	cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
 	cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
 	cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-	IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
+	IWL_DEBUG_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
 				" len %d\n", cmd.id, cmd.flags, cmd.len[0]);
-	/* ok, let's submit the command to ucode */
-	return iwl_trans_send_cmd(trans(priv), &cmd);
+
+	ret = iwl_trans_send_cmd(trans(priv), &cmd);
+	if (ret) {
+		IWL_ERR(priv, "Failed to send hcmd\n");
+		return ret;
+	}
+	if (!cmd_want_skb)
+		return ret;
+
+	/* Handling return of SKB to the user */
+	pkt = (struct iwl_rx_packet *)cmd.reply_page;
+	if (!pkt) {
+		IWL_ERR(priv, "HCMD received a null response packet\n");
+		return ret;
+	}
+
+	reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, reply_len + 20);
+	reply_buf = kmalloc(reply_len, GFP_KERNEL);
+	if (!skb || !reply_buf) {
+		kfree_skb(skb);
+		kfree(reply_buf);
+		return -ENOMEM;
+	}
+
+	/* The reply is in a page, that we cannot send to user space. */
+	memcpy(reply_buf, &(pkt->hdr), reply_len);
+	iwl_free_pages(priv->shrd, cmd.reply_page);
+
+	NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
+	NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf);
+	return cfg80211_testmode_reply(skb);
+
+nla_put_failure:
+	IWL_DEBUG_INFO(priv, "Failed creating NL attributes\n");
+	return -ENOMSG;
 }
 
 
@@ -288,14 +340,14 @@
  */
 static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	u32 ofs, val32, cmd;
 	u8 val8;
 	struct sk_buff *skb;
 	int status = 0;
 
 	if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
-		IWL_DEBUG_INFO(priv, "Error finding register offset\n");
+		IWL_ERR(priv, "Missing register offset\n");
 		return -ENOMSG;
 	}
 	ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
@@ -309,7 +361,7 @@
 		cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 ||
 		cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) &&
 		(ofs >= FH_MEM_UPPER_BOUND)) {
-		IWL_DEBUG_INFO(priv, "offset out of segment (0x0 - 0x%x)\n",
+		IWL_ERR(priv, "offset out of segment (0x0 - 0x%x)\n",
 			FH_MEM_UPPER_BOUND);
 		return -EINVAL;
 	}
@@ -321,19 +373,17 @@
 
 		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
 		if (!skb) {
-			IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+			IWL_ERR(priv, "Memory allocation fail\n");
 			return -ENOMEM;
 		}
 		NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
 		status = cfg80211_testmode_reply(skb);
 		if (status < 0)
-			IWL_DEBUG_INFO(priv,
-				       "Error sending msg : %d\n", status);
+			IWL_ERR(priv, "Error sending msg : %d\n", status);
 		break;
 	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
 		if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
-			IWL_DEBUG_INFO(priv,
-				       "Error finding value to write\n");
+			IWL_ERR(priv, "Missing value to write\n");
 			return -ENOMSG;
 		} else {
 			val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
@@ -343,7 +393,7 @@
 		break;
 	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
 		if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
-			IWL_DEBUG_INFO(priv, "Error finding value to write\n");
+			IWL_ERR(priv, "Missing value to write\n");
 			return -ENOMSG;
 		} else {
 			val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
@@ -351,34 +401,8 @@
 			iwl_write8(trans(priv), ofs, val8);
 		}
 		break;
-	case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
-		val32 = iwl_read_prph(trans(priv), ofs);
-		IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
-
-		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
-		if (!skb) {
-			IWL_DEBUG_INFO(priv, "Error allocating memory\n");
-			return -ENOMEM;
-		}
-		NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
-		status = cfg80211_testmode_reply(skb);
-		if (status < 0)
-			IWL_DEBUG_INFO(priv,
-					"Error sending msg : %d\n", status);
-		break;
-	case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
-		if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
-			IWL_DEBUG_INFO(priv,
-					"Error finding value to write\n");
-			return -ENOMSG;
-		} else {
-			val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
-			IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
-			iwl_write_prph(trans(priv), ofs, val32);
-		}
-		break;
 	default:
-		IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
+		IWL_ERR(priv, "Unknown testmode register command ID\n");
 		return -ENOSYS;
 	}
 
@@ -400,14 +424,13 @@
 				      NULL, NULL);
 	ret = iwl_init_alive_start(trans(priv));
 	if (ret) {
-		IWL_DEBUG_INFO(priv,
-			"Error configuring init calibration: %d\n", ret);
+		IWL_ERR(priv, "Fail init calibration: %d\n", ret);
 		goto cfg_init_calib_error;
 	}
 
 	ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ);
 	if (ret)
-		IWL_DEBUG_INFO(priv, "Error detecting"
+		IWL_ERR(priv, "Error detecting"
 			" CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
 	return ret;
 
@@ -434,7 +457,7 @@
  */
 static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_trans *trans = trans(priv);
 	struct sk_buff *skb;
 	unsigned char *rsp_data_ptr = NULL;
@@ -448,8 +471,7 @@
 		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
 							rsp_data_len + 20);
 		if (!skb) {
-			IWL_DEBUG_INFO(priv,
-				       "Error allocating memory\n");
+			IWL_ERR(priv, "Memory allocation fail\n");
 			return -ENOMEM;
 		}
 		NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
@@ -458,15 +480,13 @@
 			rsp_data_len, rsp_data_ptr);
 		status = cfg80211_testmode_reply(skb);
 		if (status < 0)
-			IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
-				       status);
+			IWL_ERR(priv, "Error sending msg : %d\n", status);
 		break;
 
 	case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
 		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT);
 		if (status)
-			IWL_DEBUG_INFO(priv,
-				"Error loading init ucode: %d\n", status);
+			IWL_ERR(priv, "Error loading init ucode: %d\n", status);
 		break;
 
 	case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
@@ -477,13 +497,13 @@
 	case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
 		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR);
 		if (status) {
-			IWL_DEBUG_INFO(priv,
+			IWL_ERR(priv,
 				"Error loading runtime ucode: %d\n", status);
 			break;
 		}
 		status = iwl_alive_start(priv);
 		if (status)
-			IWL_DEBUG_INFO(priv,
+			IWL_ERR(priv,
 				"Error starting the device: %d\n", status);
 		break;
 
@@ -492,13 +512,13 @@
 		iwl_trans_stop_device(trans);
 		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN);
 		if (status) {
-			IWL_DEBUG_INFO(priv,
+			IWL_ERR(priv,
 				"Error loading WOWLAN ucode: %d\n", status);
 			break;
 		}
 		status = iwl_alive_start(priv);
 		if (status)
-			IWL_DEBUG_INFO(priv,
+			IWL_ERR(priv,
 				"Error starting the device: %d\n", status);
 		break;
 
@@ -507,8 +527,7 @@
 			skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
 				cfg(priv)->base_params->eeprom_size + 20);
 			if (!skb) {
-				IWL_DEBUG_INFO(priv,
-				       "Error allocating memory\n");
+				IWL_ERR(priv, "Memory allocation fail\n");
 				return -ENOMEM;
 			}
 			NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
@@ -518,35 +537,34 @@
 				priv->shrd->eeprom);
 			status = cfg80211_testmode_reply(skb);
 			if (status < 0)
-				IWL_DEBUG_INFO(priv,
-					       "Error sending msg : %d\n",
-					       status);
+				IWL_ERR(priv, "Error sending msg : %d\n",
+					status);
 		} else
 			return -EFAULT;
 		break;
 
 	case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
 		if (!tb[IWL_TM_ATTR_FIXRATE]) {
-			IWL_DEBUG_INFO(priv,
-				       "Error finding fixrate setting\n");
+			IWL_ERR(priv, "Missing fixrate setting\n");
 			return -ENOMSG;
 		}
 		priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
 		break;
 
 	case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
-		IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver);
+		IWL_INFO(priv, "uCode version raw: 0x%x\n",
+			 nic(priv)->fw.ucode_ver);
 
 		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
 		if (!skb) {
-			IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+			IWL_ERR(priv, "Memory allocation fail\n");
 			return -ENOMEM;
 		}
-		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver);
+		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION,
+			    nic(priv)->fw.ucode_ver);
 		status = cfg80211_testmode_reply(skb);
 		if (status < 0)
-			IWL_DEBUG_INFO(priv,
-					"Error sending msg : %d\n", status);
+			IWL_ERR(priv, "Error sending msg : %d\n", status);
 		break;
 
 	case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
@@ -555,40 +573,39 @@
 
 		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
 		if (!skb) {
-			IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+			IWL_ERR(priv, "Memory allocation fail\n");
 			return -ENOMEM;
 		}
 		NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid);
 		status = cfg80211_testmode_reply(skb);
 		if (status < 0)
-			IWL_DEBUG_INFO(priv,
-					"Error sending msg : %d\n", status);
+			IWL_ERR(priv, "Error sending msg : %d\n", status);
 		break;
 
 	case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
 		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
 		if (!skb) {
-			IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+			IWL_ERR(priv, "Memory allocation fail\n");
 			return -ENOMEM;
 		}
 		switch (priv->shrd->ucode_type) {
 		case IWL_UCODE_REGULAR:
-			inst_size = trans(priv)->ucode_rt.code.len;
-			data_size = trans(priv)->ucode_rt.data.len;
+			inst_size = nic(priv)->fw.ucode_rt.code.len;
+			data_size = nic(priv)->fw.ucode_rt.data.len;
 			break;
 		case IWL_UCODE_INIT:
-			inst_size = trans(priv)->ucode_init.code.len;
-			data_size = trans(priv)->ucode_init.data.len;
+			inst_size = nic(priv)->fw.ucode_init.code.len;
+			data_size = nic(priv)->fw.ucode_init.data.len;
 			break;
 		case IWL_UCODE_WOWLAN:
-			inst_size = trans(priv)->ucode_wowlan.code.len;
-			data_size = trans(priv)->ucode_wowlan.data.len;
+			inst_size = nic(priv)->fw.ucode_wowlan.code.len;
+			data_size = nic(priv)->fw.ucode_wowlan.data.len;
 			break;
 		case IWL_UCODE_NONE:
-			IWL_DEBUG_INFO(priv, "The uCode has not been loaded\n");
+			IWL_ERR(priv, "No uCode has not been loaded\n");
 			break;
 		default:
-			IWL_DEBUG_INFO(priv, "Unsupported uCode type\n");
+			IWL_ERR(priv, "Unsupported uCode type\n");
 			break;
 		}
 		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type);
@@ -596,12 +613,11 @@
 		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size);
 		status = cfg80211_testmode_reply(skb);
 		if (status < 0)
-			IWL_DEBUG_INFO(priv,
-					"Error sending msg : %d\n", status);
+			IWL_ERR(priv, "Error sending msg : %d\n", status);
 		break;
 
 	default:
-		IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
+		IWL_ERR(priv, "Unknown testmode driver command ID\n");
 		return -ENOSYS;
 	}
 	return status;
@@ -626,7 +642,7 @@
  */
 static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct sk_buff *skb;
 	int status = 0;
 	struct device *dev = trans(priv)->dev;
@@ -664,8 +680,7 @@
 		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
 			sizeof(priv->testmode_trace.dma_addr) + 20);
 		if (!skb) {
-			IWL_DEBUG_INFO(priv,
-				"Error allocating memory\n");
+			IWL_ERR(priv, "Memory allocation fail\n");
 			iwl_trace_cleanup(priv);
 			return -ENOMEM;
 		}
@@ -674,9 +689,7 @@
 			(u64 *)&priv->testmode_trace.dma_addr);
 		status = cfg80211_testmode_reply(skb);
 		if (status < 0) {
-			IWL_DEBUG_INFO(priv,
-				       "Error sending msg : %d\n",
-				       status);
+			IWL_ERR(priv, "Error sending msg : %d\n", status);
 		}
 		priv->testmode_trace.num_chunks =
 			DIV_ROUND_UP(priv->testmode_trace.buff_size,
@@ -687,7 +700,7 @@
 		iwl_trace_cleanup(priv);
 		break;
 	default:
-		IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
+		IWL_ERR(priv, "Unknown testmode mem command ID\n");
 		return -ENOSYS;
 	}
 	return status;
@@ -704,7 +717,7 @@
 				   struct sk_buff *skb,
 				   struct netlink_callback *cb)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	int idx, length;
 
 	if (priv->testmode_trace.trace_enabled &&
@@ -748,11 +761,11 @@
  */
 static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	u8 owner;
 
 	if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
-		IWL_DEBUG_INFO(priv, "Error finding ucode owner\n");
+		IWL_ERR(priv, "Missing ucode owner\n");
 		return -ENOMSG;
 	}
 
@@ -760,12 +773,89 @@
 	if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM))
 		priv->shrd->ucode_owner = owner;
 	else {
-		IWL_DEBUG_INFO(priv, "Invalid owner\n");
+		IWL_ERR(priv, "Invalid owner\n");
 		return -EINVAL;
 	}
 	return 0;
 }
 
+static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size)
+{
+	struct iwl_trans *trans = trans(priv);
+	unsigned long flags;
+	int i;
+
+	if (size & 0x3)
+		return -EINVAL;
+	priv->testmode_mem.buff_size = size;
+	priv->testmode_mem.buff_addr =
+		kmalloc(priv->testmode_mem.buff_size, GFP_KERNEL);
+	if (priv->testmode_mem.buff_addr == NULL)
+		return -ENOMEM;
+
+	/* Hard-coded periphery absolute address */
+	if (IWL_TM_ABS_PRPH_START <= addr &&
+		addr < IWL_TM_ABS_PRPH_START + PRPH_END) {
+			spin_lock_irqsave(&trans->reg_lock, flags);
+			iwl_grab_nic_access(trans);
+			iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
+				addr | (3 << 24));
+			for (i = 0; i < size; i += 4)
+				*(u32 *)(priv->testmode_mem.buff_addr + i) =
+					iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
+			iwl_release_nic_access(trans);
+			spin_unlock_irqrestore(&trans->reg_lock, flags);
+	} else { /* target memory (SRAM) */
+		_iwl_read_targ_mem_words(trans, addr,
+			priv->testmode_mem.buff_addr,
+			priv->testmode_mem.buff_size / 4);
+	}
+
+	priv->testmode_mem.num_chunks =
+		DIV_ROUND_UP(priv->testmode_mem.buff_size, DUMP_CHUNK_SIZE);
+	priv->testmode_mem.read_in_progress = true;
+	return 0;
+
+}
+
+static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr,
+	u32 size, unsigned char *buf)
+{
+	struct iwl_trans *trans = trans(priv);
+	u32 val, i;
+	unsigned long flags;
+
+	if (IWL_TM_ABS_PRPH_START <= addr &&
+		addr < IWL_TM_ABS_PRPH_START + PRPH_END) {
+			/* Periphery writes can be 1-3 bytes long, or DWORDs */
+			if (size < 4) {
+				memcpy(&val, buf, size);
+				spin_lock_irqsave(&trans->reg_lock, flags);
+				iwl_grab_nic_access(trans);
+				iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
+					    (addr & 0x0000FFFF) |
+					    ((size - 1) << 24));
+				iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
+				iwl_release_nic_access(trans);
+				/* needed after consecutive writes w/o read */
+				mmiowb();
+				spin_unlock_irqrestore(&trans->reg_lock, flags);
+			} else {
+				if (size % 4)
+					return -EINVAL;
+				for (i = 0; i < size; i += 4)
+					iwl_write_prph(trans, addr+i,
+						*(u32 *)(buf+i));
+			}
+	} else if (iwlagn_hw_valid_rtc_data_addr(addr) ||
+		(IWLAGN_RTC_INST_LOWER_BOUND <= addr &&
+		addr < IWLAGN_RTC_INST_UPPER_BOUND)) {
+			_iwl_write_targ_mem_words(trans, addr, buf, size/4);
+	} else
+		return -EINVAL;
+	return 0;
+}
+
 /*
  * This function handles the user application commands for SRAM data dump
  *
@@ -782,82 +872,60 @@
  * @hw: ieee80211_hw object that represents the device
  * @tb: gnl message fields from the user space
  */
-static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb)
+static int iwl_testmode_indirect_mem(struct ieee80211_hw *hw,
+	struct nlattr **tb)
 {
-	struct iwl_priv *priv = hw->priv;
-	u32 ofs, size, maxsize;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	u32 addr, size, cmd;
+	unsigned char *buf;
 
-	if (priv->testmode_sram.sram_readed)
+	/* Both read and write should be blocked, for atomicity */
+	if (priv->testmode_mem.read_in_progress)
 		return -EBUSY;
 
-	if (!tb[IWL_TM_ATTR_SRAM_ADDR]) {
-		IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n");
+	cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
+	if (!tb[IWL_TM_ATTR_MEM_ADDR]) {
+		IWL_ERR(priv, "Error finding memory offset address\n");
 		return -ENOMSG;
 	}
-	ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]);
-	if (!tb[IWL_TM_ATTR_SRAM_SIZE]) {
-		IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n");
+	addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]);
+	if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) {
+		IWL_ERR(priv, "Error finding size for memory reading\n");
 		return -ENOMSG;
 	}
-	size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]);
-	switch (priv->shrd->ucode_type) {
-	case IWL_UCODE_REGULAR:
-		maxsize = trans(priv)->ucode_rt.data.len;
-		break;
-	case IWL_UCODE_INIT:
-		maxsize = trans(priv)->ucode_init.data.len;
-		break;
-	case IWL_UCODE_WOWLAN:
-		maxsize = trans(priv)->ucode_wowlan.data.len;
-		break;
-	case IWL_UCODE_NONE:
-		IWL_ERR(priv, "Error, uCode does not been loaded\n");
-		return -ENOSYS;
-	default:
-		IWL_ERR(priv, "Error, unsupported uCode type\n");
-		return -ENOSYS;
+	size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]);
+
+	if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ)
+		return iwl_testmode_indirect_read(priv, addr,  size);
+	else {
+		if (!tb[IWL_TM_ATTR_BUFFER_DUMP])
+			return -EINVAL;
+		buf = (unsigned char *) nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]);
+		return iwl_testmode_indirect_write(priv, addr, size, buf);
 	}
-	if ((ofs + size) > (maxsize + SRAM_DATA_SEG_OFFSET)) {
-		IWL_ERR(priv, "Invalid offset/size: out of range\n");
-		return -EINVAL;
-	}
-	priv->testmode_sram.buff_size = (size / 4) * 4;
-	priv->testmode_sram.buff_addr =
-		kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL);
-	if (priv->testmode_sram.buff_addr == NULL) {
-		IWL_ERR(priv, "Error allocating memory\n");
-		return -ENOMEM;
-	}
-	_iwl_read_targ_mem_words(trans(priv), ofs,
-					priv->testmode_sram.buff_addr,
-					priv->testmode_sram.buff_size / 4);
-	priv->testmode_sram.num_chunks =
-		DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE);
-	priv->testmode_sram.sram_readed = true;
-	return 0;
 }
 
-static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb,
+static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw, struct nlattr **tb,
 				   struct sk_buff *skb,
 				   struct netlink_callback *cb)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	int idx, length;
 
-	if (priv->testmode_sram.sram_readed) {
+	if (priv->testmode_mem.read_in_progress) {
 		idx = cb->args[4];
-		if (idx >= priv->testmode_sram.num_chunks) {
-			iwl_sram_cleanup(priv);
+		if (idx >= priv->testmode_mem.num_chunks) {
+			iwl_mem_cleanup(priv);
 			return -ENOENT;
 		}
 		length = DUMP_CHUNK_SIZE;
-		if (((idx + 1) == priv->testmode_sram.num_chunks) &&
-		    (priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE))
-			length = priv->testmode_sram.buff_size %
+		if (((idx + 1) == priv->testmode_mem.num_chunks) &&
+		    (priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE))
+			length = priv->testmode_mem.buff_size %
 				DUMP_CHUNK_SIZE;
 
-		NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length,
-			priv->testmode_sram.buff_addr +
+		NLA_PUT(skb, IWL_TM_ATTR_BUFFER_DUMP, length,
+			priv->testmode_mem.buff_addr +
 			(DUMP_CHUNK_SIZE * idx));
 		idx++;
 		cb->args[4] = idx;
@@ -892,20 +960,19 @@
 int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
 {
 	struct nlattr *tb[IWL_TM_ATTR_MAX];
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	int result;
 
 	result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
 			iwl_testmode_gnl_msg_policy);
 	if (result != 0) {
-		IWL_DEBUG_INFO(priv,
-			       "Error parsing the gnl message : %d\n", result);
+		IWL_ERR(priv, "Error parsing the gnl message : %d\n", result);
 		return result;
 	}
 
 	/* IWL_TM_ATTR_COMMAND is absolutely mandatory */
 	if (!tb[IWL_TM_ATTR_COMMAND]) {
-		IWL_DEBUG_INFO(priv, "Error finding testmode command type\n");
+		IWL_ERR(priv, "Missing testmode command type\n");
 		return -ENOMSG;
 	}
 	/* in case multiple accesses to the device happens */
@@ -919,8 +986,6 @@
 	case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
 	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
 	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
-	case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
-	case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
 		IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
 		result = iwl_testmode_reg(hw, tb);
 		break;
@@ -950,13 +1015,15 @@
 		result = iwl_testmode_ownership(hw, tb);
 		break;
 
-	case IWL_TM_CMD_APP2DEV_READ_SRAM:
-		IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n");
-		result = iwl_testmode_sram(hw, tb);
+	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
+	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
+		IWL_DEBUG_INFO(priv, "testmode indirect memory cmd "
+			"to driver\n");
+		result = iwl_testmode_indirect_mem(hw, tb);
 		break;
 
 	default:
-		IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
+		IWL_ERR(priv, "Unknown testmode command\n");
 		result = -ENOSYS;
 		break;
 	}
@@ -970,7 +1037,7 @@
 		      void *data, int len)
 {
 	struct nlattr *tb[IWL_TM_ATTR_MAX];
-	struct iwl_priv *priv = hw->priv;
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	int result;
 	u32 cmd;
 
@@ -981,15 +1048,14 @@
 		result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
 				iwl_testmode_gnl_msg_policy);
 		if (result) {
-			IWL_DEBUG_INFO(priv,
-			       "Error parsing the gnl message : %d\n", result);
+			IWL_ERR(priv,
+				"Error parsing the gnl message : %d\n", result);
 			return result;
 		}
 
 		/* IWL_TM_ATTR_COMMAND is absolutely mandatory */
 		if (!tb[IWL_TM_ATTR_COMMAND]) {
-			IWL_DEBUG_INFO(priv,
-				"Error finding testmode command type\n");
+			IWL_ERR(priv, "Missing testmode command type\n");
 			return -ENOMSG;
 		}
 		cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
@@ -1003,9 +1069,9 @@
 		IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
 		result = iwl_testmode_trace_dump(hw, tb, skb, cb);
 		break;
-	case IWL_TM_CMD_APP2DEV_DUMP_SRAM:
+	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:
 		IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n");
-		result = iwl_testmode_sram_dump(hw, tb, skb, cb);
+		result = iwl_testmode_buffer_dump(hw, tb, skb, cb);
 		break;
 	default:
 		result = -EINVAL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h
index f97d061..69b2e80 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h
@@ -99,7 +99,7 @@
  *	to user application
  * @IWL_TM_CMD_DEV2APP_UCODE_RX_PKT:
  *	commands from kernel space to multicast the spontaneous messages
- *	to user application
+ *	to user application, or reply of host commands
  * @IWL_TM_CMD_DEV2APP_EEPROM_RSP:
  *	commands from kernel space to carry the eeprom response
  *	to user application
@@ -109,20 +109,19 @@
  *	if application has the ownership, the only host command from
  *	testmode will deliver to uCode. Default owner is driver
  *
- * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
- * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
- *	commands from user application to indirectly access peripheral register
- *
- * @IWL_TM_CMD_APP2DEV_READ_SRAM:
- * @IWL_TM_CMD_APP2DEV_DUMP_SRAM:
- *	commands from user application to read data in sram
- *
  * @IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: load Wake On Wireless LAN uCode image
  * @IWL_TM_CMD_APP2DEV_GET_FW_VERSION: retrieve uCode version
  * @IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: retrieve ID information in device
  * @IWL_TM_CMD_APP2DEV_GET_FW_INFO:
  *	retrieve information of existing loaded uCode image
  *
+ * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
+ * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:
+ * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
+ *	Commands to read/write data from periphery or SRAM memory ranges.
+ *	Fore reading, a READ command is sent from the userspace and the data
+ *	is returned when the user calls a DUMP command.
+ *	For writing, only a WRITE command is used.
  */
 enum iwl_tm_cmd_t {
 	IWL_TM_CMD_APP2DEV_UCODE		= 1,
@@ -142,15 +141,18 @@
 	IWL_TM_CMD_DEV2APP_UCODE_RX_PKT		= 15,
 	IWL_TM_CMD_DEV2APP_EEPROM_RSP		= 16,
 	IWL_TM_CMD_APP2DEV_OWNERSHIP		= 17,
-	IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32	= 18,
-	IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32	= 19,
-	IWL_TM_CMD_APP2DEV_READ_SRAM		= 20,
-	IWL_TM_CMD_APP2DEV_DUMP_SRAM		= 21,
+	RESERVED_18				= 18,
+	RESERVED_19				= 19,
+	RESERVED_20				= 20,
+	RESERVED_21				= 21,
 	IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW	= 22,
 	IWL_TM_CMD_APP2DEV_GET_FW_VERSION	= 23,
 	IWL_TM_CMD_APP2DEV_GET_DEVICE_ID	= 24,
 	IWL_TM_CMD_APP2DEV_GET_FW_INFO		= 25,
-	IWL_TM_CMD_MAX				= 26,
+	IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26,
+	IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27,
+	IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28,
+	IWL_TM_CMD_MAX				= 29,
 };
 
 /*
@@ -171,8 +173,6 @@
  *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE,
  *	The mandatory fields are :
  *	IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID;
- *	IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands;
- *	The optional fields are:
  *	IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload
  *	to the ucode
  *
@@ -221,16 +221,19 @@
  *	The mandatory fields are:
  *	IWL_TM_ATTR_UCODE_OWNER for the new owner
  *
- * @IWL_TM_ATTR_SRAM_ADDR:
- * @IWL_TM_ATTR_SRAM_SIZE:
- *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_READ_SRAM,
+ * @IWL_TM_ATTR_MEM_ADDR:
+ * @IWL_TM_ATTR_BUFFER_SIZE:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ
+ *	or IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE.
  *	The mandatory fields are:
- *	IWL_TM_ATTR_SRAM_ADDR for the address in sram
- *	IWL_TM_ATTR_SRAM_SIZE for the buffer size of data reading
+ *	IWL_TM_ATTR_MEM_ADDR for the address in SRAM/periphery to read/write
+ *	IWL_TM_ATTR_BUFFER_SIZE for the buffer size of data to read/write.
  *
- * @IWL_TM_ATTR_SRAM_DUMP:
- *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_DUMP_SRAM,
- *	IWL_TM_ATTR_SRAM_DUMP for the data in sram
+ * @IWL_TM_ATTR_BUFFER_DUMP:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP,
+ *	IWL_TM_ATTR_BUFFER_DUMP is used for the data that was read.
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE,
+ *	this attribute contains the data to write.
  *
  * @IWL_TM_ATTR_FW_VERSION:
  *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_FW_VERSION,
@@ -249,6 +252,10 @@
  *	IWL_TM_ATTR_FW_INST_SIZE for the size of instruction section
  *	IWL_TM_ATTR_FW_DATA_SIZE for the size of data section
  *
+ * @IWL_TM_ATTR_UCODE_CMD_SKB:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag
+ *	indicates that the user wants to receive the response of the command
+ *	in a reply SKB. If it's not present, the response is not returned.
  */
 enum iwl_tm_attr_t {
 	IWL_TM_ATTR_NOT_APPLICABLE		= 0,
@@ -266,15 +273,16 @@
 	IWL_TM_ATTR_TRACE_DUMP			= 12,
 	IWL_TM_ATTR_FIXRATE			= 13,
 	IWL_TM_ATTR_UCODE_OWNER			= 14,
-	IWL_TM_ATTR_SRAM_ADDR			= 15,
-	IWL_TM_ATTR_SRAM_SIZE			= 16,
-	IWL_TM_ATTR_SRAM_DUMP			= 17,
+	IWL_TM_ATTR_MEM_ADDR			= 15,
+	IWL_TM_ATTR_BUFFER_SIZE			= 16,
+	IWL_TM_ATTR_BUFFER_DUMP			= 17,
 	IWL_TM_ATTR_FW_VERSION			= 18,
 	IWL_TM_ATTR_DEVICE_ID			= 19,
 	IWL_TM_ATTR_FW_TYPE			= 20,
 	IWL_TM_ATTR_FW_INST_SIZE		= 21,
 	IWL_TM_ATTR_FW_DATA_SIZE		= 22,
-	IWL_TM_ATTR_MAX				= 23,
+	IWL_TM_ATTR_UCODE_CMD_SKB		= 23,
+	IWL_TM_ATTR_MAX				= 24,
 };
 
 /* uCode trace buffer */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
index 561865f..5b26b71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
@@ -40,6 +40,7 @@
 #include "iwl-trans.h"
 #include "iwl-debug.h"
 #include "iwl-io.h"
+#include "iwl-op-mode.h"
 
 struct iwl_tx_queue;
 struct iwl_queue;
@@ -230,6 +231,7 @@
 	struct tasklet_struct irq_tasklet;
 	struct isr_statistics isr_stats;
 
+	spinlock_t irq_lock;
 	u32 inta_mask;
 	u32 scd_base_addr;
 	struct iwl_dma_ptr scd_bc_tbls;
@@ -373,7 +375,7 @@
 
 	if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) {
 		if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) {
-			iwl_wake_sw_queue(priv(trans), ac);
+			iwl_op_mode_queue_not_full(trans->op_mode, ac);
 			IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d. %s",
 					    hwq, ac, msg);
 		} else {
@@ -396,7 +398,7 @@
 
 	if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) {
 		if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) {
-			iwl_stop_sw_queue(priv(trans), ac);
+			iwl_op_mode_queue_full(trans->op_mode, ac);
 			IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d ac %d"
 					    " stop count %d. %s",
 					    hwq, ac, atomic_read(&trans_pcie->
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
index 3826852..2c910fd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
@@ -34,6 +34,8 @@
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-trans-pcie-int.h"
+#include "iwl-wifi.h"
+#include "iwl-op-mode.h"
 
 #ifdef CONFIG_IWLWIFI_IDI
 #include "iwl-amfh.h"
@@ -227,7 +229,7 @@
 	/* If the pre-allocated buffer pool is dropping low, schedule to
 	 * refill it */
 	if (rxq->free_count <= RX_LOW_WATERMARK)
-		queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish);
+		schedule_work(&trans_pcie->rx_replenish);
 
 
 	/* If we've added more space for the firmware to place data, tell it.
@@ -331,13 +333,14 @@
 
 void iwlagn_rx_replenish(struct iwl_trans *trans)
 {
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 	unsigned long flags;
 
 	iwlagn_rx_allocate(trans, GFP_KERNEL);
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 	iwlagn_rx_queue_restock(trans);
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
 static void iwlagn_rx_replenish_now(struct iwl_trans *trans)
@@ -351,14 +354,8 @@
 {
 	struct iwl_trans_pcie *trans_pcie =
 	    container_of(data, struct iwl_trans_pcie, rx_replenish);
-	struct iwl_trans *trans = trans_pcie->trans;
 
-	if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
-		return;
-
-	mutex_lock(&trans->shrd->mutex);
-	iwlagn_rx_replenish(trans);
-	mutex_unlock(&trans->shrd->mutex);
+	iwlagn_rx_replenish(trans_pcie->trans);
 }
 
 /**
@@ -464,7 +461,7 @@
 		     "reclaim is false, SEQ_RX_FRAME unset: %s\n",
 		     get_cmd_string(pkt->hdr.cmd));
 
-		err = iwl_rx_dispatch(priv(trans), rxb, cmd);
+		err = iwl_op_mode_rx(trans->op_mode, rxb, cmd);
 
 		/*
 		 * XXX: After here, we should always check rxb->page
@@ -594,17 +591,17 @@
 {
 	u32 base;
 	struct iwl_error_event_table table;
-	struct iwl_priv *priv = priv(trans);
+	struct iwl_nic *nic = nic(trans);
 	struct iwl_trans_pcie *trans_pcie =
 		IWL_TRANS_GET_PCIE_TRANS(trans);
 
 	base = trans->shrd->device_pointers.error_event_table;
 	if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
 		if (!base)
-			base = priv->init_errlog_ptr;
+			base = nic->init_errlog_ptr;
 	} else {
 		if (!base)
-			base = priv->inst_errlog_ptr;
+			base = nic->inst_errlog_ptr;
 	}
 
 	if (!iwlagn_hw_valid_rtc_data_addr(base)) {
@@ -616,7 +613,7 @@
 		return;
 	}
 
-	iwl_read_targ_mem_words(trans(priv), base, &table, sizeof(table));
+	iwl_read_targ_mem_words(trans, base, &table, sizeof(table));
 
 	if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
 		IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@@ -626,7 +623,7 @@
 
 	trans_pcie->isr_stats.err_code = table.error_id;
 
-	trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low,
+	trace_iwlwifi_dev_ucode_error(priv(nic), table.error_id, table.tsf_low,
 				      table.data1, table.data2, table.line,
 				      table.blink1, table.blink2, table.ilink1,
 				      table.ilink2, table.bcon_time, table.gp1,
@@ -674,9 +671,8 @@
  */
 static void iwl_irq_handle_error(struct iwl_trans *trans)
 {
-	struct iwl_priv *priv = priv(trans);
 	/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
-	if (cfg(priv)->internal_wimax_coex &&
+	if (cfg(trans)->internal_wimax_coex &&
 	    (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
 			APMS_CLK_VAL_MRB_FUNC_MODE) ||
 	     (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
@@ -687,24 +683,20 @@
 		 */
 		clear_bit(STATUS_READY, &trans->shrd->status);
 		clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
-		wake_up(&priv->shrd->wait_command_queue);
+		wake_up(&trans->shrd->wait_command_queue);
 		IWL_ERR(trans, "RF is used by WiMAX\n");
 		return;
 	}
 
 	IWL_ERR(trans, "Loaded firmware version: %s\n",
-		priv->hw->wiphy->fw_version);
+		nic(trans)->fw.fw_version);
 
 	iwl_dump_nic_error_log(trans);
 	iwl_dump_csr(trans);
 	iwl_dump_fh(trans, NULL, false);
 	iwl_dump_nic_event_log(trans, false, NULL, false);
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS)
-		iwl_print_rx_config_cmd(priv(trans), IWL_RXON_CTX_BSS);
-#endif
 
-	iwlagn_fw_error(priv, false);
+	iwl_op_mode_nic_error(trans->op_mode);
 }
 
 #define EVENT_START_OFFSET  (4 * sizeof(u32))
@@ -723,7 +715,7 @@
 	u32 ptr;        /* SRAM byte address of log data */
 	u32 ev, time, data; /* event log data */
 	unsigned long reg_flags;
-	struct iwl_priv *priv = priv(trans);
+	struct iwl_nic *nic = nic(trans);
 
 	if (num_events == 0)
 		return pos;
@@ -731,10 +723,10 @@
 	base = trans->shrd->device_pointers.log_event_table;
 	if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
 		if (!base)
-			base = priv->init_evtlog_ptr;
+			base = nic->init_evtlog_ptr;
 	} else {
 		if (!base)
-			base = priv->inst_evtlog_ptr;
+			base = nic->inst_evtlog_ptr;
 	}
 
 	if (mode == 0)
@@ -764,7 +756,7 @@
 						"EVT_LOG:0x%08x:%04u\n",
 						time, ev);
 			} else {
-				trace_iwlwifi_dev_ucode_event(priv, 0,
+				trace_iwlwifi_dev_ucode_event(priv(trans), 0,
 					time, ev);
 				IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n",
 					time, ev);
@@ -778,7 +770,7 @@
 			} else {
 				IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n",
 					time, data, ev);
-				trace_iwlwifi_dev_ucode_event(priv, time,
+				trace_iwlwifi_dev_ucode_event(priv(trans), time,
 					data, ev);
 			}
 		}
@@ -840,17 +832,17 @@
 	u32 logsize;
 	int pos = 0;
 	size_t bufsz = 0;
-	struct iwl_priv *priv = priv(trans);
+	struct iwl_nic *nic = nic(trans);
 
 	base = trans->shrd->device_pointers.log_event_table;
 	if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
-		logsize = priv->init_evtlog_size;
+		logsize = nic->init_evtlog_size;
 		if (!base)
-			base = priv->init_evtlog_ptr;
+			base = nic->init_evtlog_ptr;
 	} else {
-		logsize = priv->inst_evtlog_size;
+		logsize = nic->inst_evtlog_size;
 		if (!base)
-			base = priv->inst_evtlog_ptr;
+			base = nic->inst_evtlog_ptr;
 	}
 
 	if (!iwlagn_hw_valid_rtc_data_addr(base)) {
@@ -949,7 +941,7 @@
 	struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
 
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
 	/* Ack/clear/reset pending uCode interrupts.
 	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
@@ -979,7 +971,7 @@
 	/* saved interrupt in inta variable now we can reset trans_pcie->inta */
 	trans_pcie->inta = 0;
 
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
 	/* Now service all interrupt bits discovered above. */
 	if (inta & CSR_INT_BIT_HW_ERR) {
@@ -1039,7 +1031,7 @@
 			else
 				clear_bit(STATUS_RF_KILL_HW,
 					  &trans->shrd->status);
-			iwl_set_hw_rfkill_state(priv(trans), hw_rf_kill);
+			iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rf_kill);
 		}
 
 		handled |= CSR_INT_BIT_RF_KILL;
@@ -1232,7 +1224,7 @@
 	if (!trans_pcie->ict_tbl)
 		return;
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 	iwl_disable_interrupts(trans);
 
 	memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
@@ -1249,7 +1241,7 @@
 	trans_pcie->ict_index = 0;
 	iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
 	iwl_enable_interrupts(trans);
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
 /* Device is going down disable ict interrupt usage */
@@ -1260,9 +1252,9 @@
 
 	unsigned long flags;
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 	trans_pcie->use_ict = false;
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
 static irqreturn_t iwl_isr(int irq, void *data)
@@ -1281,7 +1273,7 @@
 
 	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
 	/* Disable (but don't clear!) interrupts here to avoid
 	 *    back-to-back ISRs and sporadic interrupts from our NIC.
@@ -1325,7 +1317,7 @@
 		iwl_enable_interrupts(trans);
 
  unplugged:
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 	return IRQ_HANDLED;
 
  none:
@@ -1335,7 +1327,7 @@
 		!trans_pcie->inta)
 		iwl_enable_interrupts(trans);
 
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 	return IRQ_NONE;
 }
 
@@ -1369,7 +1361,7 @@
 
 	trace_iwlwifi_dev_irq(priv(trans));
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
 	/* Disable (but don't clear!) interrupts here to avoid
 	 * back-to-back ISRs and sporadic interrupts from our NIC.
@@ -1440,7 +1432,7 @@
 		iwl_enable_interrupts(trans);
 	}
 
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 	return IRQ_HANDLED;
 
  none:
@@ -1451,6 +1443,6 @@
 	    !trans_pcie->inta)
 		iwl_enable_interrupts(trans);
 
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 	return IRQ_NONE;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index a8dfeca..4e1e74e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -35,6 +35,7 @@
 #include "iwl-prph.h"
 #include "iwl-io.h"
 #include "iwl-agn-hw.h"
+#include "iwl-op-mode.h"
 #include "iwl-trans-pcie-int.h"
 
 #define IWL_TX_CRC_SIZE 4
@@ -229,7 +230,7 @@
 		 * freed and that the queue is not empty - free the skb
 		 */
 		if (skb) {
-			iwl_free_skb(priv(trans), skb);
+			iwl_op_mode_free_skb(trans->op_mode, skb);
 			txq->skbs[index] = NULL;
 		}
 	}
@@ -492,7 +493,7 @@
 
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
 	/* Stop this Tx queue before configuring it */
 	iwlagn_tx_queue_stop_scheduler(trans, txq_id);
@@ -532,7 +533,7 @@
 	trans_pcie->txq[txq_id].sta_id = sta_id;
 	trans_pcie->txq[txq_id].tid = tid;
 
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
 /*
@@ -688,7 +689,7 @@
 		is_ct_kill = iwl_check_for_ct_kill(priv(trans));
 		if (!is_ct_kill) {
 			IWL_ERR(trans, "Restarting adapter queue is full\n");
-			iwlagn_fw_error(priv(trans), false);
+			iwl_op_mode_nic_error(trans->op_mode);
 		}
 		return -ENOSPC;
 	}
@@ -821,7 +822,7 @@
 		if (nfreed++ > 0) {
 			IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx,
 					q->write_ptr, q->read_ptr);
-			iwlagn_fw_error(priv(trans), false);
+			iwl_op_mode_nic_error(trans->op_mode);
 		}
 
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index f5cb5d3..9f8b239 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -76,6 +76,7 @@
 #include "iwl-eeprom.h"
 #include "iwl-agn-hw.h"
 #include "iwl-core.h"
+#include "iwl-ucode.h"
 
 static int iwl_trans_rx_alloc(struct iwl_trans *trans)
 {
@@ -219,10 +220,10 @@
 
 	iwl_trans_rx_hw_init(trans, rxq);
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 	rxq->need_update = 1;
 	iwl_rx_queue_update_write_ptr(trans, rxq);
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
 	return 0;
 }
@@ -585,7 +586,7 @@
 		alloc = true;
 	}
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
 	/* Turn off all Tx DMA fifos */
 	iwl_write_prph(trans, SCD_TXFACT, 0);
@@ -594,7 +595,7 @@
 	iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
 			   trans_pcie->kw.dma >> 4);
 
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
 	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
 	for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) {
@@ -803,17 +804,18 @@
 
 static int iwl_nic_init(struct iwl_trans *trans)
 {
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 	unsigned long flags;
 
 	/* nic_init */
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 	iwl_apm_init(trans);
 
 	/* Set interrupt coalescing calibration timer to default (512 usecs) */
 	iwl_write8(trans, CSR_INT_COALESCING,
 		IWL_HOST_INT_CALIB_TIMEOUT_DEF);
 
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
 	iwl_set_pwr_vmain(trans);
 
@@ -1044,7 +1046,7 @@
 		set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
 
 	if (iwl_is_rfkill(trans->shrd)) {
-		iwl_set_hw_rfkill_state(priv(trans), true);
+		iwl_op_mode_hw_rf_kill(trans->op_mode, true);
 		iwl_enable_interrupts(trans);
 		return -ERFKILL;
 	}
@@ -1078,10 +1080,15 @@
 
 /*
  * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- * must be called under priv->shrd->lock and mac access
+ * must be called under the irq lock and with MAC access
  */
 static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
 {
+	struct iwl_trans_pcie __maybe_unused *trans_pcie =
+		IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	lockdep_assert_held(&trans_pcie->irq_lock);
+
 	iwl_write_prph(trans, SCD_TXFACT, mask);
 }
 
@@ -1095,7 +1102,7 @@
 	int i, chan;
 	u32 reg_val;
 
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
 	trans_pcie->scd_base_addr =
 		iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
@@ -1191,7 +1198,7 @@
 					      fifo, 0);
 	}
 
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
 	/* Enable L1-Active */
 	iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
@@ -1214,7 +1221,7 @@
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
 	/* Turn off all Tx DMA fifos */
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
 	iwl_trans_txq_set_sched(trans, 0);
 
@@ -1230,7 +1237,7 @@
 			    iwl_read_direct32(trans,
 					      FH_TSSR_TX_STATUS_REG));
 	}
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
 	if (!trans_pcie->txq) {
 		IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
@@ -1250,9 +1257,9 @@
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
 	/* tell the device to stop sending interrupts */
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 	iwl_disable_interrupts(trans);
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
 	/* device going down, Stop using ICT table */
 	iwl_disable_ict(trans);
@@ -1285,14 +1292,16 @@
 	/* Upon stop, the APM issues an interrupt if HW RF kill is set.
 	 * Clean again the interrupt here
 	 */
-	spin_lock_irqsave(&trans->shrd->lock, flags);
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 	iwl_disable_interrupts(trans);
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
 	/* wait to make sure we flush pending tasklet*/
 	synchronize_irq(trans->irq);
 	tasklet_kill(&trans_pcie->irq_tasklet);
 
+	cancel_work_sync(&trans_pcie->rx_replenish);
+
 	/* stop and reset the on-board processor */
 	iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 }
@@ -1516,7 +1525,7 @@
 	else
 		set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
 
-	iwl_set_hw_rfkill_state(priv(trans),
+	iwl_op_mode_hw_rf_kill(trans->op_mode,
 				test_bit(STATUS_RF_KILL_HW,
 					 &trans->shrd->status));
 
@@ -1661,7 +1670,7 @@
 	else
 		clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
 
-	iwl_set_hw_rfkill_state(priv(trans), hw_rfkill);
+	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
 	return 0;
 }
@@ -2259,6 +2268,7 @@
 	trans->shrd = shrd;
 	trans_pcie->trans = trans;
 	spin_lock_init(&trans->hcmd_lock);
+	spin_lock_init(&trans_pcie->irq_lock);
 
 	/* W/A - seems to solve weird behavior. We need to remove this if we
 	 * don't want to stay in L1 all the time. This wastes a lot of power */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index ae68c51..4e7e6c0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -63,23 +63,75 @@
 #ifndef __iwl_trans_h__
 #define __iwl_trans_h__
 
-#include <linux/debugfs.h>
-#include <linux/skbuff.h>
+#include <linux/ieee80211.h>
 
 #include "iwl-shared.h"
-#include "iwl-commands.h"
+#include "iwl-debug.h"
 
- /*This file includes the declaration that are exported from the transport
- * layer */
+/**
+ * DOC: Transport layer - what is it ?
+ *
+ * The tranport layer is the layer that deals with the HW directly. It provides
+ * an abstraction of the underlying HW to the upper layer. The transport layer
+ * doesn't provide any policy, algorithm or anything of this kind, but only
+ * mechanisms to make the HW do something.It is not completely stateless but
+ * close to it.
+ * We will have an implementation for each different supported bus.
+ */
+
+/**
+ * DOC: Life cycle of the transport layer
+ *
+ * The transport layer has a very precise life cycle.
+ *
+ *	1) A helper function is called during the module initialization and
+ *	   registers the bus driver's ops with the transport's alloc function.
+ *	2) Bus's probe calls to the transport layer's allocation functions.
+ *	   Of course this function is bus specific.
+ *	3) This allocation functions will spawn the upper layer which will
+ *	   register mac80211.
+ *
+ *	4) At some point (i.e. mac80211's start call), the op_mode will call
+ *	   the following sequence:
+ *	   start_hw
+ *	   start_fw
+ *
+ *	5) Then when finished (or reset):
+ *	   stop_fw (a.k.a. stop device for the moment)
+ *	   stop_hw
+ *
+ *	6) Eventually, the free function will be called.
+ */
 
 struct iwl_priv;
 struct iwl_shared;
+struct iwl_op_mode;
+struct fw_img;
+struct sk_buff;
+struct dentry;
 
+/**
+ * DOC: Host command section
+ *
+ * A host command is a commaned issued by the upper layer to the fw. There are
+ * several versions of fw that have several APIs. The transport layer is
+ * completely agnostic to these differences.
+ * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode),
+ */
 #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
 #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
 #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
 
-enum {
+/**
+ * enum CMD_MODE - how to send the host commands ?
+ *
+ * @CMD_SYNC: The caller will be stalled until the fw responds to the command
+ * @CMD_ASYNC: Return right away and don't want for the response
+ * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the
+ *	response.
+ * @CMD_ON_DEMAND: This command is sent by the test mode pipe.
+ */
+enum CMD_MODE {
 	CMD_SYNC = 0,
 	CMD_ASYNC = BIT(0),
 	CMD_WANT_SKB = BIT(1),
@@ -104,20 +156,29 @@
 
 #define IWL_MAX_CMD_TFDS	2
 
+/**
+ * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command
+ *
+ * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's
+ *	ring. The transport layer doesn't map the command's buffer to DMA, but
+ *	rather copies it to an previously allocated DMA buffer. This flag tells
+ *	the transport layer not to copy the command, but to map the existing
+ *	buffer. This can save memcpy and is worth with very big comamnds.
+ */
 enum iwl_hcmd_dataflag {
 	IWL_HCMD_DFL_NOCOPY	= BIT(0),
 };
 
 /**
  * struct iwl_host_cmd - Host command to the uCode
+ *
  * @data: array of chunks that composes the data of the host command
  * @reply_page: pointer to the page that holds the response to the host command
  * @handler_status: return value of the handler of the command
  *	(put in setup_rx_handlers) - valid for SYNC mode only
- * @callback:
- * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC
+ * @flags: can be CMD_*
  * @len: array of the lenths of the chunks in data
- * @dataflags:
+ * @dataflags: IWL_HCMD_DFL_*
  * @id: id of the host command
  */
 struct iwl_host_cmd {
@@ -131,40 +192,45 @@
 	u8 id;
 };
 
-/* one for each uCode image (inst/data, boot/init/runtime) */
-struct fw_desc {
-	dma_addr_t p_addr;	/* hardware address */
-	void *v_addr;		/* software address */
-	u32 len;		/* size in bytes */
-};
-
-struct fw_img {
-	struct fw_desc code;	/* firmware code image */
-	struct fw_desc data;	/* firmware data image */
-};
-
 /**
  * struct iwl_trans_ops - transport specific operations
+ *
+ * All the handlers MUST be implemented
+ *
  * @start_hw: starts the HW- from that point on, the HW can send interrupts
+ *	May sleep
  * @stop_hw: stops the HW- from that point on, the HW will be in low power but
  *	will still issue interrupt if the HW RF kill is triggered.
+ *	May sleep
  * @start_fw: allocates and inits all the resources for the transport
- *	layer. Also kick a fw image. This handler may sleep.
+ *	layer. Also kick a fw image.
+ *	May sleep
  * @fw_alive: called when the fw sends alive notification
+ *	May sleep
  * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_*
  * @stop_device:stops the whole device (embedded CPU put to reset)
+ *	May sleep
  * @send_cmd:send a host command
+ *	May sleep only if CMD_SYNC is set
  * @tx: send an skb
+ *	Must be atomic
  * @reclaim: free packet until ssn. Returns a list of freed packets.
+ *	Must be atomic
  * @tx_agg_alloc: allocate resources for a TX BA session
+ *	May sleep
  * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is
- *                 ready and a successful ADDBA response has been received.
+ *	ready and a successful ADDBA response has been received.
+ *	May sleep
  * @tx_agg_disable: de-configure a Tx queue to send AMPDUs
+ *	May sleep
  * @free: release all the ressource for the transport layer itself such as
- *        irq, tasklet etc...
+ *	irq, tasklet etc... From this point on, the device may not issue
+ *	any interrupt (incl. RFKILL).
+ *	May sleep
  * @stop_queue: stop a specific queue
  * @check_stuck_queue: check if a specific queue is stuck
  * @wait_tx_queue_empty: wait until all tx queues are empty
+ *	May sleep
  * @dbgfs_register: add the dbgfs files under this directory. Files will be
  *	automatically deleted.
  * @suspend: stop the device unless WoWLAN is configured
@@ -227,27 +293,39 @@
 };
 
 /**
+ * enum iwl_trans_state - state of the transport layer
+ *
+ * @IWL_TRANS_NO_FW: no fw has sent an alive response
+ * @IWL_TRANS_FW_ALIVE: a fw has sent an alive response
+ */
+enum iwl_trans_state {
+	IWL_TRANS_NO_FW = 0,
+	IWL_TRANS_FW_ALIVE	= 1,
+};
+
+/**
  * struct iwl_trans - transport common data
+ *
  * @ops - pointer to iwl_trans_ops
+ * @op_mode - pointer to the op_mode
  * @shrd - pointer to iwl_shared which holds shared data from the upper layer
  * @hcmd_lock: protects HCMD
  * @reg_lock - protect hw register access
  * @dev - pointer to struct device * that represents the device
  * @irq - the irq number for the device
  * @hw_id: a u32 with the ID of the device / subdevice.
-  *	Set during transport alloaction.
+ *	Set during transport allocation.
  * @hw_id_str: a string with info about HW ID. Set during transport allocation.
  * @ucode_write_complete: indicates that the ucode has been copied.
- * @ucode_rt: run time ucode image
- * @ucode_init: init ucode image
- * @ucode_wowlan: wake on wireless ucode image (optional)
  * @nvm_device_type: indicates OTP or eeprom
  * @pm_support: set to true in start_hw if link pm is supported
  * @calib_results: list head for init calibration results
  */
 struct iwl_trans {
 	const struct iwl_trans_ops *ops;
+	struct iwl_op_mode *op_mode;
 	struct iwl_shared *shrd;
+	enum iwl_trans_state state;
 	spinlock_t hcmd_lock;
 	spinlock_t reg_lock;
 
@@ -257,36 +335,51 @@
 	u32 hw_id;
 	char hw_id_str[52];
 
-	u8 ucode_write_complete;	/* the image write is complete */
-	struct fw_img ucode_rt;
-	struct fw_img ucode_init;
-	struct fw_img ucode_wowlan;
+	u8 ucode_write_complete;
 
-	/* eeprom related variables */
 	int    nvm_device_type;
 	bool pm_support;
 
-	/* init calibration results */
 	struct list_head calib_results;
 
 	/* pointer to trans specific struct */
 	/*Ensure that this pointer will always be aligned to sizeof pointer */
-	char trans_specific[0] __attribute__((__aligned__(sizeof(void *))));
+	char trans_specific[0] __aligned(sizeof(void *));
 };
 
+static inline void iwl_trans_configure(struct iwl_trans *trans,
+				       struct iwl_op_mode *op_mode)
+{
+	/*
+	 * only set the op_mode for the moment. Later on, this function will do
+	 * more
+	 */
+	trans->op_mode = op_mode;
+}
+
 static inline int iwl_trans_start_hw(struct iwl_trans *trans)
 {
+	might_sleep();
+
 	return trans->ops->start_hw(trans);
 }
 
 static inline void iwl_trans_stop_hw(struct iwl_trans *trans)
 {
+	might_sleep();
+
 	trans->ops->stop_hw(trans);
+
+	trans->state = IWL_TRANS_NO_FW;
 }
 
 static inline void iwl_trans_fw_alive(struct iwl_trans *trans)
 {
+	might_sleep();
+
 	trans->ops->fw_alive(trans);
+
+	trans->state = IWL_TRANS_FW_ALIVE;
 }
 
 static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw)
@@ -298,13 +391,20 @@
 
 static inline void iwl_trans_stop_device(struct iwl_trans *trans)
 {
+	might_sleep();
+
 	trans->ops->stop_device(trans);
+
+	trans->state = IWL_TRANS_NO_FW;
 }
 
 static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans,
 					    enum iwl_rxon_context_id ctx,
 					    const char *msg)
 {
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	trans->ops->wake_any_queue(trans, ctx, msg);
 }
 
@@ -312,6 +412,9 @@
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
 				struct iwl_host_cmd *cmd)
 {
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	return trans->ops->send_cmd(trans, cmd);
 }
 
@@ -322,6 +425,9 @@
 		struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
 		u8 sta_id, u8 tid)
 {
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id, tid);
 }
 
@@ -329,6 +435,9 @@
 				 int tid, int txq_id, int ssn, u32 status,
 				 struct sk_buff_head *skbs)
 {
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn,
 				   status, skbs);
 }
@@ -336,12 +445,22 @@
 static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans,
 					    int sta_id, int tid)
 {
+	might_sleep();
+
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	return trans->ops->tx_agg_disable(trans, sta_id, tid);
 }
 
 static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans,
 					 int sta_id, int tid)
 {
+	might_sleep();
+
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	return trans->ops->tx_agg_alloc(trans, sta_id, tid);
 }
 
@@ -351,6 +470,11 @@
 					   int sta_id, int tid,
 					   int frame_limit, u16 ssn)
 {
+	might_sleep();
+
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn);
 }
 
@@ -362,16 +486,25 @@
 static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q,
 					const char *msg)
 {
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	trans->ops->stop_queue(trans, q, msg);
 }
 
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
 {
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	return trans->ops->wait_tx_queue_empty(trans);
 }
 
 static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q)
 {
+	if (trans->state != IWL_TRANS_FW_ALIVE)
+		IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
 	return trans->ops->check_stuck_queue(trans, q);
 }
 static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
@@ -410,8 +543,6 @@
 /*****************************************************
 * Utils functions
 ******************************************************/
-void iwl_dealloc_ucode(struct iwl_trans *trans);
-
 int iwl_send_calib_results(struct iwl_trans *trans);
 int iwl_calib_set(struct iwl_trans *trans,
 		  const struct iwl_calib_hdr *cmd, int len);
@@ -426,6 +557,8 @@
 struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
 				       struct pci_dev *pdev,
 				       const struct pci_device_id *ent);
+int __must_check iwl_pci_register_driver(void);
+void iwl_pci_unregister_driver(void);
 
 extern const struct iwl_trans_ops trans_ops_idi;
 struct iwl_trans *iwl_trans_idi_alloc(struct iwl_shared *shrd,
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c
index 11b659a..b16efc0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c
@@ -44,6 +44,7 @@
 #include "iwl-agn-calib.h"
 #include "iwl-trans.h"
 #include "iwl-fh.h"
+#include "iwl-op-mode.h"
 
 static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
 	{COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
@@ -82,29 +83,29 @@
  *
  ******************************************************************************/
 
-static void iwl_free_fw_desc(struct iwl_trans *trans, struct fw_desc *desc)
+static void iwl_free_fw_desc(struct iwl_nic *nic, struct fw_desc *desc)
 {
 	if (desc->v_addr)
-		dma_free_coherent(trans->dev, desc->len,
+		dma_free_coherent(trans(nic)->dev, desc->len,
 				  desc->v_addr, desc->p_addr);
 	desc->v_addr = NULL;
 	desc->len = 0;
 }
 
-static void iwl_free_fw_img(struct iwl_trans *trans, struct fw_img *img)
+static void iwl_free_fw_img(struct iwl_nic *nic, struct fw_img *img)
 {
-	iwl_free_fw_desc(trans, &img->code);
-	iwl_free_fw_desc(trans, &img->data);
+	iwl_free_fw_desc(nic, &img->code);
+	iwl_free_fw_desc(nic, &img->data);
 }
 
-void iwl_dealloc_ucode(struct iwl_trans *trans)
+void iwl_dealloc_ucode(struct iwl_nic *nic)
 {
-	iwl_free_fw_img(trans, &trans->ucode_rt);
-	iwl_free_fw_img(trans, &trans->ucode_init);
-	iwl_free_fw_img(trans, &trans->ucode_wowlan);
+	iwl_free_fw_img(nic, &nic->fw.ucode_rt);
+	iwl_free_fw_img(nic, &nic->fw.ucode_init);
+	iwl_free_fw_img(nic, &nic->fw.ucode_wowlan);
 }
 
-static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc,
+static int iwl_alloc_fw_desc(struct iwl_nic *nic, struct fw_desc *desc,
 		      const void *data, size_t len)
 {
 	if (!len) {
@@ -112,7 +113,7 @@
 		return -EINVAL;
 	}
 
-	desc->v_addr = dma_alloc_coherent(trans->dev, len,
+	desc->v_addr = dma_alloc_coherent(trans(nic)->dev, len,
 					  &desc->p_addr, GFP_KERNEL);
 	if (!desc->v_addr)
 		return -ENOMEM;
@@ -122,16 +123,16 @@
 	return 0;
 }
 
-static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans,
+static inline struct fw_img *iwl_get_ucode_image(struct iwl_nic *nic,
 					enum iwl_ucode_type ucode_type)
 {
 	switch (ucode_type) {
 	case IWL_UCODE_INIT:
-		return &trans->ucode_init;
+		return &nic->fw.ucode_init;
 	case IWL_UCODE_WOWLAN:
-		return &trans->ucode_wowlan;
+		return &nic->fw.ucode_wowlan;
 	case IWL_UCODE_REGULAR:
-		return &trans->ucode_rt;
+		return &nic->fw.ucode_rt;
 	case IWL_UCODE_NONE:
 		break;
 	}
@@ -397,15 +398,16 @@
  *   using sample data 100 bytes apart.  If these sample points are good,
  *   it's a pretty good bet that everything between them is good, too.
  */
-static int iwl_verify_inst_sparse(struct iwl_trans *trans,
+static int iwl_verify_inst_sparse(struct iwl_nic *nic,
 				      struct fw_desc *fw_desc)
 {
+	struct iwl_trans *trans = trans(nic);
 	__le32 *image = (__le32 *)fw_desc->v_addr;
 	u32 len = fw_desc->len;
 	u32 val;
 	u32 i;
 
-	IWL_DEBUG_FW(trans, "ucode inst image size is %u\n", len);
+	IWL_DEBUG_FW(nic, "ucode inst image size is %u\n", len);
 
 	for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
 		/* read data comes through single port, auto-incr addr */
@@ -421,16 +423,17 @@
 	return 0;
 }
 
-static void iwl_print_mismatch_inst(struct iwl_trans *trans,
+static void iwl_print_mismatch_inst(struct iwl_nic *nic,
 				    struct fw_desc *fw_desc)
 {
+	struct iwl_trans *trans = trans(nic);
 	__le32 *image = (__le32 *)fw_desc->v_addr;
 	u32 len = fw_desc->len;
 	u32 val;
 	u32 offs;
 	int errors = 0;
 
-	IWL_DEBUG_FW(trans, "ucode inst image size is %u\n", len);
+	IWL_DEBUG_FW(nic, "ucode inst image size is %u\n", len);
 
 	iwl_write_direct32(trans, HBUS_TARG_MEM_RADDR,
 			   IWLAGN_RTC_INST_LOWER_BOUND);
@@ -441,7 +444,7 @@
 		/* read data comes through single port, auto-incr addr */
 		val = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
 		if (val != le32_to_cpu(*image)) {
-			IWL_ERR(trans, "uCode INST section at "
+			IWL_ERR(nic, "uCode INST section at "
 				"offset 0x%x, is 0x%x, s/b 0x%x\n",
 				offs, val, le32_to_cpu(*image));
 			errors++;
@@ -453,24 +456,24 @@
  * iwl_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-static int iwl_verify_ucode(struct iwl_trans *trans,
+static int iwl_verify_ucode(struct iwl_nic *nic,
 			    enum iwl_ucode_type ucode_type)
 {
-	struct fw_img *img = iwl_get_ucode_image(trans, ucode_type);
+	struct fw_img *img = iwl_get_ucode_image(nic, ucode_type);
 
 	if (!img) {
-		IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type);
+		IWL_ERR(nic, "Invalid ucode requested (%d)\n", ucode_type);
 		return -EINVAL;
 	}
 
-	if (!iwl_verify_inst_sparse(trans, &img->code)) {
-		IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n");
+	if (!iwl_verify_inst_sparse(nic, &img->code)) {
+		IWL_DEBUG_FW(nic, "uCode is good in inst SRAM\n");
 		return 0;
 	}
 
-	IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
+	IWL_ERR(nic, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
 
-	iwl_print_mismatch_inst(trans, &img->code);
+	iwl_print_mismatch_inst(nic, &img->code);
 	return -EIO;
 }
 
@@ -583,7 +586,7 @@
 
 	old_type = trans->shrd->ucode_type;
 	trans->shrd->ucode_type = ucode_type;
-	fw = iwl_get_ucode_image(trans, ucode_type);
+	fw = iwl_get_ucode_image(nic(trans), ucode_type);
 
 	if (!fw)
 		return -EINVAL;
@@ -618,7 +621,7 @@
 	 * skip it for WoWLAN.
 	 */
 	if (ucode_type != IWL_UCODE_WOWLAN) {
-		ret = iwl_verify_ucode(trans, ucode_type);
+		ret = iwl_verify_ucode(nic(trans), ucode_type);
 		if (ret) {
 			trans->shrd->ucode_type = old_type;
 			return ret;
@@ -647,7 +650,7 @@
 	lockdep_assert_held(&trans->shrd->mutex);
 
 	/* No init ucode required? Curious, but maybe ok */
-	if (!trans->ucode_init.code.len)
+	if (!nic(trans)->fw.ucode_init.code.len)
 		return 0;
 
 	if (trans->shrd->ucode_type != IWL_UCODE_NONE)
@@ -685,42 +688,42 @@
 
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
 
-#define UCODE_EXPERIMENTAL_INDEX	100
 #define UCODE_EXPERIMENTAL_TAG		"exp"
 
-int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
+int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first)
 {
-	const char *name_pre = cfg(priv)->fw_name_pre;
+	struct iwl_cfg *cfg = cfg(nic);
+	const char *name_pre = cfg->fw_name_pre;
 	char tag[8];
 
 	if (first) {
 #ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
-		priv->fw_index = UCODE_EXPERIMENTAL_INDEX;
+		nic->fw_index = UCODE_EXPERIMENTAL_INDEX;
 		strcpy(tag, UCODE_EXPERIMENTAL_TAG);
-	} else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) {
+	} else if (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) {
 #endif
-		priv->fw_index = cfg(priv)->ucode_api_max;
-		sprintf(tag, "%d", priv->fw_index);
+		nic->fw_index = cfg->ucode_api_max;
+		sprintf(tag, "%d", nic->fw_index);
 	} else {
-		priv->fw_index--;
-		sprintf(tag, "%d", priv->fw_index);
+		nic->fw_index--;
+		sprintf(tag, "%d", nic->fw_index);
 	}
 
-	if (priv->fw_index < cfg(priv)->ucode_api_min) {
-		IWL_ERR(priv, "no suitable firmware found!\n");
+	if (nic->fw_index < cfg->ucode_api_min) {
+		IWL_ERR(nic, "no suitable firmware found!\n");
 		return -ENOENT;
 	}
 
-	sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
+	sprintf(nic->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
 
-	IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n",
-		       (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
+	IWL_DEBUG_INFO(nic, "attempting to load firmware %s'%s'\n",
+		       (nic->fw_index == UCODE_EXPERIMENTAL_INDEX)
 				? "EXPERIMENTAL " : "",
-		       priv->firmware_name);
+		       nic->firmware_name);
 
-	return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
-				       trans(priv)->dev,
-				       GFP_KERNEL, priv, iwl_ucode_callback);
+	return request_firmware_nowait(THIS_MODULE, 1, nic->firmware_name,
+				       trans(nic)->dev,
+				       GFP_KERNEL, nic, iwl_ucode_callback);
 }
 
 struct iwlagn_firmware_pieces {
@@ -728,31 +731,30 @@
 	size_t inst_size, data_size, init_size, init_data_size,
 	       wowlan_inst_size, wowlan_data_size;
 
-	u32 build;
-
 	u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
 	u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
 };
 
-static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
+static int iwl_parse_v1_v2_firmware(struct iwl_nic *nic,
 				       const struct firmware *ucode_raw,
 				       struct iwlagn_firmware_pieces *pieces)
 {
 	struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
-	u32 api_ver, hdr_size;
+	u32 api_ver, hdr_size, build;
+	char buildstr[25];
 	const u8 *src;
 
-	priv->ucode_ver = le32_to_cpu(ucode->ver);
-	api_ver = IWL_UCODE_API(priv->ucode_ver);
+	nic->fw.ucode_ver = le32_to_cpu(ucode->ver);
+	api_ver = IWL_UCODE_API(nic->fw.ucode_ver);
 
 	switch (api_ver) {
 	default:
 		hdr_size = 28;
 		if (ucode_raw->size < hdr_size) {
-			IWL_ERR(priv, "File size too small!\n");
+			IWL_ERR(nic, "File size too small!\n");
 			return -EINVAL;
 		}
-		pieces->build = le32_to_cpu(ucode->u.v2.build);
+		build = le32_to_cpu(ucode->u.v2.build);
 		pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
 		pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
 		pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
@@ -764,10 +766,10 @@
 	case 2:
 		hdr_size = 24;
 		if (ucode_raw->size < hdr_size) {
-			IWL_ERR(priv, "File size too small!\n");
+			IWL_ERR(nic, "File size too small!\n");
 			return -EINVAL;
 		}
-		pieces->build = 0;
+		build = 0;
 		pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size);
 		pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
 		pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
@@ -776,12 +778,28 @@
 		break;
 	}
 
+	if (build)
+		sprintf(buildstr, " build %u%s", build,
+		       (nic->fw_index == UCODE_EXPERIMENTAL_INDEX)
+				? " (EXP)" : "");
+	else
+		buildstr[0] = '\0';
+
+	snprintf(nic->fw.fw_version,
+		 sizeof(nic->fw.fw_version),
+		 "%u.%u.%u.%u%s",
+		 IWL_UCODE_MAJOR(nic->fw.ucode_ver),
+		 IWL_UCODE_MINOR(nic->fw.ucode_ver),
+		 IWL_UCODE_API(nic->fw.ucode_ver),
+		 IWL_UCODE_SERIAL(nic->fw.ucode_ver),
+		 buildstr);
+
 	/* Verify size of file vs. image size info in file's header */
 	if (ucode_raw->size != hdr_size + pieces->inst_size +
 				pieces->data_size + pieces->init_size +
 				pieces->init_data_size) {
 
-		IWL_ERR(priv,
+		IWL_ERR(nic,
 			"uCode file size %d does not match expected size\n",
 			(int)ucode_raw->size);
 		return -EINVAL;
@@ -799,10 +817,10 @@
 	return 0;
 }
 
-static int iwlagn_load_firmware(struct iwl_priv *priv,
+static int iwl_parse_tlv_firmware(struct iwl_nic *nic,
 				const struct firmware *ucode_raw,
 				struct iwlagn_firmware_pieces *pieces,
-				struct iwlagn_ucode_capabilities *capa)
+				struct iwl_ucode_capabilities *capa)
 {
 	struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data;
 	struct iwl_ucode_tlv *tlv;
@@ -814,14 +832,16 @@
 	u32 tlv_len;
 	enum iwl_ucode_tlv_type tlv_type;
 	const u8 *tlv_data;
+	char buildstr[25];
+	u32 build;
 
 	if (len < sizeof(*ucode)) {
-		IWL_ERR(priv, "uCode has invalid length: %zd\n", len);
+		IWL_ERR(nic, "uCode has invalid length: %zd\n", len);
 		return -EINVAL;
 	}
 
 	if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) {
-		IWL_ERR(priv, "invalid uCode magic: 0X%x\n",
+		IWL_ERR(nic, "invalid uCode magic: 0X%x\n",
 			le32_to_cpu(ucode->magic));
 		return -EINVAL;
 	}
@@ -839,12 +859,29 @@
 	while (wanted_alternative && !(alternatives & BIT(wanted_alternative)))
 		wanted_alternative--;
 	if (wanted_alternative && wanted_alternative != tmp)
-		IWL_WARN(priv,
+		IWL_WARN(nic,
 			 "uCode alternative %d not available, choosing %d\n",
 			 tmp, wanted_alternative);
 
-	priv->ucode_ver = le32_to_cpu(ucode->ver);
-	pieces->build = le32_to_cpu(ucode->build);
+	nic->fw.ucode_ver = le32_to_cpu(ucode->ver);
+	build = le32_to_cpu(ucode->build);
+
+	if (build)
+		sprintf(buildstr, " build %u%s", build,
+		       (nic->fw_index == UCODE_EXPERIMENTAL_INDEX)
+				? " (EXP)" : "");
+	else
+		buildstr[0] = '\0';
+
+	snprintf(nic->fw.fw_version,
+		 sizeof(nic->fw.fw_version),
+		 "%u.%u.%u.%u%s",
+		 IWL_UCODE_MAJOR(nic->fw.ucode_ver),
+		 IWL_UCODE_MINOR(nic->fw.ucode_ver),
+		 IWL_UCODE_API(nic->fw.ucode_ver),
+		 IWL_UCODE_SERIAL(nic->fw.ucode_ver),
+		 buildstr);
+
 	data = ucode->data;
 
 	len -= sizeof(*ucode);
@@ -861,7 +898,7 @@
 		tlv_data = tlv->data;
 
 		if (len < tlv_len) {
-			IWL_ERR(priv, "invalid TLV len: %zd/%u\n",
+			IWL_ERR(nic, "invalid TLV len: %zd/%u\n",
 				len, tlv_len);
 			return -EINVAL;
 		}
@@ -894,7 +931,7 @@
 			pieces->init_data_size = tlv_len;
 			break;
 		case IWL_UCODE_TLV_BOOT:
-			IWL_ERR(priv, "Found unexpected BOOT ucode\n");
+			IWL_ERR(nic, "Found unexpected BOOT ucode\n");
 			break;
 		case IWL_UCODE_TLV_PROBE_MAX_LEN:
 			if (tlv_len != sizeof(u32))
@@ -962,7 +999,7 @@
 		case IWL_UCODE_TLV_ENHANCE_SENS_TBL:
 			if (tlv_len)
 				goto invalid_tlv_len;
-			priv->enhance_sensitivity_table = true;
+			nic->fw.enhance_sensitivity_table = true;
 			break;
 		case IWL_UCODE_TLV_WOWLAN_INST:
 			pieces->wowlan_inst = tlv_data;
@@ -979,22 +1016,22 @@
 					le32_to_cpup((__le32 *)tlv_data);
 			break;
 		default:
-			IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type);
+			IWL_DEBUG_INFO(nic, "unknown TLV: %d\n", tlv_type);
 			break;
 		}
 	}
 
 	if (len) {
-		IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len);
-		iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len);
+		IWL_ERR(nic, "invalid TLV after parsing: %zd\n", len);
+		iwl_print_hex_dump(nic, IWL_DL_FW, (u8 *)data, len);
 		return -EINVAL;
 	}
 
 	return 0;
 
  invalid_tlv_len:
-	IWL_ERR(priv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
-	iwl_print_hex_dump(priv, IWL_DL_FW, tlv_data, tlv_len);
+	IWL_ERR(nic, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
+	iwl_print_hex_dump(nic, IWL_DL_FW, tlv_data, tlv_len);
 
 	return -EINVAL;
 }
@@ -1007,21 +1044,20 @@
  */
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 {
-	struct iwl_priv *priv = context;
+	struct iwl_nic *nic = context;
+	struct iwl_cfg *cfg = cfg(nic);
+	struct iwl_fw *fw = &nic->fw;
 	struct iwl_ucode_header *ucode;
 	int err;
 	struct iwlagn_firmware_pieces pieces;
-	const unsigned int api_max = cfg(priv)->ucode_api_max;
-	unsigned int api_ok = cfg(priv)->ucode_api_ok;
-	const unsigned int api_min = cfg(priv)->ucode_api_min;
+	const unsigned int api_max = cfg->ucode_api_max;
+	unsigned int api_ok = cfg->ucode_api_ok;
+	const unsigned int api_min = cfg->ucode_api_min;
 	u32 api_ver;
-	char buildstr[25];
-	u32 build;
-	struct iwlagn_ucode_capabilities ucode_capa = {
-		.max_probe_length = 200,
-		.standard_phy_calibration_size =
-			IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE,
-	};
+
+	fw->ucode_capa.max_probe_length = 200;
+	fw->ucode_capa.standard_phy_calibration_size =
+			IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE;
 
 	if (!api_ok)
 		api_ok = api_max;
@@ -1029,19 +1065,19 @@
 	memset(&pieces, 0, sizeof(pieces));
 
 	if (!ucode_raw) {
-		if (priv->fw_index <= api_ok)
-			IWL_ERR(priv,
+		if (nic->fw_index <= api_ok)
+			IWL_ERR(nic,
 				"request for firmware file '%s' failed.\n",
-				priv->firmware_name);
+				nic->firmware_name);
 		goto try_again;
 	}
 
-	IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n",
-		       priv->firmware_name, ucode_raw->size);
+	IWL_DEBUG_INFO(nic, "Loaded firmware file '%s' (%zd bytes).\n",
+		       nic->firmware_name, ucode_raw->size);
 
 	/* Make sure that we got at least the API version number */
 	if (ucode_raw->size < 4) {
-		IWL_ERR(priv, "File size way too small!\n");
+		IWL_ERR(nic, "File size way too small!\n");
 		goto try_again;
 	}
 
@@ -1049,16 +1085,15 @@
 	ucode = (struct iwl_ucode_header *)ucode_raw->data;
 
 	if (ucode->ver)
-		err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces);
+		err = iwl_parse_v1_v2_firmware(nic, ucode_raw, &pieces);
 	else
-		err = iwlagn_load_firmware(priv, ucode_raw, &pieces,
-					   &ucode_capa);
+		err = iwl_parse_tlv_firmware(nic, ucode_raw, &pieces,
+					   &fw->ucode_capa);
 
 	if (err)
 		goto try_again;
 
-	api_ver = IWL_UCODE_API(priv->ucode_ver);
-	build = pieces.build;
+	api_ver = IWL_UCODE_API(nic->fw.ucode_ver);
 
 	/*
 	 * api_ver should match the api version forming part of the
@@ -1066,9 +1101,9 @@
 	 * on the API version read from firmware header from here on forward
 	 */
 	/* no api version check required for experimental uCode */
-	if (priv->fw_index != UCODE_EXPERIMENTAL_INDEX) {
+	if (nic->fw_index != UCODE_EXPERIMENTAL_INDEX) {
 		if (api_ver < api_min || api_ver > api_max) {
-			IWL_ERR(priv,
+			IWL_ERR(nic,
 				"Driver unable to support your firmware API. "
 				"Driver supports v%u, firmware is v%u.\n",
 				api_max, api_ver);
@@ -1077,40 +1112,19 @@
 
 		if (api_ver < api_ok) {
 			if (api_ok != api_max)
-				IWL_ERR(priv, "Firmware has old API version, "
+				IWL_ERR(nic, "Firmware has old API version, "
 					"expected v%u through v%u, got v%u.\n",
 					api_ok, api_max, api_ver);
 			else
-				IWL_ERR(priv, "Firmware has old API version, "
+				IWL_ERR(nic, "Firmware has old API version, "
 					"expected v%u, got v%u.\n",
 					api_max, api_ver);
-			IWL_ERR(priv, "New firmware can be obtained from "
+			IWL_ERR(nic, "New firmware can be obtained from "
 				      "http://www.intellinuxwireless.org/.\n");
 		}
 	}
 
-	if (build)
-		sprintf(buildstr, " build %u%s", build,
-		       (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
-				? " (EXP)" : "");
-	else
-		buildstr[0] = '\0';
-
-	IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n",
-		 IWL_UCODE_MAJOR(priv->ucode_ver),
-		 IWL_UCODE_MINOR(priv->ucode_ver),
-		 IWL_UCODE_API(priv->ucode_ver),
-		 IWL_UCODE_SERIAL(priv->ucode_ver),
-		 buildstr);
-
-	snprintf(priv->hw->wiphy->fw_version,
-		 sizeof(priv->hw->wiphy->fw_version),
-		 "%u.%u.%u.%u%s",
-		 IWL_UCODE_MAJOR(priv->ucode_ver),
-		 IWL_UCODE_MINOR(priv->ucode_ver),
-		 IWL_UCODE_API(priv->ucode_ver),
-		 IWL_UCODE_SERIAL(priv->ucode_ver),
-		 buildstr);
+	IWL_INFO(nic, "loaded firmware version %s", nic->fw.fw_version);
 
 	/*
 	 * For any of the failures below (before allocating pci memory)
@@ -1118,38 +1132,38 @@
 	 * user just got a corrupted version of the latest API.
 	 */
 
-	IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
-		       priv->ucode_ver);
-	IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n",
+	IWL_DEBUG_INFO(nic, "f/w package hdr ucode version raw = 0x%x\n",
+		       nic->fw.ucode_ver);
+	IWL_DEBUG_INFO(nic, "f/w package hdr runtime inst size = %Zd\n",
 		       pieces.inst_size);
-	IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n",
+	IWL_DEBUG_INFO(nic, "f/w package hdr runtime data size = %Zd\n",
 		       pieces.data_size);
-	IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n",
+	IWL_DEBUG_INFO(nic, "f/w package hdr init inst size = %Zd\n",
 		       pieces.init_size);
-	IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
+	IWL_DEBUG_INFO(nic, "f/w package hdr init data size = %Zd\n",
 		       pieces.init_data_size);
 
 	/* Verify that uCode images will fit in card's SRAM */
-	if (pieces.inst_size > hw_params(priv).max_inst_size) {
-		IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n",
+	if (pieces.inst_size > cfg->max_inst_size) {
+		IWL_ERR(nic, "uCode instr len %Zd too large to fit in\n",
 			pieces.inst_size);
 		goto try_again;
 	}
 
-	if (pieces.data_size > hw_params(priv).max_data_size) {
-		IWL_ERR(priv, "uCode data len %Zd too large to fit in\n",
+	if (pieces.data_size > cfg->max_data_size) {
+		IWL_ERR(nic, "uCode data len %Zd too large to fit in\n",
 			pieces.data_size);
 		goto try_again;
 	}
 
-	if (pieces.init_size > hw_params(priv).max_inst_size) {
-		IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n",
+	if (pieces.init_size > cfg->max_inst_size) {
+		IWL_ERR(nic, "uCode init instr len %Zd too large to fit in\n",
 			pieces.init_size);
 		goto try_again;
 	}
 
-	if (pieces.init_data_size > hw_params(priv).max_data_size) {
-		IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n",
+	if (pieces.init_data_size > cfg->max_data_size) {
+		IWL_ERR(nic, "uCode init data len %Zd too large to fit in\n",
 			pieces.init_data_size);
 		goto try_again;
 	}
@@ -1159,34 +1173,34 @@
 	/* Runtime instructions and 2 copies of data:
 	 * 1) unmodified from disk
 	 * 2) backup cache for save/restore during power-downs */
-	if (iwl_alloc_fw_desc(trans(priv), &trans(priv)->ucode_rt.code,
+	if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.code,
 			      pieces.inst, pieces.inst_size))
 		goto err_pci_alloc;
-	if (iwl_alloc_fw_desc(trans(priv), &trans(priv)->ucode_rt.data,
+	if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.data,
 			      pieces.data, pieces.data_size))
 		goto err_pci_alloc;
 
 	/* Initialization instructions and data */
 	if (pieces.init_size && pieces.init_data_size) {
-		if (iwl_alloc_fw_desc(trans(priv),
-				      &trans(priv)->ucode_init.code,
+		if (iwl_alloc_fw_desc(nic,
+				      &nic->fw.ucode_init.code,
 				      pieces.init, pieces.init_size))
 			goto err_pci_alloc;
-		if (iwl_alloc_fw_desc(trans(priv),
-				      &trans(priv)->ucode_init.data,
+		if (iwl_alloc_fw_desc(nic,
+				      &nic->fw.ucode_init.data,
 				      pieces.init_data, pieces.init_data_size))
 			goto err_pci_alloc;
 	}
 
 	/* WoWLAN instructions and data */
 	if (pieces.wowlan_inst_size && pieces.wowlan_data_size) {
-		if (iwl_alloc_fw_desc(trans(priv),
-				      &trans(priv)->ucode_wowlan.code,
+		if (iwl_alloc_fw_desc(nic,
+				      &nic->fw.ucode_wowlan.code,
 				      pieces.wowlan_inst,
 				      pieces.wowlan_inst_size))
 			goto err_pci_alloc;
-		if (iwl_alloc_fw_desc(trans(priv),
-				      &trans(priv)->ucode_wowlan.data,
+		if (iwl_alloc_fw_desc(nic,
+				      &nic->fw.ucode_wowlan.data,
 				      pieces.wowlan_data,
 				      pieces.wowlan_data_size))
 			goto err_pci_alloc;
@@ -1199,92 +1213,54 @@
 	 * for each event, which is of mode 1 (including timestamp) for all
 	 * new microcodes that include this information.
 	 */
-	priv->init_evtlog_ptr = pieces.init_evtlog_ptr;
+	nic->init_evtlog_ptr = pieces.init_evtlog_ptr;
 	if (pieces.init_evtlog_size)
-		priv->init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
+		nic->init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
 	else
-		priv->init_evtlog_size =
-			cfg(priv)->base_params->max_event_log_size;
-	priv->init_errlog_ptr = pieces.init_errlog_ptr;
-	priv->inst_evtlog_ptr = pieces.inst_evtlog_ptr;
+		nic->init_evtlog_size =
+			cfg->base_params->max_event_log_size;
+	nic->init_errlog_ptr = pieces.init_errlog_ptr;
+	nic->inst_evtlog_ptr = pieces.inst_evtlog_ptr;
 	if (pieces.inst_evtlog_size)
-		priv->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
+		nic->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
 	else
-		priv->inst_evtlog_size =
-			cfg(priv)->base_params->max_event_log_size;
-	priv->inst_errlog_ptr = pieces.inst_errlog_ptr;
-#ifndef CONFIG_IWLWIFI_P2P
-	ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
-#endif
+		nic->inst_evtlog_size =
+			cfg->base_params->max_event_log_size;
+	nic->inst_errlog_ptr = pieces.inst_errlog_ptr;
 
-	priv->new_scan_threshold_behaviour =
-		!!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
-
-	if (!(cfg(priv)->sku & EEPROM_SKU_CAP_IPAN_ENABLE))
-		ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
-
-	/*
-	 * if not PAN, then don't support P2P -- might be a uCode
-	 * packaging bug or due to the eeprom check above
-	 */
-	if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN))
-		ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
-
-	if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) {
-		priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
-		priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
-	} else {
-		priv->sta_key_max_num = STA_KEY_MAX_NUM;
-		priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
-	}
 	/*
 	 * figure out the offset of chain noise reset and gain commands
 	 * base on the size of standard phy calibration commands table size
 	 */
-	if (ucode_capa.standard_phy_calibration_size >
+	if (fw->ucode_capa.standard_phy_calibration_size >
 	    IWL_MAX_PHY_CALIBRATE_TBL_SIZE)
-		ucode_capa.standard_phy_calibration_size =
+		fw->ucode_capa.standard_phy_calibration_size =
 			IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE;
 
-	priv->phy_calib_chain_noise_reset_cmd =
-		ucode_capa.standard_phy_calibration_size;
-	priv->phy_calib_chain_noise_gain_cmd =
-		ucode_capa.standard_phy_calibration_size + 1;
-
-	/* initialize all valid contexts */
-	iwl_init_context(priv, ucode_capa.flags);
-
-	/**************************************************
-	 * This is still part of probe() in a sense...
-	 *
-	 * 9. Setup and register with mac80211 and debugfs
-	 **************************************************/
-	err = iwlagn_mac_setup_register(priv, &ucode_capa);
-	if (err)
-		goto out_unbind;
-
-	err = iwl_dbgfs_register(priv, DRV_NAME);
-	if (err)
-		IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
-
 	/* We have our copies now, allow OS release its copies */
 	release_firmware(ucode_raw);
-	complete(&priv->firmware_loading_complete);
+	complete(&nic->request_firmware_complete);
+
+	nic->op_mode = iwl_dvm_ops.start(nic->shrd->trans);
+
+	if (!nic->op_mode)
+		goto out_unbind;
+
 	return;
 
  try_again:
 	/* try next, if any */
-	if (iwl_request_firmware(priv, false))
-		goto out_unbind;
 	release_firmware(ucode_raw);
+	if (iwl_request_firmware(nic, false))
+		goto out_unbind;
 	return;
 
  err_pci_alloc:
-	IWL_ERR(priv, "failed to allocate pci memory\n");
-	iwl_dealloc_ucode(trans(priv));
- out_unbind:
-	complete(&priv->firmware_loading_complete);
-	device_release_driver(trans(priv)->dev);
+	IWL_ERR(nic, "failed to allocate pci memory\n");
+	iwl_dealloc_ucode(nic);
 	release_firmware(ucode_raw);
+ out_unbind:
+	complete(&nic->request_firmware_complete);
+	device_release_driver(trans(nic)->dev);
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.h b/drivers/net/wireless/iwlwifi/iwl-ucode.h
index eccf925..8bebeb0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-ucode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-ucode.h
@@ -63,6 +63,8 @@
 #ifndef __iwl_ucode_h__
 #define __iwl_ucode_h__
 
+#include <linux/netdevice.h>
+
 /* v1/v2 uCode file layout */
 struct iwl_ucode_header {
 	__le32 ver;	/* major/minor/API/serial */
@@ -171,8 +173,48 @@
 	u8 data[0];
 };
 
-struct iwl_priv;
+struct iwl_ucode_capabilities {
+	u32 max_probe_length;
+	u32 standard_phy_calibration_size;
+	u32 flags;
+};
 
-int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first);
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+	dma_addr_t p_addr;	/* hardware address */
+	void *v_addr;		/* software address */
+	u32 len;		/* size in bytes */
+};
+
+struct fw_img {
+	struct fw_desc code;	/* firmware code image */
+	struct fw_desc data;	/* firmware data image */
+};
+
+/**
+ * struct iwl_fw - variables associated with the firmware
+ *
+ * @ucode_ver: ucode version from the ucode file
+ * @fw_version: firmware version string
+ * @ucode_rt: run time ucode image
+ * @ucode_init: init ucode image
+ * @ucode_wowlan: wake on wireless ucode image (optional)
+ * @ucode_capa: capabilities parsed from the ucode file.
+ * @enhance_sensitivity_table: device can do enhanced sensitivity.
+ */
+struct iwl_fw {
+
+	u32 ucode_ver;
+
+	char fw_version[ETHTOOL_BUSINFO_LEN];
+
+	/* ucode images */
+	struct fw_img ucode_rt;
+	struct fw_img ucode_init;
+	struct fw_img ucode_wowlan;
+
+	struct iwl_ucode_capabilities ucode_capa;
+	bool enhance_sensitivity_table;
+};
 
 #endif  /* __iwl_ucode_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h
index 7e6eb20..d5cba07 100644
--- a/drivers/net/wireless/iwlwifi/iwl-wifi.h
+++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h
@@ -64,6 +64,43 @@
 #define __iwl_wifi_h__
 
 #include "iwl-shared.h"
+#include "iwl-ucode.h"
+
+#define UCODE_EXPERIMENTAL_INDEX	100
+
+/**
+ * struct iwl_nic - nic common data
+ * @fw: the iwl_fw structure
+ * @shrd: pointer to common shared structure
+ * @op_mode: the running op_mode
+ * @fw_index: firmware revision to try loading
+ * @firmware_name: composite filename of ucode file to load
+ * @init_evtlog_ptr: event log offset for init ucode.
+ * @init_evtlog_size: event log size for init ucode.
+ * @init_errlog_ptr: error log offfset for init ucode.
+ * @inst_evtlog_ptr: event log offset for runtime ucode.
+ * @inst_evtlog_size: event log size for runtime ucode.
+ * @inst_errlog_ptr: error log offfset for runtime ucode.
+ * @request_firmware_complete: the firmware has been obtained from user space
+ */
+struct iwl_nic {
+	struct iwl_fw fw;
+
+	struct iwl_shared *shrd;
+	struct iwl_op_mode *op_mode;
+
+	int fw_index;                   /* firmware we're trying to load */
+	char firmware_name[25];         /* name of firmware file to load */
+
+	u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+	u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+
+	struct completion request_firmware_complete;
+};
+
+
+int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first);
+void iwl_dealloc_ucode(struct iwl_nic *nic);
 
 int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type);
 void iwl_send_prio_tbl(struct iwl_trans *trans);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 4b9e730..ba16f05 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -592,7 +592,7 @@
 	return;
 
 nla_put_failure:
-	printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+	printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
 }
 
 static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
@@ -1564,7 +1564,7 @@
 
 	return 0;
 err:
-	printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+	printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
 	goto out;
 out:
 	dev_kfree_skb(skb);
@@ -1580,11 +1580,11 @@
 	wmediumd_pid = info->snd_pid;
 
 	printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, "
-	"switching to wmediumd mode with pid %d\n", info->snd_pid);
+	       "switching to wmediumd mode with pid %d\n", info->snd_pid);
 
 	return 0;
 out:
-	printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+	printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
 	return -EINVAL;
 }
 
@@ -1647,7 +1647,7 @@
 	return 0;
 
 failure:
-	printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+	printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
 	return -EINVAL;
 }
 
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 8d8ee63..a460fb0 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -146,7 +146,7 @@
 	struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
 
 	/* Return if WEP key not configured */
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED)
+	if (!priv->sec_info.wep_enabled)
 		return 0;
 
 	if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) {
@@ -872,6 +872,7 @@
 	priv->sec_info.wpa_enabled = false;
 	priv->sec_info.wpa2_enabled = false;
 	priv->wep_key_curr_index = 0;
+	priv->sec_info.encryption_mode = 0;
 	ret = mwifiex_set_encode(priv, NULL, 0, 0, 1);
 
 	if (mode == NL80211_IFTYPE_ADHOC) {
@@ -923,12 +924,6 @@
 		}
 	}
 done:
-	/* Do specific SSID scanning */
-	if (mwifiex_request_scan(priv, &req_ssid)) {
-		dev_err(priv->adapter->dev, "scan error\n");
-		return -EFAULT;
-	}
-
 	/*
 	 * Scan entries are valid for some time (15 sec). So we can save one
 	 * active scan time if we just try cfg80211_get_bss first. If it fails
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 51c5417..c826200 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -86,11 +86,6 @@
 	MWIFIEX_802_11_PRIV_FILTER_8021X_WEP
 };
 
-enum MWIFIEX_802_11_WEP_STATUS {
-	MWIFIEX_802_11_WEP_ENABLED,
-	MWIFIEX_802_11_WEP_DISABLED,
-};
-
 #define CAL_SNR(RSSI, NF)		((s16)((s16)(RSSI)-(s16)(NF)))
 
 #define PROPRIETARY_TLV_BASE_ID                 0x0100
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index ca59cc0..e81bf6e 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -82,7 +82,7 @@
 	priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
 	priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
 
-	priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
+	priv->sec_info.wep_enabled = 0;
 	priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
 	priv->sec_info.encryption_mode = 0;
 	for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++)
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 0b0eb5e..ee439fc 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -417,7 +417,7 @@
 	auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
 	auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
 	auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type));
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+	if (priv->sec_info.wep_enabled)
 		auth_tlv->auth_type = cpu_to_le16(
 				(u16) priv->sec_info.authentication_mode);
 	else
@@ -1069,8 +1069,7 @@
 	priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel;
 	priv->curr_bss_params.band = (u8) bss_desc->bss_band;
 
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
-	    || priv->sec_info.wpa_enabled)
+	if (priv->sec_info.wep_enabled || priv->sec_info.wpa_enabled)
 		tmp_cap |= WLAN_CAPABILITY_PRIVACY;
 
 	if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) {
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 52810b1..4c86217 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -217,7 +217,7 @@
 	u8 wpa2_enabled;
 	u8 wapi_enabled;
 	u8 wapi_key_on;
-	enum MWIFIEX_802_11_WEP_STATUS wep_status;
+	u8 wep_enabled;
 	u32 authentication_mode;
 	u32 encryption_mode;
 };
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 98f1ca9..8f10038 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -196,9 +196,8 @@
 mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv,
 				       struct mwifiex_bssdescriptor *bss_desc)
 {
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-	    && ((!bss_desc->bcn_wpa_ie) ||
+	if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+	    !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
 		((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
 	    WLAN_EID_WPA))
 	    && ((!bss_desc->bcn_rsn_ie) ||
@@ -219,9 +218,8 @@
 mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
 				       struct mwifiex_bssdescriptor *bss_desc)
 {
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
-	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-	    && bss_desc->privacy) {
+	if (priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+	    !priv->sec_info.wpa2_enabled && bss_desc->privacy) {
 		return true;
 	}
 	return false;
@@ -235,10 +233,9 @@
 mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
 				      struct mwifiex_bssdescriptor *bss_desc)
 {
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-	    && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-	    && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
-						element_id == WLAN_EID_WPA))
+	if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled &&
+	    !priv->sec_info.wpa2_enabled && ((bss_desc->bcn_wpa_ie) &&
+	    ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == WLAN_EID_WPA))
 	   /*
 	    * Privacy bit may NOT be set in some APs like
 	    * LinkSys WRT54G && bss_desc->privacy
@@ -253,8 +250,7 @@
 			(bss_desc->bcn_rsn_ie) ?
 			(*(bss_desc->bcn_rsn_ie)).
 			ieee_hdr.element_id : 0,
-			(priv->sec_info.wep_status ==
-			MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+			(priv->sec_info.wep_enabled) ? "e" : "d",
 			(priv->sec_info.wpa_enabled) ? "e" : "d",
 			(priv->sec_info.wpa2_enabled) ? "e" : "d",
 			priv->sec_info.encryption_mode,
@@ -272,10 +268,9 @@
 mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
 				       struct mwifiex_bssdescriptor *bss_desc)
 {
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-	   && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled
-	   && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
-						element_id == WLAN_EID_RSN))
+	if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+	    priv->sec_info.wpa2_enabled && ((bss_desc->bcn_rsn_ie) &&
+	    ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id == WLAN_EID_RSN))
 	   /*
 	    * Privacy bit may NOT be set in some APs like
 	    * LinkSys WRT54G && bss_desc->privacy
@@ -290,8 +285,7 @@
 			(bss_desc->bcn_rsn_ie) ?
 			(*(bss_desc->bcn_rsn_ie)).
 			ieee_hdr.element_id : 0,
-			(priv->sec_info.wep_status ==
-			MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+			(priv->sec_info.wep_enabled) ? "e" : "d",
 			(priv->sec_info.wpa_enabled) ? "e" : "d",
 			(priv->sec_info.wpa2_enabled) ? "e" : "d",
 			priv->sec_info.encryption_mode,
@@ -309,10 +303,9 @@
 mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
 				       struct mwifiex_bssdescriptor *bss_desc)
 {
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-	    && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
-		   element_id != WLAN_EID_WPA))
+	if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+	    !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
+	    ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA))
 	    && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
 		   element_id != WLAN_EID_RSN))
 	    && !priv->sec_info.encryption_mode
@@ -330,10 +323,9 @@
 mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
 				       struct mwifiex_bssdescriptor *bss_desc)
 {
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-	    && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
-		   element_id != WLAN_EID_WPA))
+	if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+	    !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
+	    ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA))
 	    && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
 		   element_id != WLAN_EID_RSN))
 	    && priv->sec_info.encryption_mode
@@ -468,8 +460,7 @@
 		       (bss_desc->bcn_rsn_ie) ?
 		       (*(bss_desc->bcn_rsn_ie)).ieee_hdr.
 		       element_id : 0,
-		       (priv->sec_info.wep_status ==
-				MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+		       (priv->sec_info.wep_enabled) ? "e" : "d",
 		       (priv->sec_info.wpa_enabled) ? "e" : "d",
 		       (priv->sec_info.wpa2_enabled) ? "e" : "d",
 		       priv->sec_info.encryption_mode, bss_desc->privacy);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index b0fbf5d..866026e 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -471,7 +471,7 @@
 
 	info->bcn_nf_last = priv->bcn_nf_last;
 
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+	if (priv->sec_info.wep_enabled)
 		info->wep_status = true;
 	else
 		info->wep_status = false;
@@ -1020,7 +1020,7 @@
 	wep_key = &priv->wep_key[priv->wep_key_curr_index];
 	index = encrypt_key->key_index;
 	if (encrypt_key->key_disable) {
-		priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
+		priv->sec_info.wep_enabled = 0;
 	} else if (!encrypt_key->key_len) {
 		/* Copy the required key as the current key */
 		wep_key = &priv->wep_key[index];
@@ -1030,7 +1030,7 @@
 			return -1;
 		}
 		priv->wep_key_curr_index = (u16) index;
-		priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
+		priv->sec_info.wep_enabled = 1;
 	} else {
 		wep_key = &priv->wep_key[index];
 		memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
@@ -1040,7 +1040,7 @@
 		       encrypt_key->key_len);
 		wep_key->key_index = index;
 		wep_key->key_length = encrypt_key->key_len;
-		priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
+		priv->sec_info.wep_enabled = 1;
 	}
 	if (wep_key->key_length) {
 		/* Send request to firmware */
@@ -1050,7 +1050,7 @@
 		if (ret)
 			return ret;
 	}
-	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+	if (priv->sec_info.wep_enabled)
 		priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
 	else
 		priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 42b97bc..a08a6f0 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -690,7 +690,7 @@
 	if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
 		*flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
 
-	if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)
+	if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)
 		*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
 
 	if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index a0a7854..299c387 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -163,7 +163,7 @@
        depends on EXPERIMENTAL
        ---help---
          This adds support for rt53xx wireless chipset family to the
-         rt2800pci driver.
+         rt2800usb driver.
          Supported chips: RT5370
 
 config RT2800USB_UNKNOWN
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 06acabd..e5c05d8 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -68,6 +68,7 @@
 #define RF3322				0x000c
 #define RF3053				0x000d
 #define RF5370				0x5370
+#define RF5372				0x5372
 #define RF5390				0x5390
 
 /*
@@ -965,6 +966,7 @@
  * TX_PIN_CFG:
  */
 #define TX_PIN_CFG			0x1328
+#define TX_PIN_CFG_PA_PE_DISABLE	0xfcfffff0
 #define TX_PIN_CFG_PA_PE_A0_EN		FIELD32(0x00000001)
 #define TX_PIN_CFG_PA_PE_G0_EN		FIELD32(0x00000002)
 #define TX_PIN_CFG_PA_PE_A1_EN		FIELD32(0x00000004)
@@ -985,6 +987,14 @@
 #define TX_PIN_CFG_RFTR_POL		FIELD32(0x00020000)
 #define TX_PIN_CFG_TRSW_EN		FIELD32(0x00040000)
 #define TX_PIN_CFG_TRSW_POL		FIELD32(0x00080000)
+#define TX_PIN_CFG_PA_PE_A2_EN		FIELD32(0x01000000)
+#define TX_PIN_CFG_PA_PE_G2_EN		FIELD32(0x02000000)
+#define TX_PIN_CFG_PA_PE_A2_POL		FIELD32(0x04000000)
+#define TX_PIN_CFG_PA_PE_G2_POL		FIELD32(0x08000000)
+#define TX_PIN_CFG_LNA_PE_A2_EN		FIELD32(0x10000000)
+#define TX_PIN_CFG_LNA_PE_G2_EN		FIELD32(0x20000000)
+#define TX_PIN_CFG_LNA_PE_A2_POL	FIELD32(0x40000000)
+#define TX_PIN_CFG_LNA_PE_G2_POL	FIELD32(0x80000000)
 
 /*
  * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz
@@ -1627,6 +1637,7 @@
 
 /*
  * H2M_MAILBOX_CSR: Host-to-MCU Mailbox.
+ * CMD_TOKEN: Command id, 0xff disable status reporting.
  */
 #define H2M_MAILBOX_CSR			0x7010
 #define H2M_MAILBOX_CSR_ARG0		FIELD32(0x000000ff)
@@ -1636,6 +1647,8 @@
 
 /*
  * H2M_MAILBOX_CID:
+ * Free slots contain 0xff. MCU will store command's token to lowest free slot.
+ * If all slots are occupied status will be dropped.
  */
 #define H2M_MAILBOX_CID			0x7014
 #define H2M_MAILBOX_CID_CMD0		FIELD32(0x000000ff)
@@ -1645,6 +1658,7 @@
 
 /*
  * H2M_MAILBOX_STATUS:
+ * Command status will be saved to same slot as command id.
  */
 #define H2M_MAILBOX_STATUS		0x701c
 
@@ -2288,6 +2302,12 @@
 
 /*
  * MCU mailbox commands.
+ * MCU_SLEEP - go to power-save mode.
+ *             arg1: 1: save as much power as possible, 0: save less power.
+ *             status: 1: success, 2: already asleep,
+ *                     3: maybe MAC is busy so can't finish this task.
+ * MCU_RADIO_OFF
+ *             arg0: 0: do power-saving, NOT turn off radio.
  */
 #define MCU_SLEEP			0x30
 #define MCU_WAKEUP			0x31
@@ -2308,7 +2328,10 @@
 /*
  * MCU mailbox tokens
  */
-#define TOKEN_WAKUP			3
+#define TOKEN_SLEEP			1
+#define TOKEN_RADIO_OFF			2
+#define TOKEN_WAKEUP			3
+
 
 /*
  * DMA descriptor defines.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 772d4ae..474b5b9 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -402,7 +402,8 @@
 
 	if (rt2x00_is_pci(rt2x00dev)) {
 		if (rt2x00_rt(rt2x00dev, RT3572) ||
-		    rt2x00_rt(rt2x00dev, RT5390)) {
+		    rt2x00_rt(rt2x00dev, RT5390) ||
+		    rt2x00_rt(rt2x00dev, RT5392)) {
 			rt2800_register_read(rt2x00dev, AUX_CTRL, &reg);
 			rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
 			rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
@@ -1989,7 +1990,8 @@
 						   r55_nonbt_rev[idx]);
 				rt2800_rfcsr_write(rt2x00dev, 59,
 						   r59_nonbt_rev[idx]);
-			} else if (rt2x00_rt(rt2x00dev, RT5390)) {
+			} else if (rt2x00_rt(rt2x00dev, RT5390) ||
+					   rt2x00_rt(rt2x00dev, RT5392)) {
 				static const char r59_non_bt[] = {0x8f, 0x8f,
 					0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d,
 					0x8a, 0x88, 0x88, 0x87, 0x87, 0x86};
@@ -2039,6 +2041,7 @@
 		rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
 		break;
 	case RF5370:
+	case RF5372:
 	case RF5390:
 		rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
 		break;
@@ -2055,7 +2058,8 @@
 	rt2800_bbp_write(rt2x00dev, 86, 0);
 
 	if (rf->channel <= 14) {
-		if (!rt2x00_rt(rt2x00dev, RT5390)) {
+		if (!rt2x00_rt(rt2x00dev, RT5390) &&
+			!rt2x00_rt(rt2x00dev, RT5392)) {
 			if (test_bit(CAPABILITY_EXTERNAL_LNA_BG,
 				     &rt2x00dev->cap_flags)) {
 				rt2800_bbp_write(rt2x00dev, 82, 0x62);
@@ -2497,6 +2501,80 @@
 }
 EXPORT_SYMBOL_GPL(rt2800_gain_calibration);
 
+void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
+{
+	u32	tx_pin;
+	u8	rfcsr;
+
+	/*
+	 * A voltage-controlled oscillator(VCO) is an electronic oscillator
+	 * designed to be controlled in oscillation frequency by a voltage
+	 * input. Maybe the temperature will affect the frequency of
+	 * oscillation to be shifted. The VCO calibration will be called
+	 * periodically to adjust the frequency to be precision.
+	*/
+
+	rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin);
+	tx_pin &= TX_PIN_CFG_PA_PE_DISABLE;
+	rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
+
+	switch (rt2x00dev->chip.rf) {
+	case RF2020:
+	case RF3020:
+	case RF3021:
+	case RF3022:
+	case RF3320:
+	case RF3052:
+		rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr);
+		rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
+		rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
+		break;
+	case RF5370:
+	case RF5372:
+	case RF5390:
+		rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
+		rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
+		rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
+		break;
+	default:
+		return;
+	}
+
+	mdelay(1);
+
+	rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin);
+	if (rt2x00dev->rf_channel <= 14) {
+		switch (rt2x00dev->default_ant.tx_chain_num) {
+		case 3:
+			rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G2_EN, 1);
+			/* fall through */
+		case 2:
+			rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1);
+			/* fall through */
+		case 1:
+		default:
+			rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1);
+			break;
+		}
+	} else {
+		switch (rt2x00dev->default_ant.tx_chain_num) {
+		case 3:
+			rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A2_EN, 1);
+			/* fall through */
+		case 2:
+			rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1);
+			/* fall through */
+		case 1:
+		default:
+			rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, 1);
+			break;
+		}
+	}
+	rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
+
+}
+EXPORT_SYMBOL_GPL(rt2800_vco_calibration);
+
 static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
 				      struct rt2x00lib_conf *libconf)
 {
@@ -2585,7 +2663,8 @@
 		    rt2x00_rt(rt2x00dev, RT3071) ||
 		    rt2x00_rt(rt2x00dev, RT3090) ||
 		    rt2x00_rt(rt2x00dev, RT3390) ||
-		    rt2x00_rt(rt2x00dev, RT5390))
+		    rt2x00_rt(rt2x00dev, RT5390) ||
+		    rt2x00_rt(rt2x00dev, RT5392))
 			return 0x1c + (2 * rt2x00dev->lna_gain);
 		else
 			return 0x2e + rt2x00dev->lna_gain;
@@ -2720,7 +2799,8 @@
 	} else if (rt2x00_rt(rt2x00dev, RT3572)) {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-	} else if (rt2x00_rt(rt2x00dev, RT5390)) {
+	} else if (rt2x00_rt(rt2x00dev, RT5390) ||
+			   rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@@ -3096,7 +3176,8 @@
 		     rt2800_wait_bbp_ready(rt2x00dev)))
 		return -EACCES;
 
-	if (rt2x00_rt(rt2x00dev, RT5390)) {
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_bbp_read(rt2x00dev, 4, &value);
 		rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1);
 		rt2800_bbp_write(rt2x00dev, 4, value);
@@ -3104,19 +3185,22 @@
 
 	if (rt2800_is_305x_soc(rt2x00dev) ||
 	    rt2x00_rt(rt2x00dev, RT3572) ||
-	    rt2x00_rt(rt2x00dev, RT5390))
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 31, 0x08);
 
 	rt2800_bbp_write(rt2x00dev, 65, 0x2c);
 	rt2800_bbp_write(rt2x00dev, 66, 0x38);
 
-	if (rt2x00_rt(rt2x00dev, RT5390))
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 68, 0x0b);
 
 	if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
 		rt2800_bbp_write(rt2x00dev, 69, 0x16);
 		rt2800_bbp_write(rt2x00dev, 73, 0x12);
-	} else if (rt2x00_rt(rt2x00dev, RT5390)) {
+	} else if (rt2x00_rt(rt2x00dev, RT5390) ||
+			   rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_bbp_write(rt2x00dev, 69, 0x12);
 		rt2800_bbp_write(rt2x00dev, 73, 0x13);
 		rt2800_bbp_write(rt2x00dev, 75, 0x46);
@@ -3134,7 +3218,8 @@
 	    rt2x00_rt(rt2x00dev, RT3090) ||
 	    rt2x00_rt(rt2x00dev, RT3390) ||
 	    rt2x00_rt(rt2x00dev, RT3572) ||
-	    rt2x00_rt(rt2x00dev, RT5390)) {
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_bbp_write(rt2x00dev, 79, 0x13);
 		rt2800_bbp_write(rt2x00dev, 80, 0x05);
 		rt2800_bbp_write(rt2x00dev, 81, 0x33);
@@ -3146,64 +3231,88 @@
 	}
 
 	rt2800_bbp_write(rt2x00dev, 82, 0x62);
-	if (rt2x00_rt(rt2x00dev, RT5390))
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 83, 0x7a);
 	else
 		rt2800_bbp_write(rt2x00dev, 83, 0x6a);
 
 	if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D))
 		rt2800_bbp_write(rt2x00dev, 84, 0x19);
-	else if (rt2x00_rt(rt2x00dev, RT5390))
+	else if (rt2x00_rt(rt2x00dev, RT5390) ||
+			 rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 84, 0x9a);
 	else
 		rt2800_bbp_write(rt2x00dev, 84, 0x99);
 
-	if (rt2x00_rt(rt2x00dev, RT5390))
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 86, 0x38);
 	else
 		rt2800_bbp_write(rt2x00dev, 86, 0x00);
 
+	if (rt2x00_rt(rt2x00dev, RT5392))
+		rt2800_bbp_write(rt2x00dev, 88, 0x90);
+
 	rt2800_bbp_write(rt2x00dev, 91, 0x04);
 
-	if (rt2x00_rt(rt2x00dev, RT5390))
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 92, 0x02);
 	else
 		rt2800_bbp_write(rt2x00dev, 92, 0x00);
 
+	if (rt2x00_rt(rt2x00dev, RT5392)) {
+		rt2800_bbp_write(rt2x00dev, 95, 0x9a);
+		rt2800_bbp_write(rt2x00dev, 98, 0x12);
+	}
+
 	if (rt2x00_rt_rev_gte(rt2x00dev, RT3070, REV_RT3070F) ||
 	    rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
 	    rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
 	    rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
 	    rt2x00_rt(rt2x00dev, RT3572) ||
 	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392) ||
 	    rt2800_is_305x_soc(rt2x00dev))
 		rt2800_bbp_write(rt2x00dev, 103, 0xc0);
 	else
 		rt2800_bbp_write(rt2x00dev, 103, 0x00);
 
-	if (rt2x00_rt(rt2x00dev, RT5390))
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 104, 0x92);
 
 	if (rt2800_is_305x_soc(rt2x00dev))
 		rt2800_bbp_write(rt2x00dev, 105, 0x01);
-	else if (rt2x00_rt(rt2x00dev, RT5390))
+	else if (rt2x00_rt(rt2x00dev, RT5390) ||
+			 rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 105, 0x3c);
 	else
 		rt2800_bbp_write(rt2x00dev, 105, 0x05);
 
 	if (rt2x00_rt(rt2x00dev, RT5390))
 		rt2800_bbp_write(rt2x00dev, 106, 0x03);
+	else if (rt2x00_rt(rt2x00dev, RT5392))
+		rt2800_bbp_write(rt2x00dev, 106, 0x12);
 	else
 		rt2800_bbp_write(rt2x00dev, 106, 0x35);
 
-	if (rt2x00_rt(rt2x00dev, RT5390))
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 128, 0x12);
 
+	if (rt2x00_rt(rt2x00dev, RT5392)) {
+		rt2800_bbp_write(rt2x00dev, 134, 0xd0);
+		rt2800_bbp_write(rt2x00dev, 135, 0xf6);
+	}
+
 	if (rt2x00_rt(rt2x00dev, RT3071) ||
 	    rt2x00_rt(rt2x00dev, RT3090) ||
 	    rt2x00_rt(rt2x00dev, RT3390) ||
 	    rt2x00_rt(rt2x00dev, RT3572) ||
-	    rt2x00_rt(rt2x00dev, RT5390)) {
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_bbp_read(rt2x00dev, 138, &value);
 
 		rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
@@ -3215,7 +3324,8 @@
 		rt2800_bbp_write(rt2x00dev, 138, value);
 	}
 
-	if (rt2x00_rt(rt2x00dev, RT5390)) {
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392)) {
 		int ant, div_mode;
 
 		rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
@@ -3342,13 +3452,15 @@
 	    !rt2x00_rt(rt2x00dev, RT3390) &&
 	    !rt2x00_rt(rt2x00dev, RT3572) &&
 	    !rt2x00_rt(rt2x00dev, RT5390) &&
+	    !rt2x00_rt(rt2x00dev, RT5392) &&
 	    !rt2800_is_305x_soc(rt2x00dev))
 		return 0;
 
 	/*
 	 * Init RF calibration.
 	 */
-	if (rt2x00_rt(rt2x00dev, RT5390)) {
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr);
 		rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1);
 		rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
@@ -3566,6 +3678,66 @@
 			rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
 		rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
 		rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+	}	else if (rt2x00_rt(rt2x00dev, RT5392)) {
+			rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
+			rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+			rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
+			rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+			rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
+			rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+			rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+			rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+			rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+			rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+			rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+			rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+			rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+			rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+			rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
+			rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+			rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
+			rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+			rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
+			rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
+			rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+			rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+			rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+			rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+			rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+			rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+			rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+			rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
+			rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
+			rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+			rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+			rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+			rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+			rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
+			rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+			rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
+			rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+			rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+			rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
+			rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+			rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+			rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+			rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
+			rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+			rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
+			rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
+			rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
+			rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
+			rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
+			rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
+			rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+			rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
+			rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
+			rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
+			rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
+			rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+			rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
+			rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
+			rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
 	}
 
 	if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
@@ -3639,7 +3811,8 @@
 	rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25);
 	rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26);
 
-	if (!rt2x00_rt(rt2x00dev, RT5390)) {
+	if (!rt2x00_rt(rt2x00dev, RT5390) &&
+		!rt2x00_rt(rt2x00dev, RT5392)) {
 		/*
 		 * Set back to initial state
 		 */
@@ -3667,7 +3840,8 @@
 	rt2x00_set_field32(&reg, OPT_14_CSR_BIT0, 1);
 	rt2800_register_write(rt2x00dev, OPT_14_CSR, reg);
 
-	if (!rt2x00_rt(rt2x00dev, RT5390)) {
+	if (!rt2x00_rt(rt2x00dev, RT5390) &&
+		!rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
 		rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0);
 		if (rt2x00_rt(rt2x00dev, RT3070) ||
@@ -3732,7 +3906,8 @@
 		rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
 	}
 
-	if (rt2x00_rt(rt2x00dev, RT5390)) {
+	if (rt2x00_rt(rt2x00dev, RT5390) ||
+		rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr);
 		rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0);
 		rt2800_rfcsr_write(rt2x00dev, 38, rfcsr);
@@ -4033,7 +4208,8 @@
 	 * RT53xx: defined in "EEPROM_CHIP_ID" field
 	 */
 	rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-	if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390)
+	if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 ||
+		rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392)
 		rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &value);
 	else
 		value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
@@ -4051,9 +4227,10 @@
 	case RT3390:
 	case RT3572:
 	case RT5390:
+	case RT5392:
 		break;
 	default:
-		ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+		ERROR(rt2x00dev, "Invalid RT chipset 0x%04x detected.\n", rt2x00dev->chip.rt);
 		return -ENODEV;
 	}
 
@@ -4069,10 +4246,11 @@
 	case RF3052:
 	case RF3320:
 	case RF5370:
+	case RF5372:
 	case RF5390:
 		break;
 	default:
-		ERROR(rt2x00dev, "Invalid RF chipset 0x%x detected.\n",
+		ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
 		      rt2x00dev->chip.rf);
 		return -ENODEV;
 	}
@@ -4375,6 +4553,7 @@
 		   rt2x00_rf(rt2x00dev, RF3022) ||
 		   rt2x00_rf(rt2x00dev, RF3320) ||
 		   rt2x00_rf(rt2x00dev, RF5370) ||
+		   rt2x00_rf(rt2x00dev, RF5372) ||
 		   rt2x00_rf(rt2x00dev, RF5390)) {
 		spec->num_channels = 14;
 		spec->channels = rf_vals_3x;
@@ -4451,6 +4630,20 @@
 		}
 	}
 
+	switch (rt2x00dev->chip.rf) {
+	case RF2020:
+	case RF3020:
+	case RF3021:
+	case RF3022:
+	case RF3320:
+	case RF3052:
+	case RF5370:
+	case RF5372:
+	case RF5390:
+		__set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags);
+		break;
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode);
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 8c3c281..419e36c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -184,6 +184,7 @@
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
 		       const u32 count);
 void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev);
+void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
 void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 6ad6929..9375db4 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -480,7 +480,8 @@
 
 	if (rt2x00_is_pcie(rt2x00dev) &&
 	    (rt2x00_rt(rt2x00dev, RT3572) ||
-	     rt2x00_rt(rt2x00dev, RT5390))) {
+	     rt2x00_rt(rt2x00dev, RT5390) ||
+	     rt2x00_rt(rt2x00dev, RT5392))) {
 		rt2x00pci_register_read(rt2x00dev, AUX_CTRL, &reg);
 		rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
 		rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
@@ -501,11 +502,27 @@
 
 static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
+	int retval;
+
 	if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
 		     rt2800pci_init_queues(rt2x00dev)))
 		return -EIO;
 
-	return rt2800_enable_radio(rt2x00dev);
+	retval = rt2800_enable_radio(rt2x00dev);
+	if (retval)
+		return retval;
+
+	/* After resume MCU_BOOT_SIGNAL will trash these. */
+	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+
+	rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, 0xff, 0x02);
+	rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF);
+
+	rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, 0, 0);
+	rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
+
+	return retval;
 }
 
 static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
@@ -521,14 +538,16 @@
 			       enum dev_state state)
 {
 	if (state == STATE_AWAKE) {
-		rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02);
-		rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
+		rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP,
+				   0, 0x02);
+		rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
 	} else if (state == STATE_SLEEP) {
 		rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
 					 0xffffffff);
 		rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID,
 					 0xffffffff);
-		rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01);
+		rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP,
+				   0xff, 0x01);
 	}
 
 	return 0;
@@ -541,13 +560,6 @@
 
 	switch (state) {
 	case STATE_RADIO_ON:
-		/*
-		 * Before the radio can be enabled, the device first has
-		 * to be woken up. After that it needs a bit of time
-		 * to be fully awake and then the radio can be enabled.
-		 */
-		rt2800pci_set_state(rt2x00dev, STATE_AWAKE);
-		msleep(1);
 		retval = rt2800pci_enable_radio(rt2x00dev);
 		break;
 	case STATE_RADIO_OFF:
@@ -1050,6 +1062,7 @@
 	.reset_tuner		= rt2800_reset_tuner,
 	.link_tuner		= rt2800_link_tuner,
 	.gain_calibration	= rt2800_gain_calibration,
+	.vco_calibration	= rt2800_vco_calibration,
 	.start_queue		= rt2800pci_start_queue,
 	.kick_queue		= rt2800pci_kick_queue,
 	.stop_queue		= rt2800pci_stop_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index d009b6b..2c11137 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -781,6 +781,7 @@
 	.reset_tuner		= rt2800_reset_tuner,
 	.link_tuner		= rt2800_link_tuner,
 	.gain_calibration	= rt2800_gain_calibration,
+	.vco_calibration	= rt2800_vco_calibration,
 	.watchdog		= rt2800usb_watchdog,
 	.start_queue		= rt2800usb_start_queue,
 	.kick_queue		= rt2x00usb_kick_queue,
@@ -921,6 +922,7 @@
 	{ USB_DEVICE(0x07d1, 0x3c13) },
 	{ USB_DEVICE(0x07d1, 0x3c15) },
 	{ USB_DEVICE(0x07d1, 0x3c16) },
+	{ USB_DEVICE(0x2001, 0x3c1b) },
 	/* Draytek */
 	{ USB_DEVICE(0x07fa, 0x7712) },
 	/* DVICO */
@@ -1100,12 +1102,26 @@
 	{ USB_DEVICE(0x5a57, 0x0284) },
 #endif
 #ifdef CONFIG_RT2800USB_RT53XX
+	/* Alpha */
+	{ USB_DEVICE(0x2001, 0x3c15) },
+	{ USB_DEVICE(0x2001, 0x3c19) },
+	/* Arcadyan */
+	{ USB_DEVICE(0x043e, 0x7a12) },
 	/* Azurewave */
 	{ USB_DEVICE(0x13d3, 0x3329) },
 	{ USB_DEVICE(0x13d3, 0x3365) },
+	/* LG innotek */
+	{ USB_DEVICE(0x043e, 0x7a22) },
+	/* Panasonic */
+	{ USB_DEVICE(0x04da, 0x1801) },
+	{ USB_DEVICE(0x04da, 0x1800) },
+	/* Philips */
+	{ USB_DEVICE(0x0471, 0x2104) },
 	/* Ralink */
 	{ USB_DEVICE(0x148f, 0x5370) },
 	{ USB_DEVICE(0x148f, 0x5372) },
+	/* Unknown */
+	{ USB_DEVICE(0x04da, 0x23f6) },
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
 	/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index ed2ae6e..65275ef 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -192,6 +192,7 @@
 #define RT3593		0x3593
 #define RT3883		0x3883	/* WSOC */
 #define RT5390		0x5390  /* 2.4GHz */
+#define RT5392		0x5392  /* 2.4GHz */
 
 	u16 rf;
 	u16 rev;
@@ -355,6 +356,11 @@
 	 * Work structure for scheduling periodic AGC adjustments.
 	 */
 	struct delayed_work agc_work;
+
+	/*
+	 * Work structure for scheduling periodic VCO calibration.
+	 */
+	struct delayed_work vco_work;
 };
 
 enum rt2x00_delayed_flags {
@@ -579,6 +585,7 @@
 	void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
 			    struct link_qual *qual, const u32 count);
 	void (*gain_calibration) (struct rt2x00_dev *rt2x00dev);
+	void (*vco_calibration) (struct rt2x00_dev *rt2x00dev);
 
 	/*
 	 * Data queue handlers.
@@ -722,6 +729,7 @@
 	CAPABILITY_EXTERNAL_LNA_BG,
 	CAPABILITY_DOUBLE_ANTENNA,
 	CAPABILITY_BT_COEXIST,
+	CAPABILITY_VCO_RECALIBRATION,
 };
 
 /*
@@ -978,6 +986,11 @@
 	struct tasklet_struct autowake_tasklet;
 
 	/*
+	 * Used for VCO periodic calibration.
+	 */
+	int rf_channel;
+
+	/*
 	 * Protect the interrupt mask register.
 	 */
 	spinlock_t irqmask_lock;
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index b704e5b..d7c0f86 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -232,6 +232,9 @@
 		memcpy(&libconf.channel,
 		       &rt2x00dev->spec.channels_info[hw_value],
 		       sizeof(libconf.channel));
+
+		/* Used for VCO periodic calibration */
+		rt2x00dev->rf_channel = libconf.rf.channel;
 	}
 
 	if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index d62e64f..49a51b4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -88,6 +88,8 @@
 	rt2x00queue_start_queues(rt2x00dev);
 	rt2x00link_start_tuner(rt2x00dev);
 	rt2x00link_start_agc(rt2x00dev);
+	if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+		rt2x00link_start_vcocal(rt2x00dev);
 
 	/*
 	 * Start watchdog monitoring.
@@ -111,6 +113,8 @@
 	 * Stop all queues
 	 */
 	rt2x00link_stop_agc(rt2x00dev);
+	if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+		rt2x00link_stop_vcocal(rt2x00dev);
 	rt2x00link_stop_tuner(rt2x00dev);
 	rt2x00queue_stop_queues(rt2x00dev);
 	rt2x00queue_flush_queues(rt2x00dev, true);
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 4cdf247..78bd43b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -33,6 +33,7 @@
 #define WATCHDOG_INTERVAL	round_jiffies_relative(HZ)
 #define LINK_TUNE_INTERVAL	round_jiffies_relative(HZ)
 #define AGC_INTERVAL		round_jiffies_relative(4 * HZ)
+#define VCO_INTERVAL		round_jiffies_relative(10 * HZ) /* 10 sec */
 
 /*
  * rt2x00_rate: Per rate device information
@@ -278,12 +279,24 @@
 void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev);
 
 /**
+ * rt2x00link_start_vcocal - Start periodic VCO calibration
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ */
+void rt2x00link_start_vcocal(struct rt2x00_dev *rt2x00dev);
+
+/**
  * rt2x00link_stop_agc - Stop periodic gain calibration
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  */
 void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev);
 
 /**
+ * rt2x00link_stop_vcocal - Stop periodic VCO calibration
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ */
+void rt2x00link_stop_vcocal(struct rt2x00_dev *rt2x00dev);
+
+/**
  * rt2x00link_register - Initialize link tuning & watchdog functionality
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  *
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index ea10b00..8368aab 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -447,11 +447,27 @@
 					     AGC_INTERVAL);
 }
 
+void rt2x00link_start_vcocal(struct rt2x00_dev *rt2x00dev)
+{
+	struct link *link = &rt2x00dev->link;
+
+	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+	    rt2x00dev->ops->lib->vco_calibration)
+		ieee80211_queue_delayed_work(rt2x00dev->hw,
+					     &link->vco_work,
+					     VCO_INTERVAL);
+}
+
 void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev)
 {
 	cancel_delayed_work_sync(&rt2x00dev->link.agc_work);
 }
 
+void rt2x00link_stop_vcocal(struct rt2x00_dev *rt2x00dev)
+{
+	cancel_delayed_work_sync(&rt2x00dev->link.vco_work);
+}
+
 static void rt2x00link_agc(struct work_struct *work)
 {
 	struct rt2x00_dev *rt2x00dev =
@@ -473,9 +489,32 @@
 					     AGC_INTERVAL);
 }
 
+static void rt2x00link_vcocal(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, link.vco_work.work);
+	struct link *link = &rt2x00dev->link;
+
+	/*
+	 * When the radio is shutting down we should
+	 * immediately cease the VCO calibration.
+	 */
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	rt2x00dev->ops->lib->vco_calibration(rt2x00dev);
+
+	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+		ieee80211_queue_delayed_work(rt2x00dev->hw,
+					     &link->vco_work,
+					     VCO_INTERVAL);
+}
+
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
 {
 	INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc);
+	if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+		INIT_DELAYED_WORK(&rt2x00dev->link.vco_work, rt2x00link_vcocal);
 	INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
 	INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
 }
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index 44b9c0a..cefac6a 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -50,7 +50,7 @@
 	default m
 
 config RTLWIFI_DEBUG
-	tristate "Additional debugging output"
+	bool "Additional debugging output"
 	depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE
 	default y
 
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index df5655c..5100235 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -39,10 +39,10 @@
 #include <linux/module.h>
 
 /*
- *NOTICE!!!: This file will be very big, we hsould
- *keep it clear under follwing roles:
+ *NOTICE!!!: This file will be very big, we should
+ *keep it clear under following roles:
  *
- *This file include follwing part, so, if you add new
+ *This file include following parts, so, if you add new
  *functions into this file, please check which part it
  *should includes. or check if you should add new part
  *for this file:
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
index bfff5fe..1eec3a0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
@@ -177,7 +177,7 @@
 	u32 i;
 
 	for (i = 0; i <= 31; i++) {
-		if (((bitmask >> i) & 0x1) == 1)
+		if ((bitmask >> i) & 0x1)
 			break;
 	}
 	return i;
@@ -253,121 +253,51 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	int index;
 
-	if (regaddr == RTXAGC_A_RATE18_06) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][0] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][0]);
-	}
-	if (regaddr == RTXAGC_A_RATE54_24) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][1] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][1]);
-	}
-	if (regaddr == RTXAGC_A_CCK1_MCS32) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][6] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][6]);
-	}
-	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][7] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][7]);
-	}
-	if (regaddr == RTXAGC_A_MCS03_MCS00) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][2] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][2]);
-	}
-	if (regaddr == RTXAGC_A_MCS07_MCS04) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][3] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][3]);
-	}
-	if (regaddr == RTXAGC_A_MCS11_MCS08) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][4] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][4]);
-	}
-	if (regaddr == RTXAGC_A_MCS15_MCS12) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][5] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][5]);
-	}
-	if (regaddr == RTXAGC_B_RATE18_06) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][8] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][8]);
-	}
-	if (regaddr == RTXAGC_B_RATE54_24) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9]);
-	}
-	if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14]);
-	}
-	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15]);
-	}
-	if (regaddr == RTXAGC_B_MCS03_MCS00) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10]);
-	}
-	if (regaddr == RTXAGC_B_MCS07_MCS04) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11]);
-	}
-	if (regaddr == RTXAGC_B_MCS11_MCS08) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12]);
-	}
-	if (regaddr == RTXAGC_B_MCS15_MCS12) {
-		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13]);
+	if (regaddr == RTXAGC_A_RATE18_06)
+		index = 0;
+	else if (regaddr == RTXAGC_A_RATE54_24)
+		index = 1;
+	else if (regaddr == RTXAGC_A_CCK1_MCS32)
+		index = 6;
+	else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00)
+		index = 7;
+	else if (regaddr == RTXAGC_A_MCS03_MCS00)
+		index = 2;
+	else if (regaddr == RTXAGC_A_MCS07_MCS04)
+		index = 3;
+	else if (regaddr == RTXAGC_A_MCS11_MCS08)
+		index = 4;
+	else if (regaddr == RTXAGC_A_MCS15_MCS12)
+		index = 5;
+	else if (regaddr == RTXAGC_B_RATE18_06)
+		index = 8;
+	else if (regaddr == RTXAGC_B_RATE54_24)
+		index = 9;
+	else if (regaddr == RTXAGC_B_CCK1_55_MCS32)
+		index = 14;
+	else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff)
+		index = 15;
+	else if (regaddr == RTXAGC_B_MCS03_MCS00)
+		index = 10;
+	else if (regaddr == RTXAGC_B_MCS07_MCS04)
+		index = 11;
+	else if (regaddr == RTXAGC_B_MCS11_MCS08)
+		index = 12;
+	else if (regaddr == RTXAGC_B_MCS15_MCS12)
+		index = 13;
+	else
+		return;
 
+	rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index] = data;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",
+		 rtlphy->pwrgroup_cnt, index,
+		 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index]);
+
+	if (index == 13)
 		rtlphy->pwrgroup_cnt++;
-	}
 }
 EXPORT_SYMBOL(_rtl92c_store_pwrIndex_diffrate_offset);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
index 93eecbd..34591eeb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
@@ -665,152 +665,51 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	int index;
 
-	if (regaddr == RTXAGC_A_RATE18_06) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][0]);
-	}
-	if (regaddr == RTXAGC_A_RATE54_24) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][1]);
-	}
-	if (regaddr == RTXAGC_A_CCK1_MCS32) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][6]);
-	}
-	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][7] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][7]);
-	}
-	if (regaddr == RTXAGC_A_MCS03_MCS00) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][2]);
-	}
-	if (regaddr == RTXAGC_A_MCS07_MCS04) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][3]);
-	}
-	if (regaddr == RTXAGC_A_MCS11_MCS08) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][4]);
-	}
-	if (regaddr == RTXAGC_A_MCS15_MCS12) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][5]);
-	}
-	if (regaddr == RTXAGC_B_RATE18_06) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][8] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][8]);
-	}
-	if (regaddr == RTXAGC_B_RATE54_24) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][9] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][9]);
-	}
-	if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][14] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][14]);
-	}
-	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][15] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][15]);
-	}
-	if (regaddr == RTXAGC_B_MCS03_MCS00) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][10] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][10]);
-	}
-	if (regaddr == RTXAGC_B_MCS07_MCS04) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][11] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][11]);
-	}
-	if (regaddr == RTXAGC_B_MCS11_MCS08) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][12] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][12]);
-	}
-	if (regaddr == RTXAGC_B_MCS15_MCS12) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][13] =
-									 data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%ulx\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_txpwrlevel_origoffset
-			 [rtlphy->pwrgroup_cnt][13]);
+	if (regaddr == RTXAGC_A_RATE18_06)
+		index = 0;
+	else if (regaddr == RTXAGC_A_RATE54_24)
+		index = 1;
+	else if (regaddr == RTXAGC_A_CCK1_MCS32)
+		index = 6;
+	else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00)
+		index = 7;
+	else if (regaddr == RTXAGC_A_MCS03_MCS00)
+		index = 2;
+	else if (regaddr == RTXAGC_A_MCS07_MCS04)
+		index = 3;
+	else if (regaddr == RTXAGC_A_MCS11_MCS08)
+		index = 4;
+	else if (regaddr == RTXAGC_A_MCS15_MCS12)
+		index = 5;
+	else if (regaddr == RTXAGC_B_RATE18_06)
+		index = 8;
+	else if (regaddr == RTXAGC_B_RATE54_24)
+		index = 9;
+	else if (regaddr == RTXAGC_B_CCK1_55_MCS32)
+		index = 14;
+	else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff)
+		index = 15;
+	else if (regaddr == RTXAGC_B_MCS03_MCS00)
+		index = 10;
+	else if (regaddr == RTXAGC_B_MCS07_MCS04)
+		index = 11;
+	else if (regaddr == RTXAGC_B_MCS11_MCS08)
+		index = 12;
+	else if (regaddr == RTXAGC_B_MCS15_MCS12)
+		index = 13;
+	else
+		return;
+
+	rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n",
+		 rtlphy->pwrgroup_cnt, index,
+		 rtlphy->mcs_txpwrlevel_origoffset
+		 [rtlphy->pwrgroup_cnt][index]);
+	if (index == 13)
 		rtlphy->pwrgroup_cnt++;
-	}
 }
 
 static bool _rtl92d_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
index babe85d..b4afff62 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
@@ -30,6 +30,7 @@
 #define __REALTEK_FIRMWARE92S_H__
 
 #define RTL8190_MAX_FIRMWARE_CODE_SIZE		64000
+#define RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE	90000
 #define RTL8190_CPU_START_OFFSET		0x80
 /* Firmware Local buffer size. 64k */
 #define	MAX_FIRMWARE_CODE_SIZE			0xFF00
@@ -217,7 +218,7 @@
 	u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE];
 	u32 fw_imem_len;
 	u32 fw_emem_len;
-	u8 sz_fw_tmpbuffer[164000];
+	u8 sz_fw_tmpbuffer[RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE];
 	u32 sz_fw_tmpbufferlen;
 	u16 cmdpacket_fragthresold;
 };
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
index 3bfc411..4a49992 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
@@ -677,30 +677,28 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	int index;
 
 	if (reg_addr == RTXAGC_RATE18_06)
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
-									 data;
-	if (reg_addr == RTXAGC_RATE54_24)
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
-									 data;
-	if (reg_addr == RTXAGC_CCK_MCS32)
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
-									 data;
-	if (reg_addr == RTXAGC_MCS03_MCS00)
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
-									 data;
-	if (reg_addr == RTXAGC_MCS07_MCS04)
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
-									 data;
-	if (reg_addr == RTXAGC_MCS11_MCS08)
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
-									 data;
-	if (reg_addr == RTXAGC_MCS15_MCS12) {
-		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
-									 data;
+		index = 0;
+	else if (reg_addr == RTXAGC_RATE54_24)
+		index = 1;
+	else if (reg_addr == RTXAGC_CCK_MCS32)
+		index = 6;
+	else if (reg_addr == RTXAGC_MCS03_MCS00)
+		index = 2;
+	else if (reg_addr == RTXAGC_MCS07_MCS04)
+		index = 3;
+	else if (reg_addr == RTXAGC_MCS11_MCS08)
+		index = 4;
+	else if (reg_addr == RTXAGC_MCS15_MCS12)
+		index = 5;
+	else
+		return;
+
+	rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data;
+	if (index == 5)
 		rtlphy->pwrgroup_cnt++;
-	}
 }
 
 static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
index eda30b9..f1b3600 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -108,6 +108,7 @@
 	if (firmware->size > rtlpriv->max_fw_size) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "Firmware is too big!\n");
+		rtlpriv->max_fw_size = 0;
 		release_firmware(firmware);
 		return;
 	}
@@ -229,7 +230,7 @@
 	if (!rtlpriv->rtlhal.pfirmware)
 		return 1;
 
-	rtlpriv->max_fw_size = sizeof(struct rt_firmware);
+	rtlpriv->max_fw_size = RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE;
 
 	pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n"
 		"Loading firmware %s\n", rtlpriv->cfg->fw_name);
diff --git a/drivers/net/wireless/wl1251/Makefile b/drivers/net/wireless/wl1251/Makefile
index 58b4f93..a5c6328 100644
--- a/drivers/net/wireless/wl1251/Makefile
+++ b/drivers/net/wireless/wl1251/Makefile
@@ -6,3 +6,5 @@
 obj-$(CONFIG_WL1251)		+= wl1251.o
 obj-$(CONFIG_WL1251_SPI)	+= wl1251_spi.o
 obj-$(CONFIG_WL1251_SDIO)	+= wl1251_sdio.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/wl1251/boot.c b/drivers/net/wireless/wl1251/boot.c
index d729daf..a2e5241 100644
--- a/drivers/net/wireless/wl1251/boot.c
+++ b/drivers/net/wireless/wl1251/boot.c
@@ -464,8 +464,6 @@
 		val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
 		       | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
 
-		val = cpu_to_le32(val);
-
 		wl1251_debug(DEBUG_BOOT,
 			     "nvs write table 0x%x: 0x%x",
 			     nvs_start, val);
diff --git a/drivers/net/wireless/wl1251/io.h b/drivers/net/wireless/wl1251/io.h
index c545e9d..d382877 100644
--- a/drivers/net/wireless/wl1251/io.h
+++ b/drivers/net/wireless/wl1251/io.h
@@ -36,16 +36,15 @@
 
 static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
 {
-	u32 response;
+	wl->if_ops->read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32));
 
-	wl->if_ops->read(wl, addr, &response, sizeof(u32));
-
-	return response;
+	return le32_to_cpu(wl->buffer_32);
 }
 
 static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
 {
-	wl->if_ops->write(wl, addr, &val, sizeof(u32));
+	wl->buffer_32 = cpu_to_le32(val);
+	wl->if_ops->write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32));
 }
 
 static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr)
diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h
index a77f1bb..9d8f581 100644
--- a/drivers/net/wireless/wl1251/wl1251.h
+++ b/drivers/net/wireless/wl1251/wl1251.h
@@ -380,7 +380,7 @@
 	struct wl1251_stats stats;
 	struct wl1251_debugfs debugfs;
 
-	u32 buffer_32;
+	__le32 buffer_32;
 	u32 buffer_cmd;
 	u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
 	struct wl1251_rx_descriptor *rx_descriptor;
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index fe67262..98f289c 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -11,3 +11,5 @@
 
 # small builtin driver bit
 obj-$(CONFIG_WL12XX_PLATFORM_DATA)	+= wl12xx_platform_data.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 7537c40..bc96db0 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -34,12 +34,14 @@
 #include "reg.h"
 #include "ps.h"
 
-int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+				  u8 wake_up_event, u8 listen_interval)
 {
 	struct acx_wake_up_condition *wake_up;
 	int ret;
 
-	wl1271_debug(DEBUG_ACX, "acx wake up conditions");
+	wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)",
+		     wake_up_event, listen_interval);
 
 	wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
 	if (!wake_up) {
@@ -48,8 +50,8 @@
 	}
 
 	wake_up->role_id = wlvif->role_id;
-	wake_up->wake_up_event = wl->conf.conn.wake_up_event;
-	wake_up->listen_interval = wl->conf.conn.listen_interval;
+	wake_up->wake_up_event = wake_up_event;
+	wake_up->listen_interval = listen_interval;
 
 	ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
 				   wake_up, sizeof(*wake_up));
@@ -1459,9 +1461,10 @@
 	return ret;
 }
 
-int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
+int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			u64 *mactime)
 {
-	struct wl1271_acx_fw_tsf_information *tsf_info;
+	struct wl12xx_acx_fw_tsf_information *tsf_info;
 	int ret;
 
 	tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
@@ -1470,6 +1473,8 @@
 		goto out;
 	}
 
+	tsf_info->role_id = wlvif->role_id;
+
 	ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO,
 				     tsf_info, sizeof(*tsf_info));
 	if (ret < 0) {
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 69892b4..a28fc04 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -995,15 +995,17 @@
 	u8 padding[2];
 } __packed;
 
-struct wl1271_acx_fw_tsf_information {
+struct wl12xx_acx_fw_tsf_information {
 	struct acx_header header;
 
+	u8 role_id;
+	u8 padding1[3];
 	__le32 current_tsf_high;
 	__le32 current_tsf_low;
 	__le32 last_bttt_high;
 	__le32 last_tbtt_low;
 	u8 last_dtim_count;
-	u8 padding[3];
+	u8 padding2[3];
 } __packed;
 
 struct wl1271_acx_ps_rx_streaming {
@@ -1151,79 +1153,81 @@
 } __packed;
 
 enum {
-	ACX_WAKE_UP_CONDITIONS      = 0x0002,
-	ACX_MEM_CFG                 = 0x0003,
-	ACX_SLOT                    = 0x0004,
-	ACX_AC_CFG                  = 0x0007,
-	ACX_MEM_MAP                 = 0x0008,
-	ACX_AID                     = 0x000A,
-	ACX_MEDIUM_USAGE            = 0x000F,
-	ACX_TX_QUEUE_CFG            = 0x0011, /* FIXME: only used by wl1251 */
-	ACX_STATISTICS              = 0x0013, /* Debug API */
-	ACX_PWR_CONSUMPTION_STATISTICS = 0x0014,
-	ACX_FEATURE_CFG             = 0x0015,
-	ACX_TID_CFG                 = 0x001A,
-	ACX_PS_RX_STREAMING         = 0x001B,
-	ACX_BEACON_FILTER_OPT       = 0x001F,
-	ACX_NOISE_HIST              = 0x0021,
-	ACX_HDK_VERSION             = 0x0022, /* ??? */
-	ACX_PD_THRESHOLD            = 0x0023,
-	ACX_TX_CONFIG_OPT           = 0x0024,
-	ACX_CCA_THRESHOLD           = 0x0025,
-	ACX_EVENT_MBOX_MASK         = 0x0026,
-	ACX_CONN_MONIT_PARAMS       = 0x002D,
-	ACX_BCN_DTIM_OPTIONS        = 0x0031,
-	ACX_SG_ENABLE               = 0x0032,
-	ACX_SG_CFG                  = 0x0033,
-	ACX_FM_COEX_CFG             = 0x0034,
-	ACX_BEACON_FILTER_TABLE     = 0x0038,
-	ACX_ARP_IP_FILTER           = 0x0039,
-	ACX_ROAMING_STATISTICS_TBL  = 0x003B,
-	ACX_RATE_POLICY             = 0x003D,
-	ACX_CTS_PROTECTION          = 0x003E,
-	ACX_SLEEP_AUTH              = 0x003F,
-	ACX_PREAMBLE_TYPE	    = 0x0040,
-	ACX_ERROR_CNT               = 0x0041,
-	ACX_IBSS_FILTER		    = 0x0044,
-	ACX_SERVICE_PERIOD_TIMEOUT  = 0x0045,
-	ACX_TSF_INFO                = 0x0046,
-	ACX_CONFIG_PS_WMM           = 0x0049,
-	ACX_ENABLE_RX_DATA_FILTER   = 0x004A,
-	ACX_SET_RX_DATA_FILTER      = 0x004B,
-	ACX_GET_DATA_FILTER_STATISTICS = 0x004C,
-	ACX_RX_CONFIG_OPT           = 0x004E,
-	ACX_FRAG_CFG                = 0x004F,
-	ACX_BET_ENABLE              = 0x0050,
-	ACX_RSSI_SNR_TRIGGER        = 0x0051,
-	ACX_RSSI_SNR_WEIGHTS        = 0x0052,
-	ACX_KEEP_ALIVE_MODE         = 0x0053,
-	ACX_SET_KEEP_ALIVE_CONFIG   = 0x0054,
-	ACX_BA_SESSION_INIT_POLICY  = 0x0055,
-	ACX_BA_SESSION_RX_SETUP     = 0x0056,
-	ACX_PEER_HT_CAP             = 0x0057,
-	ACX_HT_BSS_OPERATION        = 0x0058,
-	ACX_COEX_ACTIVITY           = 0x0059,
-	ACX_BURST_MODE              = 0x005C,
-	ACX_SET_RATE_MGMT_PARAMS    = 0x005D,
-	ACX_SET_RATE_ADAPT_PARAMS   = 0x0060,
-	ACX_SET_DCO_ITRIM_PARAMS    = 0x0061,
-	ACX_GEN_FW_CMD              = 0x0070,
-	ACX_HOST_IF_CFG_BITMAP      = 0x0071,
-	ACX_MAX_TX_FAILURE          = 0x0072,
-	ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073,
-	DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
-	DOT11_CUR_TX_PWR            = 0x100D,
-	DOT11_RX_DOT11_MODE         = 0x1012,
-	DOT11_RTS_THRESHOLD         = 0x1013,
-	DOT11_GROUP_ADDRESS_TBL     = 0x1014,
-	ACX_PM_CONFIG               = 0x1016,
-	ACX_CONFIG_PS               = 0x1017,
-	ACX_CONFIG_HANGOVER         = 0x1018,
+	ACX_WAKE_UP_CONDITIONS           = 0x0000,
+	ACX_MEM_CFG                      = 0x0001,
+	ACX_SLOT                         = 0x0002,
+	ACX_AC_CFG                       = 0x0003,
+	ACX_MEM_MAP                      = 0x0004,
+	ACX_AID                          = 0x0005,
+	ACX_MEDIUM_USAGE                 = 0x0006,
+	ACX_STATISTICS                   = 0x0007,
+	ACX_PWR_CONSUMPTION_STATISTICS   = 0x0008,
+	ACX_TID_CFG                      = 0x0009,
+	ACX_PS_RX_STREAMING              = 0x000A,
+	ACX_BEACON_FILTER_OPT            = 0x000B,
+	ACX_NOISE_HIST                   = 0x000C,
+	ACX_HDK_VERSION                  = 0x000D,
+	ACX_PD_THRESHOLD                 = 0x000E,
+	ACX_TX_CONFIG_OPT                = 0x000F,
+	ACX_CCA_THRESHOLD                = 0x0010,
+	ACX_EVENT_MBOX_MASK              = 0x0011,
+	ACX_CONN_MONIT_PARAMS            = 0x0012,
+	ACX_DISABLE_BROADCASTS           = 0x0013,
+	ACX_BCN_DTIM_OPTIONS             = 0x0014,
+	ACX_SG_ENABLE                    = 0x0015,
+	ACX_SG_CFG                       = 0x0016,
+	ACX_FM_COEX_CFG                  = 0x0017,
+	ACX_BEACON_FILTER_TABLE          = 0x0018,
+	ACX_ARP_IP_FILTER                = 0x0019,
+	ACX_ROAMING_STATISTICS_TBL       = 0x001A,
+	ACX_RATE_POLICY                  = 0x001B,
+	ACX_CTS_PROTECTION               = 0x001C,
+	ACX_SLEEP_AUTH                   = 0x001D,
+	ACX_PREAMBLE_TYPE                = 0x001E,
+	ACX_ERROR_CNT                    = 0x001F,
+	ACX_IBSS_FILTER                  = 0x0020,
+	ACX_SERVICE_PERIOD_TIMEOUT       = 0x0021,
+	ACX_TSF_INFO                     = 0x0022,
+	ACX_CONFIG_PS_WMM                = 0x0023,
+	ACX_ENABLE_RX_DATA_FILTER        = 0x0024,
+	ACX_SET_RX_DATA_FILTER           = 0x0025,
+	ACX_GET_DATA_FILTER_STATISTICS   = 0x0026,
+	ACX_RX_CONFIG_OPT                = 0x0027,
+	ACX_FRAG_CFG                     = 0x0028,
+	ACX_BET_ENABLE                   = 0x0029,
+	ACX_RSSI_SNR_TRIGGER             = 0x002A,
+	ACX_RSSI_SNR_WEIGHTS             = 0x002B,
+	ACX_KEEP_ALIVE_MODE              = 0x002C,
+	ACX_SET_KEEP_ALIVE_CONFIG        = 0x002D,
+	ACX_BA_SESSION_INIT_POLICY       = 0x002E,
+	ACX_BA_SESSION_RX_SETUP          = 0x002F,
+	ACX_PEER_HT_CAP                  = 0x0030,
+	ACX_HT_BSS_OPERATION             = 0x0031,
+	ACX_COEX_ACTIVITY                = 0x0032,
+	ACX_BURST_MODE                   = 0x0033,
+	ACX_SET_RATE_MGMT_PARAMS         = 0x0034,
+	ACX_GET_RATE_MGMT_PARAMS         = 0x0035,
+	ACX_SET_RATE_ADAPT_PARAMS        = 0x0036,
+	ACX_SET_DCO_ITRIM_PARAMS         = 0x0037,
+	ACX_GEN_FW_CMD                   = 0x0038,
+	ACX_HOST_IF_CFG_BITMAP           = 0x0039,
+	ACX_MAX_TX_FAILURE               = 0x003A,
+	ACX_UPDATE_INCONNECTION_STA_LIST = 0x003B,
+	DOT11_RX_MSDU_LIFE_TIME          = 0x003C,
+	DOT11_CUR_TX_PWR                 = 0x003D,
+	DOT11_RTS_THRESHOLD              = 0x003E,
+	DOT11_GROUP_ADDRESS_TBL          = 0x003F,
+	ACX_PM_CONFIG                    = 0x0040,
+	ACX_CONFIG_PS                    = 0x0041,
+	ACX_CONFIG_HANGOVER              = 0x0042,
+	ACX_FEATURE_CFG                  = 0x0043,
+	ACX_PROTECTION_CFG               = 0x0044,
 };
 
 
 int wl1271_acx_wake_up_conditions(struct wl1271 *wl,
-				  struct wl12xx_vif *wlvif);
+				  struct wl12xx_vif *wlvif,
+				  u8 wake_up_event, u8 listen_interval);
 int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
 int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			int power);
@@ -1296,7 +1300,8 @@
 				       struct wl12xx_vif *wlvif);
 int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
 				       u16 ssn, bool enable, u8 peer_hlid);
-int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
+int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			u64 *mactime);
 int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			       bool enable);
 int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 8f9cf5a..954101d 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -33,65 +33,6 @@
 #include "event.h"
 #include "rx.h"
 
-static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
-	[PART_DOWN] = {
-		.mem = {
-			.start = 0x00000000,
-			.size  = 0x000177c0
-		},
-		.reg = {
-			.start = REGISTERS_BASE,
-			.size  = 0x00008800
-		},
-		.mem2 = {
-			.start = 0x00000000,
-			.size  = 0x00000000
-		},
-		.mem3 = {
-			.start = 0x00000000,
-			.size  = 0x00000000
-		},
-	},
-
-	[PART_WORK] = {
-		.mem = {
-			.start = 0x00040000,
-			.size  = 0x00014fc0
-		},
-		.reg = {
-			.start = REGISTERS_BASE,
-			.size  = 0x0000a000
-		},
-		.mem2 = {
-			.start = 0x003004f8,
-			.size  = 0x00000004
-		},
-		.mem3 = {
-			.start = 0x00040404,
-			.size  = 0x00000000
-		},
-	},
-
-	[PART_DRPW] = {
-		.mem = {
-			.start = 0x00040000,
-			.size  = 0x00014fc0
-		},
-		.reg = {
-			.start = DRPW_BASE,
-			.size  = 0x00006000
-		},
-		.mem2 = {
-			.start = 0x00000000,
-			.size  = 0x00000000
-		},
-		.mem3 = {
-			.start = 0x00000000,
-			.size  = 0x00000000
-		}
-	}
-};
-
 static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
 {
 	u32 cpu_ctrl;
@@ -181,13 +122,13 @@
 		return -ENOMEM;
 	}
 
-	memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
+	memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition));
 	partition.mem.start = dest;
 	wl1271_set_partition(wl, &partition);
 
 	/* 10.1 set partition limit and chunk num */
 	chunk_num = 0;
-	partition_limit = part_table[PART_DOWN].mem.size;
+	partition_limit = wl12xx_part_table[PART_DOWN].mem.size;
 
 	while (chunk_num < fw_data_len / CHUNK_SIZE) {
 		/* 10.2 update partition, if needed */
@@ -195,7 +136,7 @@
 		if (addr > partition_limit) {
 			addr = dest + chunk_num * CHUNK_SIZE;
 			partition_limit = chunk_num * CHUNK_SIZE +
-				part_table[PART_DOWN].mem.size;
+				wl12xx_part_table[PART_DOWN].mem.size;
 			partition.mem.start = addr;
 			wl1271_set_partition(wl, &partition);
 		}
@@ -317,12 +258,12 @@
 	}
 
 	/* update current MAC address to NVS */
-	nvs_ptr[11] = wl->mac_addr[0];
-	nvs_ptr[10] = wl->mac_addr[1];
-	nvs_ptr[6] = wl->mac_addr[2];
-	nvs_ptr[5] = wl->mac_addr[3];
-	nvs_ptr[4] = wl->mac_addr[4];
-	nvs_ptr[3] = wl->mac_addr[5];
+	nvs_ptr[11] = wl->addresses[0].addr[0];
+	nvs_ptr[10] = wl->addresses[0].addr[1];
+	nvs_ptr[6] = wl->addresses[0].addr[2];
+	nvs_ptr[5] = wl->addresses[0].addr[3];
+	nvs_ptr[4] = wl->addresses[0].addr[4];
+	nvs_ptr[3] = wl->addresses[0].addr[5];
 
 	/*
 	 * Layout before the actual NVS tables:
@@ -383,7 +324,7 @@
 	nvs_len -= nvs_ptr - (u8 *)wl->nvs;
 
 	/* Now we must set the partition correctly */
-	wl1271_set_partition(wl, &part_table[PART_WORK]);
+	wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
 
 	/* Copy the NVS tables to a new block to ensure alignment */
 	nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
@@ -492,7 +433,7 @@
 	wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
 
 	/* set the working partition to its "running" mode offset */
-	wl1271_set_partition(wl, &part_table[PART_WORK]);
+	wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
 
 	wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
 		     wl->cmd_box_addr, wl->event_box_addr);
@@ -507,8 +448,7 @@
 	/* unmask required mbox events  */
 	wl->event_mask = BSS_LOSE_EVENT_ID |
 		SCAN_COMPLETE_EVENT_ID |
-		PS_REPORT_EVENT_ID |
-		DISCONNECT_EVENT_COMPLETE_ID |
+		ROLE_STOP_COMPLETE_EVENT_ID |
 		RSSI_SNR_TRIGGER_0_EVENT_ID |
 		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
 		SOFT_GEMINI_SENSE_EVENT_ID |
@@ -547,19 +487,6 @@
 	return 0;
 }
 
-static void wl1271_boot_hw_version(struct wl1271 *wl)
-{
-	u32 fuse;
-
-	if (wl->chip.id == CHIP_ID_1283_PG20)
-		fuse = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
-	else
-		fuse = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
-	fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET;
-
-	wl->hw_pg_ver = (s8)fuse;
-}
-
 static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
 {
 	u16 spare_reg;
@@ -698,7 +625,7 @@
 	u32 pause;
 	u32 clk;
 
-	if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3)
+	if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
 		wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
 
 	if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
@@ -753,8 +680,6 @@
 	u32 tmp, clk;
 	int selected_clock = -1;
 
-	wl1271_boot_hw_version(wl);
-
 	if (wl->chip.id == CHIP_ID_1283_PG20) {
 		ret = wl128x_boot_clk(wl, &selected_clock);
 		if (ret < 0)
@@ -769,7 +694,7 @@
 	wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
 	udelay(500);
 
-	wl1271_set_partition(wl, &part_table[PART_DRPW]);
+	wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
 
 	/* Read-modify-write DRPW_SCRATCH_START register (see next state)
 	   to be used by DRPw FW. The RTRIM value will be added by the FW
@@ -788,7 +713,7 @@
 
 	wl1271_write32(wl, DRPW_SCRATCH_START, clk);
 
-	wl1271_set_partition(wl, &part_table[PART_WORK]);
+	wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
 
 	/* Disable interrupts */
 	wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h
index 06dad93..c3adc09 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/boot.h
@@ -55,16 +55,6 @@
 #define OCP_REG_CLK_POLARITY 0x0cb2
 #define OCP_REG_CLK_PULL     0x0cb4
 
-#define WL127X_REG_FUSE_DATA_2_1    0x050a
-#define WL128X_REG_FUSE_DATA_2_1    0x2152
-#define PG_VER_MASK          0x3c
-#define PG_VER_OFFSET        2
-
-#define PG_MAJOR_VER_MASK    0x3
-#define PG_MAJOR_VER_OFFSET  0x0
-#define PG_MINOR_VER_MASK    0xc
-#define PG_MINOR_VER_OFFSET  0x2
-
 #define CMD_MBOX_ADDRESS     0x407B4
 
 #define POLARITY_LOW         BIT(1)
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 25990bd..b776d9d 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -566,7 +566,7 @@
 		goto out_free;
 	}
 
-	ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
+	ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID);
 	if (ret < 0) {
 		wl1271_error("cmd role stop dev event completion error");
 		goto out_free;
@@ -715,6 +715,8 @@
 	cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
 	cmd->ap.dtim_interval = bss_conf->dtim_period;
 	cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
+	/* FIXME: Change when adding DFS */
+	cmd->ap.reset_tsf = 1;  /* By default reset AP TSF */
 	cmd->channel = wlvif->channel;
 
 	if (!bss_conf->hidden_ssid) {
@@ -994,7 +996,7 @@
 }
 
 int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-		       u8 ps_mode)
+		       u8 ps_mode, u16 auto_ps_timeout)
 {
 	struct wl1271_cmd_ps_params *ps_params = NULL;
 	int ret = 0;
@@ -1009,6 +1011,7 @@
 
 	ps_params->role_id = wlvif->role_id;
 	ps_params->ps_mode = ps_mode;
+	ps_params->auto_ps_timeout = auto_ps_timeout;
 
 	ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
 			      sizeof(*ps_params), 0);
@@ -1022,13 +1025,15 @@
 	return ret;
 }
 
-int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
-			    void *buf, size_t buf_len, int index, u32 rates)
+int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id,
+			    u16 template_id, void *buf, size_t buf_len,
+			    int index, u32 rates)
 {
 	struct wl1271_cmd_template_set *cmd;
 	int ret = 0;
 
-	wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
+	wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)",
+		     template_id, role_id);
 
 	WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
 	buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
@@ -1039,6 +1044,8 @@
 		goto out;
 	}
 
+	/* during initialization wlvif is NULL */
+	cmd->role_id = role_id;
 	cmd->len = cpu_to_le16(buf_len);
 	cmd->template_type = template_id;
 	cmd->enabled_rates = cpu_to_le32(rates);
@@ -1082,7 +1089,8 @@
 		ptr = skb->data;
 	}
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+				      CMD_TEMPL_NULL_DATA, ptr, size, 0,
 				      wlvif->basic_rate);
 
 out:
@@ -1105,7 +1113,7 @@
 	if (!skb)
 		goto out;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV,
 				      skb->data, skb->len,
 				      CMD_TEMPL_KLV_IDX_NULL_DATA,
 				      wlvif->basic_rate);
@@ -1130,7 +1138,8 @@
 	if (!skb)
 		goto out;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+				      CMD_TEMPL_PS_POLL, skb->data,
 				      skb->len, 0, wlvif->basic_rate_set);
 
 out:
@@ -1138,9 +1147,10 @@
 	return ret;
 }
 
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			       u8 role_id, u8 band,
 			       const u8 *ssid, size_t ssid_len,
-			       const u8 *ie, size_t ie_len, u8 band)
+			       const u8 *ie, size_t ie_len)
 {
 	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
 	struct sk_buff *skb;
@@ -1158,10 +1168,12 @@
 
 	rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
 	if (band == IEEE80211_BAND_2GHZ)
-		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+		ret = wl1271_cmd_template_set(wl, role_id,
+					      CMD_TEMPL_CFG_PROBE_REQ_2_4,
 					      skb->data, skb->len, 0, rate);
 	else
-		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+		ret = wl1271_cmd_template_set(wl, role_id,
+					      CMD_TEMPL_CFG_PROBE_REQ_5,
 					      skb->data, skb->len, 0, rate);
 
 out:
@@ -1186,10 +1198,12 @@
 
 	rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
 	if (wlvif->band == IEEE80211_BAND_2GHZ)
-		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+		ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+					      CMD_TEMPL_CFG_PROBE_REQ_2_4,
 					      skb->data, skb->len, 0, rate);
 	else
-		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+		ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+					      CMD_TEMPL_CFG_PROBE_REQ_5,
 					      skb->data, skb->len, 0, rate);
 
 	if (ret < 0)
@@ -1199,32 +1213,34 @@
 	return skb;
 }
 
-int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-			     __be32 ip_addr)
+int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
-	int ret;
+	int ret, extra;
+	u16 fc;
 	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-	struct wl12xx_arp_rsp_template tmpl;
+	struct sk_buff *skb;
+	struct wl12xx_arp_rsp_template *tmpl;
 	struct ieee80211_hdr_3addr *hdr;
 	struct arphdr *arp_hdr;
 
-	memset(&tmpl, 0, sizeof(tmpl));
+	skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) +
+			    WL1271_EXTRA_SPACE_MAX);
+	if (!skb) {
+		wl1271_error("failed to allocate buffer for arp rsp template");
+		return -ENOMEM;
+	}
 
-	/* mac80211 header */
-	hdr = &tmpl.hdr;
-	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
-					 IEEE80211_STYPE_DATA |
-					 IEEE80211_FCTL_TODS);
-	memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
-	memcpy(hdr->addr2, vif->addr, ETH_ALEN);
-	memset(hdr->addr3, 0xff, ETH_ALEN);
+	skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX);
+
+	tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl));
+	memset(tmpl, 0, sizeof(tmpl));
 
 	/* llc layer */
-	memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
-	tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
+	memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
+	tmpl->llc_type = cpu_to_be16(ETH_P_ARP);
 
 	/* arp header */
-	arp_hdr = &tmpl.arp_hdr;
+	arp_hdr = &tmpl->arp_hdr;
 	arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
 	arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
 	arp_hdr->ar_hln = ETH_ALEN;
@@ -1232,13 +1248,59 @@
 	arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
 
 	/* arp payload */
-	memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN);
-	tmpl.sender_ip = ip_addr;
+	memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN);
+	tmpl->sender_ip = wlvif->ip_addr;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
-				      &tmpl, sizeof(tmpl), 0,
+	/* encryption space */
+	switch (wlvif->encryption_type) {
+	case KEY_TKIP:
+		extra = WL1271_EXTRA_SPACE_TKIP;
+		break;
+	case KEY_AES:
+		extra = WL1271_EXTRA_SPACE_AES;
+		break;
+	case KEY_NONE:
+	case KEY_WEP:
+	case KEY_GEM:
+		extra = 0;
+		break;
+	default:
+		wl1271_warning("Unknown encryption type: %d",
+			       wlvif->encryption_type);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (extra) {
+		u8 *space = skb_push(skb, extra);
+		memset(space, 0, extra);
+	}
+
+	/* QoS header - BE */
+	if (wlvif->sta.qos)
+		memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16));
+
+	/* mac80211 header */
+	hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr));
+	memset(hdr, 0, sizeof(hdr));
+	fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS;
+	if (wlvif->sta.qos)
+		fc |= IEEE80211_STYPE_QOS_DATA;
+	else
+		fc |= IEEE80211_STYPE_DATA;
+	if (wlvif->encryption_type != KEY_NONE)
+		fc |= IEEE80211_FCTL_PROTECTED;
+
+	hdr->frame_control = cpu_to_le16(fc);
+	memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
+	memcpy(hdr->addr2, vif->addr, ETH_ALEN);
+	memset(hdr->addr3, 0xff, ETH_ALEN);
+
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP,
+				      skb->data, skb->len, 0,
 				      wlvif->basic_rate);
-
+out:
+	dev_kfree_skb(skb);
 	return ret;
 }
 
@@ -1260,7 +1322,8 @@
 	/* FIXME: not sure what priority to use here */
 	template.qos_ctrl = cpu_to_le16(0);
 
-	return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
+	return wl1271_cmd_template_set(wl, wlvif->role_id,
+				       CMD_TEMPL_QOS_NULL_DATA, &template,
 				       sizeof(template), 0,
 				       wlvif->basic_rate);
 }
@@ -1744,6 +1807,7 @@
 }
 
 int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+			      struct wl12xx_vif *wlvif,
 			      struct ieee80211_channel_switch *ch_switch)
 {
 	struct wl12xx_cmd_channel_switch *cmd;
@@ -1757,10 +1821,13 @@
 		goto out;
 	}
 
+	cmd->role_id = wlvif->role_id;
 	cmd->channel = ch_switch->channel->hw_value;
 	cmd->switch_time = ch_switch->count;
-	cmd->tx_suspend = ch_switch->block_tx;
-	cmd->flush = 0; /* this value is ignored by the FW */
+	cmd->stop_tx = ch_switch->block_tx;
+
+	/* FIXME: control from mac80211 in the future */
+	cmd->post_switch_tx_disable = 0;  /* Enable TX on the target channel */
 
 	ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
 	if (ret < 0) {
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 3f7d0b9..de217d9 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -51,22 +51,23 @@
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
 int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-		       u8 ps_mode);
+		       u8 ps_mode, u16 auto_ps_timeout);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
 			   size_t len);
-int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
-			    void *buf, size_t buf_len, int index, u32 rates);
+int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id,
+			    u16 template_id, void *buf, size_t buf_len,
+			    int index, u32 rates);
 int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			     u16 aid);
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			       u8 role_id, u8 band,
 			       const u8 *ssid, size_t ssid_len,
-			       const u8 *ie, size_t ie_len, u8 band);
+			       const u8 *ie, size_t ie_len);
 struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
 					      struct wl12xx_vif *wlvif,
 					      struct sk_buff *skb);
-int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-			     __be32 ip_addr);
+int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif);
 int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
 				   struct wl12xx_vif *wlvif);
@@ -89,6 +90,7 @@
 int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
 int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
 int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+			      struct wl12xx_vif *wlvif,
 			      struct ieee80211_channel_switch *ch_switch);
 int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
 int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -96,62 +98,65 @@
 void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
 
 enum wl1271_commands {
-	CMD_INTERROGATE     = 1,    /*use this to read information elements*/
-	CMD_CONFIGURE       = 2,    /*use this to write information elements*/
-	CMD_ENABLE_RX       = 3,
-	CMD_ENABLE_TX       = 4,
-	CMD_DISABLE_RX      = 5,
-	CMD_DISABLE_TX      = 6,
-	CMD_SCAN            = 8,
-	CMD_STOP_SCAN       = 9,
-	CMD_SET_KEYS        = 12,
-	CMD_READ_MEMORY     = 13,
-	CMD_WRITE_MEMORY    = 14,
-	CMD_SET_TEMPLATE    = 19,
-	CMD_TEST            = 23,
-	CMD_NOISE_HIST      = 28,
-	CMD_QUIET_ELEMENT_SET_STATE  = 29,
-	CMD_SET_BCN_MODE    = 33,
-	CMD_MEASUREMENT      = 34,
-	CMD_STOP_MEASUREMENT = 35,
-	CMD_SET_PS_MODE      = 37,
-	CMD_CHANNEL_SWITCH   = 38,
-	CMD_STOP_CHANNEL_SWICTH = 39,
-	CMD_AP_DISCOVERY     = 40,
-	CMD_STOP_AP_DISCOVERY = 41,
-	CMD_HEALTH_CHECK     = 45,
-	CMD_DEBUG            = 46,
-	CMD_TRIGGER_SCAN_TO  = 47,
-	CMD_CONNECTION_SCAN_CFG      = 48,
-	CMD_CONNECTION_SCAN_SSID_CFG = 49,
-	CMD_START_PERIODIC_SCAN      = 50,
-	CMD_STOP_PERIODIC_SCAN       = 51,
-	CMD_SET_PEER_STATE           = 52,
-	CMD_REMAIN_ON_CHANNEL        = 53,
-	CMD_CANCEL_REMAIN_ON_CHANNEL = 54,
+	CMD_INTERROGATE	= 1, /* use this to read information elements */
+	CMD_CONFIGURE	= 2, /* use this to write information elements */
+	CMD_ENABLE_RX	= 3,
+	CMD_ENABLE_TX	= 4,
+	CMD_DISABLE_RX	= 5,
+	CMD_DISABLE_TX	= 6,
+	CMD_SCAN	= 7,
+	CMD_STOP_SCAN	= 8,
+	CMD_SET_KEYS	= 9,
+	CMD_READ_MEMORY	= 10,
+	CMD_WRITE_MEMORY	= 11,
+	CMD_SET_TEMPLATE	= 12,
+	CMD_TEST		= 13,
+	CMD_NOISE_HIST		= 14,
+	CMD_QUIET_ELEMENT_SET_STATE = 15,
+	CMD_SET_BCN_MODE	= 16,
 
-	CMD_CONFIG_FWLOGGER          = 55,
-	CMD_START_FWLOGGER           = 56,
-	CMD_STOP_FWLOGGER            = 57,
+	CMD_MEASUREMENT		= 17,
+	CMD_STOP_MEASUREMENT	= 18,
+	CMD_SET_PS_MODE		= 19,
+	CMD_CHANNEL_SWITCH	= 20,
+	CMD_STOP_CHANNEL_SWICTH = 21,
+	CMD_AP_DISCOVERY	= 22,
+	CMD_STOP_AP_DISCOVERY	= 23,
+	CMD_HEALTH_CHECK	= 24,
+	CMD_DEBUG		= 25,
+	CMD_TRIGGER_SCAN_TO	= 26,
+	CMD_CONNECTION_SCAN_CFG	= 27,
+	CMD_CONNECTION_SCAN_SSID_CFG	= 28,
+	CMD_START_PERIODIC_SCAN	= 29,
+	CMD_STOP_PERIODIC_SCAN	= 30,
+	CMD_SET_PEER_STATE	= 31,
+	CMD_REMAIN_ON_CHANNEL	= 32,
+	CMD_CANCEL_REMAIN_ON_CHANNEL	= 33,
+	CMD_CONFIG_FWLOGGER		= 34,
+	CMD_START_FWLOGGER			= 35,
+	CMD_STOP_FWLOGGER			= 36,
 
-	/* AP commands */
-	CMD_ADD_PEER                 = 62,
-	CMD_REMOVE_PEER              = 63,
+	/* Access point commands */
+	CMD_ADD_PEER		= 37,
+	CMD_REMOVE_PEER		= 38,
 
 	/* Role API */
-	CMD_ROLE_ENABLE              = 70,
-	CMD_ROLE_DISABLE             = 71,
-	CMD_ROLE_START               = 72,
-	CMD_ROLE_STOP                = 73,
+	CMD_ROLE_ENABLE		= 39,
+	CMD_ROLE_DISABLE	= 40,
+	CMD_ROLE_START		= 41,
+	CMD_ROLE_STOP		= 42,
+
+	/* DFS */
+	CMD_START_RADAR_DETECTION	= 43,
+	CMD_STOP_RADAR_DETECTION	= 44,
 
 	/* WIFI Direct */
-	CMD_WFD_START_DISCOVERY      = 80,
-	CMD_WFD_STOP_DISCOVERY	     = 81,
-	CMD_WFD_ATTRIBUTE_CONFIG     = 82,
+	CMD_WFD_START_DISCOVERY	= 45,
+	CMD_WFD_STOP_DISCOVERY	= 46,
+	CMD_WFD_ATTRIBUTE_CONFIG	= 47,
+	CMD_NOP			= 48,
+	CMD_LAST_COMMAND,
 
-	CMD_NOP                      = 100,
-
-	NUM_COMMANDS,
 	MAX_COMMAND_ID = 0xFFFF,
 };
 
@@ -191,7 +196,7 @@
 /* unit ms */
 #define WL1271_COMMAND_TIMEOUT     2000
 #define WL1271_CMD_TEMPL_DFLT_SIZE 252
-#define WL1271_CMD_TEMPL_MAX_SIZE  548
+#define WL1271_CMD_TEMPL_MAX_SIZE  512
 #define WL1271_EVENT_TIMEOUT       750
 
 struct wl1271_cmd_header {
@@ -339,7 +344,9 @@
 			u8 ssid_len;
 			u8 ssid[IEEE80211_MAX_SSID_LEN];
 
-			u8 padding_1[5];
+			u8 reset_tsf;
+
+			u8 padding_1[4];
 		} __packed ap;
 	};
 } __packed;
@@ -364,14 +371,18 @@
 struct wl1271_cmd_template_set {
 	struct wl1271_cmd_header header;
 
-	__le16 len;
+	u8 role_id;
 	u8 template_type;
+	__le16 len;
 	u8 index;  /* relevant only for KLV_TEMPLATE type */
+	u8 padding[3];
+
 	__le32 enabled_rates;
 	u8 short_retry_limit;
 	u8 long_retry_limit;
 	u8 aflags;
 	u8 reserved;
+
 	u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE];
 } __packed;
 
@@ -388,6 +399,7 @@
 } __packed;
 
 enum wl1271_cmd_ps_mode {
+	STATION_AUTO_PS_MODE,   /* Dynamic Power Save */
 	STATION_ACTIVE_MODE,
 	STATION_POWER_SAVE_MODE
 };
@@ -397,7 +409,7 @@
 
 	u8 role_id;
 	u8 ps_mode; /* STATION_* */
-	u8 padding[2];
+	u16 auto_ps_timeout;
 } __packed;
 
 /* HW encryption keys */
@@ -695,14 +707,18 @@
 struct wl12xx_cmd_channel_switch {
 	struct wl1271_cmd_header header;
 
+	u8 role_id;
+
 	/* The new serving channel */
 	u8 channel;
 	/* Relative time of the serving channel switch in TBTT units */
 	u8 switch_time;
-	/* 1: Suspend TX till switch time; 0: Do not suspend TX */
-	u8 tx_suspend;
-	/* 1: Flush TX at switch time; 0: Do not flush */
-	u8 flush;
+	/* Stop the role TX, should expect it after radar detection */
+	u8 stop_tx;
+	/* The target channel tx status 1-stopped 0-open*/
+	u8 post_switch_tx_disable;
+
+	u8 padding[3];
 } __packed;
 
 struct wl12xx_cmd_stop_channel_switch {
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 1bcfb01..cc50faa 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -66,7 +66,8 @@
 };
 
 enum {
-	CONF_HW_RXTX_RATE_MCS7 = 0,
+	CONF_HW_RXTX_RATE_MCS7_SGI = 0,
+	CONF_HW_RXTX_RATE_MCS7,
 	CONF_HW_RXTX_RATE_MCS6,
 	CONF_HW_RXTX_RATE_MCS5,
 	CONF_HW_RXTX_RATE_MCS4,
@@ -91,6 +92,10 @@
 	CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
 };
 
+/* Rates between and including these are MCS rates */
+#define CONF_HW_RXTX_RATE_MCS_MIN CONF_HW_RXTX_RATE_MCS7_SGI
+#define CONF_HW_RXTX_RATE_MCS_MAX CONF_HW_RXTX_RATE_MCS0
+
 enum {
 	CONF_SG_DISABLE = 0,
 	CONF_SG_PROTECTIVE,
@@ -312,6 +317,10 @@
 	CONF_AP_BT_ACL_VAL_BT_SERVE_TIME,
 	CONF_AP_BT_ACL_VAL_WL_SERVE_TIME,
 
+	/* CTS Diluting params */
+	CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH,
+	CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER,
+
 	CONF_SG_TEMP_PARAM_1,
 	CONF_SG_TEMP_PARAM_2,
 	CONF_SG_TEMP_PARAM_3,
@@ -810,6 +819,19 @@
 	u8 listen_interval;
 
 	/*
+	 * Firmware wakeup conditions during suspend
+	 * Range: CONF_WAKE_UP_EVENT_*
+	 */
+	u8 suspend_wake_up_event;
+
+	/*
+	 * Listen interval during suspend.
+	 * Currently will be in DTIMs (1-10)
+	 *
+	 */
+	u8 suspend_listen_interval;
+
+	/*
 	 * Enable or disable the beacon filtering.
 	 *
 	 * Range: CONF_BCN_FILT_MODE_*
@@ -868,13 +890,6 @@
 	u8 ps_poll_threshold;
 
 	/*
-	 * PS Poll failure recovery ACTIVE period length
-	 *
-	 * Range: u32 (ms)
-	 */
-	u32 ps_poll_recovery_period;
-
-	/*
 	 * Configuration of signal average weights.
 	 */
 	struct conf_sig_weights sig_weights;
@@ -922,6 +937,18 @@
 	u8 psm_entry_nullfunc_retries;
 
 	/*
+	 * Specifies the dynamic PS timeout in ms that will be used
+	 * by the FW when in AUTO_PS mode
+	 */
+	u16 dynamic_ps_timeout;
+
+	/*
+	 * Specifies whether dynamic PS should be disabled and PSM forced.
+	 * This is required for certain WiFi certification tests.
+	 */
+	u8 forced_ps;
+
+	/*
 	 *
 	 * Specifies the interval of the connection keep-alive null-func
 	 * frame in ms.
@@ -1055,6 +1082,14 @@
 	 */
 	u16 num_probe_reqs;
 
+	/*
+	 * Scan trigger (split scan) timeout. The FW will split the scan
+	 * operation into slices of the given time and allow the FW to schedule
+	 * other tasks in between.
+	 *
+	 * Range: u32 Microsecs
+	 */
+	u32 split_scan_timeout;
 };
 
 struct conf_sched_scan_settings {
diff --git a/drivers/net/wireless/wl12xx/debug.h b/drivers/net/wireless/wl12xx/debug.h
index b85fd8c4..ec0fdc2 100644
--- a/drivers/net/wireless/wl12xx/debug.h
+++ b/drivers/net/wireless/wl12xx/debug.h
@@ -51,6 +51,7 @@
 	DEBUG_FILTERS   = BIT(15),
 	DEBUG_ADHOC     = BIT(16),
 	DEBUG_AP	= BIT(17),
+	DEBUG_PROBE	= BIT(18),
 	DEBUG_MASTER	= (DEBUG_ADHOC | DEBUG_AP),
 	DEBUG_ALL	= ~0,
 };
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 15eb3a9..e1cf727 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -113,7 +113,7 @@
 	if (ret < 0)
 		goto out;
 
-	if (wl->state == WL1271_STATE_ON &&
+	if (wl->state == WL1271_STATE_ON && !wl->plt &&
 	    time_after(jiffies, wl->stats.fw_stats_update +
 		       msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
 		wl1271_acx_statistics(wl, wl->stats.fw_stats);
@@ -312,6 +312,181 @@
 	.llseek = default_llseek,
 };
 
+static ssize_t dynamic_ps_timeout_read(struct file *file, char __user *user_buf,
+			  size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+
+	return wl1271_format_buffer(user_buf, count,
+				    ppos, "%d\n",
+				    wl->conf.conn.dynamic_ps_timeout);
+}
+
+static ssize_t dynamic_ps_timeout_write(struct file *file,
+				    const char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	struct wl12xx_vif *wlvif;
+	unsigned long value;
+	int ret;
+
+	ret = kstrtoul_from_user(user_buf, count, 10, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in dynamic_ps");
+		return -EINVAL;
+	}
+
+	if (value < 1 || value > 65535) {
+		wl1271_warning("dyanmic_ps_timeout is not in valid range");
+		return -ERANGE;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	wl->conf.conn.dynamic_ps_timeout = value;
+
+	if (wl->state == WL1271_STATE_OFF)
+		goto out;
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	/* In case we're already in PSM, trigger it again to set new timeout
+	 * immediately without waiting for re-association
+	 */
+
+	wl12xx_for_each_wlvif_sta(wl, wlvif) {
+		if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
+			wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE);
+	}
+
+	wl1271_ps_elp_sleep(wl);
+
+out:
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static const struct file_operations dynamic_ps_timeout_ops = {
+	.read = dynamic_ps_timeout_read,
+	.write = dynamic_ps_timeout_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
+static ssize_t forced_ps_read(struct file *file, char __user *user_buf,
+			  size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+
+	return wl1271_format_buffer(user_buf, count,
+				    ppos, "%d\n",
+				    wl->conf.conn.forced_ps);
+}
+
+static ssize_t forced_ps_write(struct file *file,
+				    const char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	struct wl12xx_vif *wlvif;
+	unsigned long value;
+	int ret, ps_mode;
+
+	ret = kstrtoul_from_user(user_buf, count, 10, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in forced_ps");
+		return -EINVAL;
+	}
+
+	if (value != 1 && value != 0) {
+		wl1271_warning("forced_ps should be either 0 or 1");
+		return -ERANGE;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	if (wl->conf.conn.forced_ps == value)
+		goto out;
+
+	wl->conf.conn.forced_ps = value;
+
+	if (wl->state == WL1271_STATE_OFF)
+		goto out;
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	/* In case we're already in PSM, trigger it again to switch mode
+	 * immediately without waiting for re-association
+	 */
+
+	ps_mode = value ? STATION_POWER_SAVE_MODE : STATION_AUTO_PS_MODE;
+
+	wl12xx_for_each_wlvif_sta(wl, wlvif) {
+		if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
+			wl1271_ps_set_mode(wl, wlvif, ps_mode);
+	}
+
+	wl1271_ps_elp_sleep(wl);
+
+out:
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static const struct file_operations forced_ps_ops = {
+	.read = forced_ps_read,
+	.write = forced_ps_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
+static ssize_t split_scan_timeout_read(struct file *file, char __user *user_buf,
+			  size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+
+	return wl1271_format_buffer(user_buf, count,
+				    ppos, "%d\n",
+				    wl->conf.scan.split_scan_timeout / 1000);
+}
+
+static ssize_t split_scan_timeout_write(struct file *file,
+				    const char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	unsigned long value;
+	int ret;
+
+	ret = kstrtoul_from_user(user_buf, count, 10, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in split_scan_timeout");
+		return -EINVAL;
+	}
+
+	if (value == 0)
+		wl1271_info("split scan will be disabled");
+
+	mutex_lock(&wl->mutex);
+
+	wl->conf.scan.split_scan_timeout = value * 1000;
+
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static const struct file_operations split_scan_timeout_ops = {
+	.read = split_scan_timeout_read,
+	.write = split_scan_timeout_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
 static ssize_t driver_state_read(struct file *file, char __user *user_buf,
 				 size_t count, loff_t *ppos)
 {
@@ -446,6 +621,7 @@
 			VIF_STATE_PRINT_INT(sta.basic_rate_idx);
 			VIF_STATE_PRINT_INT(sta.ap_rate_idx);
 			VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
+			VIF_STATE_PRINT_INT(sta.qos);
 		} else {
 			VIF_STATE_PRINT_INT(ap.global_hlid);
 			VIF_STATE_PRINT_INT(ap.bcast_hlid);
@@ -471,7 +647,6 @@
 		VIF_STATE_PRINT_INT(default_key);
 		VIF_STATE_PRINT_INT(aid);
 		VIF_STATE_PRINT_INT(session_counter);
-		VIF_STATE_PRINT_INT(ps_poll_failures);
 		VIF_STATE_PRINT_INT(psm_entry_retry);
 		VIF_STATE_PRINT_INT(power_level);
 		VIF_STATE_PRINT_INT(rssi_thold);
@@ -562,6 +737,64 @@
 	.llseek = default_llseek,
 };
 
+
+
+static ssize_t suspend_dtim_interval_read(struct file *file,
+					  char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	u8 value;
+
+	if (wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
+	    wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
+		value = wl->conf.conn.suspend_listen_interval;
+	else
+		value = 0;
+
+	return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
+}
+
+static ssize_t suspend_dtim_interval_write(struct file *file,
+					   const char __user *user_buf,
+					   size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	unsigned long value;
+	int ret;
+
+	ret = kstrtoul_from_user(user_buf, count, 10, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value for suspend_dtim_interval");
+		return -EINVAL;
+	}
+
+	if (value < 1 || value > 10) {
+		wl1271_warning("suspend_dtim value is not in valid range");
+		return -ERANGE;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	wl->conf.conn.suspend_listen_interval = value;
+	/* for some reason there are different event types for 1 and >1 */
+	if (value == 1)
+		wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
+	else
+		wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
+
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+
+static const struct file_operations suspend_dtim_interval_ops = {
+	.read = suspend_dtim_interval_read,
+	.write = suspend_dtim_interval_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
 static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
 				    size_t count, loff_t *ppos)
 {
@@ -886,8 +1119,12 @@
 	DEBUGFS_ADD(driver_state, rootdir);
 	DEBUGFS_ADD(vifs_state, rootdir);
 	DEBUGFS_ADD(dtim_interval, rootdir);
+	DEBUGFS_ADD(suspend_dtim_interval, rootdir);
 	DEBUGFS_ADD(beacon_interval, rootdir);
 	DEBUGFS_ADD(beacon_filtering, rootdir);
+	DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
+	DEBUGFS_ADD(forced_ps, rootdir);
+	DEBUGFS_ADD(split_scan_timeout, rootdir);
 
 	streaming = debugfs_create_dir("rx_streaming", rootdir);
 	if (!streaming || IS_ERR(streaming))
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index d3280df68..c953717 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -30,133 +30,6 @@
 #include "scan.h"
 #include "wl12xx_80211.h"
 
-void wl1271_pspoll_work(struct work_struct *work)
-{
-	struct ieee80211_vif *vif;
-	struct wl12xx_vif *wlvif;
-	struct delayed_work *dwork;
-	struct wl1271 *wl;
-	int ret;
-
-	dwork = container_of(work, struct delayed_work, work);
-	wlvif = container_of(dwork, struct wl12xx_vif, pspoll_work);
-	vif = container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
-	wl = wlvif->wl;
-
-	wl1271_debug(DEBUG_EVENT, "pspoll work");
-
-	mutex_lock(&wl->mutex);
-
-	if (unlikely(wl->state == WL1271_STATE_OFF))
-		goto out;
-
-	if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags))
-		goto out;
-
-	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-		goto out;
-
-	/*
-	 * if we end up here, then we were in powersave when the pspoll
-	 * delivery failure occurred, and no-one changed state since, so
-	 * we should go back to powersave.
-	 */
-	ret = wl1271_ps_elp_wakeup(wl);
-	if (ret < 0)
-		goto out;
-
-	wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
-			   wlvif->basic_rate, true);
-
-	wl1271_ps_elp_sleep(wl);
-out:
-	mutex_unlock(&wl->mutex);
-};
-
-static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl,
-					      struct wl12xx_vif *wlvif)
-{
-	int delay = wl->conf.conn.ps_poll_recovery_period;
-	int ret;
-
-	wlvif->ps_poll_failures++;
-	if (wlvif->ps_poll_failures == 1)
-		wl1271_info("AP with dysfunctional ps-poll, "
-			    "trying to work around it.");
-
-	/* force active mode receive data from the AP */
-	if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
-		ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
-					 wlvif->basic_rate, true);
-		if (ret < 0)
-			return;
-		set_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
-		ieee80211_queue_delayed_work(wl->hw, &wlvif->pspoll_work,
-					     msecs_to_jiffies(delay));
-	}
-
-	/*
-	 * If already in active mode, lets we should be getting data from
-	 * the AP right away. If we enter PSM too fast after this, and data
-	 * remains on the AP, we will get another event like this, and we'll
-	 * go into active once more.
-	 */
-}
-
-static int wl1271_event_ps_report(struct wl1271 *wl,
-				  struct wl12xx_vif *wlvif,
-				  struct event_mailbox *mbox,
-				  bool *beacon_loss)
-{
-	int ret = 0;
-	u32 total_retries = wl->conf.conn.psm_entry_retries;
-
-	wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
-
-	switch (mbox->ps_status) {
-	case EVENT_ENTER_POWER_SAVE_FAIL:
-		wl1271_debug(DEBUG_PSM, "PSM entry failed");
-
-		if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
-			/* remain in active mode */
-			wlvif->psm_entry_retry = 0;
-			break;
-		}
-
-		if (wlvif->psm_entry_retry < total_retries) {
-			wlvif->psm_entry_retry++;
-			ret = wl1271_ps_set_mode(wl, wlvif,
-						 STATION_POWER_SAVE_MODE,
-						 wlvif->basic_rate, true);
-		} else {
-			wl1271_info("No ack to nullfunc from AP.");
-			wlvif->psm_entry_retry = 0;
-			*beacon_loss = true;
-		}
-		break;
-	case EVENT_ENTER_POWER_SAVE_SUCCESS:
-		wlvif->psm_entry_retry = 0;
-
-		/*
-		 * BET has only a minor effect in 5GHz and masks
-		 * channel switch IEs, so we only enable BET on 2.4GHz
-		*/
-		if (wlvif->band == IEEE80211_BAND_2GHZ)
-			/* enable beacon early termination */
-			ret = wl1271_acx_bet_enable(wl, wlvif, true);
-
-		if (wlvif->ps_compl) {
-			complete(wlvif->ps_compl);
-			wlvif->ps_compl = NULL;
-		}
-		break;
-	default:
-		break;
-	}
-
-	return ret;
-}
-
 static void wl1271_event_rssi_trigger(struct wl1271 *wl,
 				      struct wl12xx_vif *wlvif,
 				      struct event_mailbox *mbox)
@@ -205,21 +78,13 @@
 static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
 					       u8 enable)
 {
-	struct ieee80211_vif *vif;
 	struct wl12xx_vif *wlvif;
 
 	if (enable) {
-		/* disable dynamic PS when requested by the firmware */
-		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			vif = wl12xx_wlvif_to_vif(wlvif);
-			ieee80211_disable_dyn_ps(vif);
-		}
 		set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
 	} else {
 		clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
 		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			vif = wl12xx_wlvif_to_vif(wlvif);
-			ieee80211_enable_dyn_ps(vif);
 			wl1271_recalc_rx_streaming(wl, wlvif);
 		}
 	}
@@ -237,7 +102,6 @@
 {
 	struct ieee80211_vif *vif;
 	struct wl12xx_vif *wlvif;
-	int ret;
 	u32 vector;
 	bool beacon_loss = false;
 	bool disconnect_sta = false;
@@ -293,21 +157,6 @@
 		beacon_loss = true;
 	}
 
-	if (vector & PS_REPORT_EVENT_ID) {
-		wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
-		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			ret = wl1271_event_ps_report(wl, wlvif,
-						     mbox, &beacon_loss);
-			if (ret < 0)
-				return ret;
-		}
-	}
-
-	if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
-		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			wl1271_event_pspoll_delivery_fail(wl, wlvif);
-		}
-
 	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
 		/* TODO: check actual multi-role support */
 		wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
@@ -344,7 +193,6 @@
 
 		/* TODO: configure only the relevant vif */
 		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
 			bool success;
 
 			if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
@@ -352,6 +200,8 @@
 				continue;
 
 			success = mbox->channel_switch_status ? false : true;
+			vif = wl12xx_wlvif_to_vif(wlvif);
+
 			ieee80211_chswitch_done(vif, success);
 		}
 	}
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index 1d878ba..057d193 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -51,10 +51,10 @@
 	SCAN_COMPLETE_EVENT_ID			 = BIT(10),
 	WFD_DISCOVERY_COMPLETE_EVENT_ID		 = BIT(11),
 	AP_DISCOVERY_COMPLETE_EVENT_ID		 = BIT(12),
-	PS_REPORT_EVENT_ID			 = BIT(13),
+	RESERVED1			         = BIT(13),
 	PSPOLL_DELIVERY_FAILURE_EVENT_ID	 = BIT(14),
-	DISCONNECT_EVENT_COMPLETE_ID		 = BIT(15),
-	/* BIT(16) is reserved */
+	ROLE_STOP_COMPLETE_EVENT_ID		 = BIT(15),
+	RADAR_DETECTED_EVENT_ID                  = BIT(16),
 	CHANNEL_SWITCH_COMPLETE_EVENT_ID	 = BIT(17),
 	BSS_LOSE_EVENT_ID			 = BIT(18),
 	REGAINED_BSS_EVENT_ID			 = BIT(19),
@@ -94,9 +94,9 @@
 	u8 soft_gemini_sense_info;
 	u8 soft_gemini_protective_info;
 	s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
-	u8 channel_switch_status;
+	u8 change_auto_mode_timeout;
 	u8 scheduled_scan_status;
-	u8 ps_status;
+	u8 reserved4;
 	/* tuned channel (roc) */
 	u8 roc_channel;
 
@@ -119,17 +119,21 @@
 	u8 rx_ba_allowed;
 	u8 reserved_6[2];
 
+	/* Channel switch results */
+
+	u8 channel_switch_role_id;
+	u8 channel_switch_status;
+	u8 reserved_7[2];
+
 	u8 ps_poll_delivery_failure_role_ids;
 	u8 stopped_role_ids;
 	u8 started_role_ids;
-	u8 change_auto_mode_timeout;
 
-	u8 reserved_7[12];
+	u8 reserved_8[9];
 } __packed;
 
 int wl1271_event_unmask(struct wl1271 *wl);
 void wl1271_event_mbox_config(struct wl1271 *wl);
 int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
-void wl1271_pspoll_work(struct work_struct *work);
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index ca7ee59..203fbeb 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -37,54 +37,64 @@
 int wl1271_init_templates_config(struct wl1271 *wl)
 {
 	int ret, i;
+	size_t max_size;
 
 	/* send empty templates for fw memory reservation */
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
-				      WL1271_CMD_TEMPL_DFLT_SIZE,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
+				      WL1271_CMD_TEMPL_MAX_SIZE,
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-				      NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_CFG_PROBE_REQ_5,
+				      NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
 				      WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_NULL_DATA, NULL,
 				      sizeof(struct wl12xx_null_data_template),
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_PS_POLL, NULL,
 				      sizeof(struct wl12xx_ps_poll_template),
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_QOS_NULL_DATA, NULL,
 				      sizeof
 				      (struct ieee80211_qos_hdr),
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_PROBE_RESPONSE, NULL,
 				      WL1271_CMD_TEMPL_DFLT_SIZE,
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_BEACON, NULL,
 				      WL1271_CMD_TEMPL_DFLT_SIZE,
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
-				      sizeof
-				      (struct wl12xx_arp_rsp_template),
+	max_size = sizeof(struct wl12xx_arp_rsp_template) +
+		   WL1271_EXTRA_SPACE_MAX;
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_ARP_RSP, NULL,
+				      max_size,
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
@@ -93,19 +103,22 @@
 	 * Put very large empty placeholders for all templates. These
 	 * reserve memory for later.
 	 */
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
 				      WL1271_CMD_TEMPL_MAX_SIZE,
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_AP_BEACON, NULL,
 				      WL1271_CMD_TEMPL_MAX_SIZE,
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL,
+	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+				      CMD_TEMPL_DEAUTH_AP, NULL,
 				      sizeof
 				      (struct wl12xx_disconn_template),
 				      0, WL1271_RATE_AUTOMATIC);
@@ -113,7 +126,8 @@
 		return ret;
 
 	for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
-		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
+		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+					      CMD_TEMPL_KLV, NULL,
 					      sizeof(struct ieee80211_qos_hdr),
 					      i, WL1271_RATE_AUTOMATIC);
 		if (ret < 0)
@@ -140,7 +154,8 @@
 					     IEEE80211_STYPE_DEAUTH);
 
 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+				      CMD_TEMPL_DEAUTH_AP,
 				      tmpl, sizeof(*tmpl), 0, rate);
 
 out:
@@ -172,7 +187,8 @@
 	memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
 
 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+				      CMD_TEMPL_NULL_DATA, nullfunc,
 				      sizeof(*nullfunc), 0, rate);
 
 out:
@@ -204,7 +220,8 @@
 	memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
 
 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+				      CMD_TEMPL_QOS_NULL_DATA, qosnull,
 				      sizeof(*qosnull), 0, rate);
 
 out:
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c
index 079ad38..c574a3b 100644
--- a/drivers/net/wireless/wl12xx/io.c
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -45,6 +45,65 @@
 #define OCP_STATUS_REQ_FAILED 0x20000
 #define OCP_STATUS_RESP_ERROR 0x30000
 
+struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN] = {
+	[PART_DOWN] = {
+		.mem = {
+			.start = 0x00000000,
+			.size  = 0x000177c0
+		},
+		.reg = {
+			.start = REGISTERS_BASE,
+			.size  = 0x00008800
+		},
+		.mem2 = {
+			.start = 0x00000000,
+			.size  = 0x00000000
+		},
+		.mem3 = {
+			.start = 0x00000000,
+			.size  = 0x00000000
+		},
+	},
+
+	[PART_WORK] = {
+		.mem = {
+			.start = 0x00040000,
+			.size  = 0x00014fc0
+		},
+		.reg = {
+			.start = REGISTERS_BASE,
+			.size  = 0x0000a000
+		},
+		.mem2 = {
+			.start = 0x003004f8,
+			.size  = 0x00000004
+		},
+		.mem3 = {
+			.start = 0x00040404,
+			.size  = 0x00000000
+		},
+	},
+
+	[PART_DRPW] = {
+		.mem = {
+			.start = 0x00040000,
+			.size  = 0x00014fc0
+		},
+		.reg = {
+			.start = DRPW_BASE,
+			.size  = 0x00006000
+		},
+		.mem2 = {
+			.start = 0x00000000,
+			.size  = 0x00000000
+		},
+		.mem3 = {
+			.start = 0x00000000,
+			.size  = 0x00000000
+		}
+	}
+};
+
 bool wl1271_set_block_size(struct wl1271 *wl)
 {
 	if (wl->if_ops->set_block_size) {
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index d398cbc..4fb3dab 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -43,6 +43,8 @@
 
 #define HW_ACCESS_PRAM_MAX_RANGE	0x3c000
 
+extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN];
+
 struct wl1271;
 
 void wl1271_disable_interrupts(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index f8748ce..adf9bbc 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1,3 +1,4 @@
+
 /*
  * This file is part of wl1271
  *
@@ -115,6 +116,9 @@
 			[CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
 			[CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
 			[CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
+			/* CTS Diluting params */
+			[CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
+			[CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
 		},
 		.state = CONF_SG_PROTECTIVE,
 	},
@@ -217,6 +221,8 @@
 	.conn = {
 		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
 		.listen_interval             = 1,
+		.suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
+		.suspend_listen_interval     = 3,
 		.bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
 		.bcn_filt_ie_count           = 2,
 		.bcn_filt_ie = {
@@ -235,12 +241,13 @@
 		.broadcast_timeout           = 20000,
 		.rx_broadcast_in_ps          = 1,
 		.ps_poll_threshold           = 10,
-		.ps_poll_recovery_period     = 700,
 		.bet_enable                  = CONF_BET_MODE_ENABLE,
 		.bet_max_consecutive         = 50,
 		.psm_entry_retries           = 8,
 		.psm_exit_retries            = 16,
 		.psm_entry_nullfunc_retries  = 3,
+		.dynamic_ps_timeout          = 100,
+		.forced_ps                   = false,
 		.keep_alive_interval         = 55000,
 		.max_listen_interval         = 20,
 	},
@@ -265,6 +272,7 @@
 		.min_dwell_time_passive       = 100000,
 		.max_dwell_time_passive       = 100000,
 		.num_probe_reqs               = 2,
+		.split_scan_timeout           = 50000,
 	},
 	.sched_scan = {
 		/* sched_scan requires dwell times in TU instead of TU/1000 */
@@ -672,8 +680,6 @@
 		if (ret < 0)
 			return ret;
 	}
-	if (ret < 0)
-		return ret;
 
 	/* Chip-specific initializations */
 	ret = wl1271_chip_specific_init(wl);
@@ -985,16 +991,70 @@
 	return IRQ_HANDLED;
 }
 
-static int wl1271_fetch_firmware(struct wl1271 *wl)
+struct vif_counter_data {
+	u8 counter;
+
+	struct ieee80211_vif *cur_vif;
+	bool cur_vif_running;
+};
+
+static void wl12xx_vif_count_iter(void *data, u8 *mac,
+				  struct ieee80211_vif *vif)
+{
+	struct vif_counter_data *counter = data;
+
+	counter->counter++;
+	if (counter->cur_vif == vif)
+		counter->cur_vif_running = true;
+}
+
+/* caller must not hold wl->mutex, as it might deadlock */
+static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *cur_vif,
+			       struct vif_counter_data *data)
+{
+	memset(data, 0, sizeof(*data));
+	data->cur_vif = cur_vif;
+
+	ieee80211_iterate_active_interfaces(hw,
+					    wl12xx_vif_count_iter, data);
+}
+
+static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
 {
 	const struct firmware *fw;
 	const char *fw_name;
+	enum wl12xx_fw_type fw_type;
 	int ret;
 
-	if (wl->chip.id == CHIP_ID_1283_PG20)
-		fw_name = WL128X_FW_NAME;
-	else
-		fw_name	= WL127X_FW_NAME;
+	if (plt) {
+		fw_type = WL12XX_FW_TYPE_PLT;
+		if (wl->chip.id == CHIP_ID_1283_PG20)
+			fw_name = WL128X_PLT_FW_NAME;
+		else
+			fw_name	= WL127X_PLT_FW_NAME;
+	} else {
+		/*
+		 * we can't call wl12xx_get_vif_count() here because
+		 * wl->mutex is taken, so use the cached last_vif_count value
+		 */
+		if (wl->last_vif_count > 1) {
+			fw_type = WL12XX_FW_TYPE_MULTI;
+			if (wl->chip.id == CHIP_ID_1283_PG20)
+				fw_name = WL128X_FW_NAME_MULTI;
+			else
+				fw_name = WL127X_FW_NAME_MULTI;
+		} else {
+			fw_type = WL12XX_FW_TYPE_NORMAL;
+			if (wl->chip.id == CHIP_ID_1283_PG20)
+				fw_name = WL128X_FW_NAME_SINGLE;
+			else
+				fw_name = WL127X_FW_NAME_SINGLE;
+		}
+	}
+
+	if (wl->fw_type == fw_type)
+		return 0;
 
 	wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
 
@@ -1013,6 +1073,7 @@
 	}
 
 	vfree(wl->fw);
+	wl->fw_type = WL12XX_FW_TYPE_NONE;
 	wl->fw_len = fw->size;
 	wl->fw = vmalloc(wl->fw_len);
 
@@ -1024,7 +1085,7 @@
 
 	memcpy(wl->fw, fw->data, wl->fw_len);
 	ret = 0;
-
+	wl->fw_type = fw_type;
 out:
 	release_firmware(fw);
 
@@ -1152,7 +1213,7 @@
 
 	mutex_lock(&wl->mutex);
 
-	if (wl->state != WL1271_STATE_ON)
+	if (wl->state != WL1271_STATE_ON || wl->plt)
 		goto out_unlock;
 
 	/* Avoid a recursive recovery */
@@ -1232,10 +1293,9 @@
 	return 0;
 }
 
-static int wl1271_chip_wakeup(struct wl1271 *wl)
+static int wl12xx_set_power_on(struct wl1271 *wl)
 {
-	struct wl1271_partition_set partition;
-	int ret = 0;
+	int ret;
 
 	msleep(WL1271_PRE_POWER_ON_SLEEP);
 	ret = wl1271_power_on(wl);
@@ -1245,20 +1305,22 @@
 	wl1271_io_reset(wl);
 	wl1271_io_init(wl);
 
-	/* We don't need a real memory partition here, because we only want
-	 * to use the registers at this point. */
-	memset(&partition, 0, sizeof(partition));
-	partition.reg.start = REGISTERS_BASE;
-	partition.reg.size = REGISTERS_DOWN_SIZE;
-	wl1271_set_partition(wl, &partition);
+	wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
 
 	/* ELP module wake up */
 	wl1271_fw_wakeup(wl);
 
-	/* whal_FwCtrl_BootSm() */
+out:
+	return ret;
+}
 
-	/* 0. read chip id from CHIP_ID */
-	wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
+static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
+{
+	int ret = 0;
+
+	ret = wl12xx_set_power_on(wl);
+	if (ret < 0)
+		goto out;
 
 	/*
 	 * For wl127x based devices we could use the default block
@@ -1307,11 +1369,9 @@
 		goto out;
 	}
 
-	if (wl->fw == NULL) {
-		ret = wl1271_fetch_firmware(wl);
-		if (ret < 0)
-			goto out;
-	}
+	ret = wl12xx_fetch_firmware(wl, plt);
+	if (ret < 0)
+		goto out;
 
 	/* No NVS from netlink, try to get it from the filesystem */
 	if (wl->nvs == NULL) {
@@ -1343,7 +1403,7 @@
 
 	while (retries) {
 		retries--;
-		ret = wl1271_chip_wakeup(wl);
+		ret = wl12xx_chip_wakeup(wl, true);
 		if (ret < 0)
 			goto power_off;
 
@@ -1355,7 +1415,8 @@
 		if (ret < 0)
 			goto irq_disable;
 
-		wl->state = WL1271_STATE_PLT;
+		wl->plt = true;
+		wl->state = WL1271_STATE_ON;
 		wl1271_notice("firmware booted in PLT mode (%s)",
 			      wl->chip.fw_ver_str);
 
@@ -1391,41 +1452,51 @@
 	return ret;
 }
 
-static int __wl1271_plt_stop(struct wl1271 *wl)
+int wl1271_plt_stop(struct wl1271 *wl)
 {
 	int ret = 0;
 
 	wl1271_notice("power down");
 
-	if (wl->state != WL1271_STATE_PLT) {
+	/*
+	 * Interrupts must be disabled before setting the state to OFF.
+	 * Otherwise, the interrupt handler might be called and exit without
+	 * reading the interrupt status.
+	 */
+	wl1271_disable_interrupts(wl);
+	mutex_lock(&wl->mutex);
+	if (!wl->plt) {
+		mutex_unlock(&wl->mutex);
+
+		/*
+		 * This will not necessarily enable interrupts as interrupts
+		 * may have been disabled when op_stop was called. It will,
+		 * however, balance the above call to disable_interrupts().
+		 */
+		wl1271_enable_interrupts(wl);
+
 		wl1271_error("cannot power down because not in PLT "
 			     "state: %d", wl->state);
 		ret = -EBUSY;
 		goto out;
 	}
 
-	wl1271_power_off(wl);
-
-	wl->state = WL1271_STATE_OFF;
-	wl->rx_counter = 0;
-
 	mutex_unlock(&wl->mutex);
-	wl1271_disable_interrupts(wl);
+
 	wl1271_flush_deferred_work(wl);
 	cancel_work_sync(&wl->netstack_work);
 	cancel_work_sync(&wl->recovery_work);
-	mutex_lock(&wl->mutex);
-out:
-	return ret;
-}
-
-int wl1271_plt_stop(struct wl1271 *wl)
-{
-	int ret;
+	cancel_delayed_work_sync(&wl->elp_work);
 
 	mutex_lock(&wl->mutex);
-	ret = __wl1271_plt_stop(wl);
+	wl1271_power_off(wl);
+	wl->flags = 0;
+	wl->state = WL1271_STATE_OFF;
+	wl->plt = false;
+	wl->rx_counter = 0;
 	mutex_unlock(&wl->mutex);
+
+out:
 	return ret;
 }
 
@@ -1574,38 +1645,16 @@
 	if (ret < 0)
 		goto out_unlock;
 
-	/* enter psm if needed*/
-	if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
-		DECLARE_COMPLETION_ONSTACK(compl);
+	ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+				    wl->conf.conn.suspend_wake_up_event,
+				    wl->conf.conn.suspend_listen_interval);
 
-		wlvif->ps_compl = &compl;
-		ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
-				   wlvif->basic_rate, true);
-		if (ret < 0)
-			goto out_sleep;
+	if (ret < 0)
+		wl1271_error("suspend: set wake up conditions failed: %d", ret);
 
-		/* we must unlock here so we will be able to get events */
-		wl1271_ps_elp_sleep(wl);
-		mutex_unlock(&wl->mutex);
 
-		ret = wait_for_completion_timeout(
-			&compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
-
-		mutex_lock(&wl->mutex);
-		if (ret <= 0) {
-			wl1271_warning("couldn't enter ps mode!");
-			ret = -EBUSY;
-			goto out_cleanup;
-		}
-
-		ret = wl1271_ps_elp_wakeup(wl);
-		if (ret < 0)
-			goto out_cleanup;
-	}
-out_sleep:
 	wl1271_ps_elp_sleep(wl);
-out_cleanup:
-	wlvif->ps_compl = NULL;
+
 out_unlock:
 	mutex_unlock(&wl->mutex);
 	return ret;
@@ -1648,11 +1697,11 @@
 static void wl1271_configure_resume(struct wl1271 *wl,
 				    struct wl12xx_vif *wlvif)
 {
-	int ret;
-	bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
+	int ret = 0;
 	bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
+	bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
 
-	if (!is_sta && !is_ap)
+	if ((!is_ap) && (!is_sta))
 		return;
 
 	mutex_lock(&wl->mutex);
@@ -1661,12 +1710,16 @@
 		goto out;
 
 	if (is_sta) {
-		/* exit psm if it wasn't configured */
-		if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
-			wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
-					   wlvif->basic_rate, true);
+		ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+				    wl->conf.conn.wake_up_event,
+				    wl->conf.conn.listen_interval);
+
+		if (ret < 0)
+			wl1271_error("resume: wake up conditions failed: %d",
+				     ret);
+
 	} else if (is_ap) {
-		wl1271_acx_beacon_filter_opt(wl, wlvif, false);
+		ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
 	}
 
 	wl1271_ps_elp_sleep(wl);
@@ -1709,9 +1762,6 @@
 
 	wl1271_enable_interrupts(wl);
 	flush_work(&wl->tx_work);
-	wl12xx_for_each_wlvif(wl, wlvif) {
-		flush_delayed_work(&wlvif->pspoll_work);
-	}
 	flush_delayed_work(&wl->elp_work);
 
 	return 0;
@@ -1778,11 +1828,25 @@
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
 
+	/*
+	 * Interrupts must be disabled before setting the state to OFF.
+	 * Otherwise, the interrupt handler might be called and exit without
+	 * reading the interrupt status.
+	 */
+	wl1271_disable_interrupts(wl);
 	mutex_lock(&wl->mutex);
 	if (wl->state == WL1271_STATE_OFF) {
 		mutex_unlock(&wl->mutex);
+
+		/*
+		 * This will not necessarily enable interrupts as interrupts
+		 * may have been disabled when op_stop was called. It will,
+		 * however, balance the above call to disable_interrupts().
+		 */
+		wl1271_enable_interrupts(wl);
 		return;
 	}
+
 	/*
 	 * this must be before the cancel_work calls below, so that the work
 	 * functions don't perform further work.
@@ -1794,7 +1858,6 @@
 	list_del(&wl->list);
 	mutex_unlock(&wl_list_mutex);
 
-	wl1271_disable_interrupts(wl);
 	wl1271_flush_deferred_work(wl);
 	cancel_delayed_work_sync(&wl->scan_complete_work);
 	cancel_work_sync(&wl->netstack_work);
@@ -1969,7 +2032,6 @@
 		  wl1271_rx_streaming_enable_work);
 	INIT_WORK(&wlvif->rx_streaming_disable_work,
 		  wl1271_rx_streaming_disable_work);
-	INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
 	INIT_LIST_HEAD(&wlvif->list);
 
 	setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
@@ -1986,7 +2048,7 @@
 
 	while (retries) {
 		retries--;
-		ret = wl1271_chip_wakeup(wl);
+		ret = wl12xx_chip_wakeup(wl, false);
 		if (ret < 0)
 			goto power_off;
 
@@ -2051,11 +2113,60 @@
 	return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
 }
 
+/*
+ * Check whether a fw switch (i.e. moving from one loaded
+ * fw to another) is needed. This function is also responsible
+ * for updating wl->last_vif_count, so it must be called before
+ * loading a non-plt fw (so the correct fw (single-role/multi-role)
+ * will be used).
+ */
+static bool wl12xx_need_fw_change(struct wl1271 *wl,
+				  struct vif_counter_data vif_counter_data,
+				  bool add)
+{
+	enum wl12xx_fw_type current_fw = wl->fw_type;
+	u8 vif_count = vif_counter_data.counter;
+
+	if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
+		return false;
+
+	/* increase the vif count if this is a new vif */
+	if (add && !vif_counter_data.cur_vif_running)
+		vif_count++;
+
+	wl->last_vif_count = vif_count;
+
+	/* no need for fw change if the device is OFF */
+	if (wl->state == WL1271_STATE_OFF)
+		return false;
+
+	if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
+		return true;
+	if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
+		return true;
+
+	return false;
+}
+
+/*
+ * Enter "forced psm". Make sure the sta is in psm against the ap,
+ * to make the fw switch a bit more disconnection-persistent.
+ */
+static void wl12xx_force_active_psm(struct wl1271 *wl)
+{
+	struct wl12xx_vif *wlvif;
+
+	wl12xx_for_each_wlvif_sta(wl, wlvif) {
+		wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
+	}
+}
+
 static int wl1271_op_add_interface(struct ieee80211_hw *hw,
 				   struct ieee80211_vif *vif)
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+	struct vif_counter_data vif_count;
 	int ret = 0;
 	u8 role_type;
 	bool booted = false;
@@ -2066,18 +2177,13 @@
 	wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
 		     ieee80211_vif_type_p2p(vif), vif->addr);
 
+	wl12xx_get_vif_count(hw, vif, &vif_count);
+
 	mutex_lock(&wl->mutex);
 	ret = wl1271_ps_elp_wakeup(wl);
 	if (ret < 0)
 		goto out_unlock;
 
-	if (wl->vif) {
-		wl1271_debug(DEBUG_MAC80211,
-			     "multiple vifs are not supported yet");
-		ret = -EBUSY;
-		goto out;
-	}
-
 	/*
 	 * in some very corner case HW recovery scenarios its possible to
 	 * get here before __wl1271_op_remove_interface is complete, so
@@ -2089,6 +2195,7 @@
 		goto out;
 	}
 
+
 	ret = wl12xx_init_vif_data(wl, vif);
 	if (ret < 0)
 		goto out;
@@ -2100,6 +2207,13 @@
 		goto out;
 	}
 
+	if (wl12xx_need_fw_change(wl, vif_count, true)) {
+		wl12xx_force_active_psm(wl);
+		mutex_unlock(&wl->mutex);
+		wl1271_recovery_work(&wl->recovery_work);
+		return 0;
+	}
+
 	/*
 	 * TODO: after the nvs issue will be solved, move this block
 	 * to start(), and make sure here the driver is ON.
@@ -2109,7 +2223,7 @@
 		 * we still need this in order to configure the fw
 		 * while uploading the nvs
 		 */
-		memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
+		memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
 
 		booted = wl12xx_init_fw(wl);
 		if (!booted) {
@@ -2142,7 +2256,6 @@
 	if (ret < 0)
 		goto out;
 
-	wl->vif = vif;
 	list_add(&wlvif->list, &wl->wlvif_list);
 	set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
 
@@ -2175,18 +2288,12 @@
 	if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
 		return;
 
-	wl->vif = NULL;
-
 	/* because of hardware recovery, we may get here twice */
 	if (wl->state != WL1271_STATE_ON)
 		return;
 
 	wl1271_info("down");
 
-	/* enable dyn ps just in case (if left on due to fw crash etc) */
-	if (wlvif->bss_type == BSS_TYPE_STA_BSS)
-		ieee80211_enable_dyn_ps(vif);
-
 	if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
 	    wl->scan_vif == vif) {
 		wl->scan.state = WL1271_SCAN_STATE_IDLE;
@@ -2253,10 +2360,10 @@
 		wl->sta_count--;
 
 	mutex_unlock(&wl->mutex);
+
 	del_timer_sync(&wlvif->rx_streaming_timer);
 	cancel_work_sync(&wlvif->rx_streaming_enable_work);
 	cancel_work_sync(&wlvif->rx_streaming_disable_work);
-	cancel_delayed_work_sync(&wlvif->pspoll_work);
 
 	mutex_lock(&wl->mutex);
 }
@@ -2267,7 +2374,10 @@
 	struct wl1271 *wl = hw->priv;
 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	struct wl12xx_vif *iter;
+	struct vif_counter_data vif_count;
+	bool cancel_recovery = true;
 
+	wl12xx_get_vif_count(hw, vif, &vif_count);
 	mutex_lock(&wl->mutex);
 
 	if (wl->state == WL1271_STATE_OFF ||
@@ -2286,20 +2396,33 @@
 		break;
 	}
 	WARN_ON(iter != wlvif);
+	if (wl12xx_need_fw_change(wl, vif_count, false)) {
+		wl12xx_force_active_psm(wl);
+		wl12xx_queue_recovery_work(wl);
+		cancel_recovery = false;
+	}
 out:
 	mutex_unlock(&wl->mutex);
-	cancel_work_sync(&wl->recovery_work);
+	if (cancel_recovery)
+		cancel_work_sync(&wl->recovery_work);
 }
 
 static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
 				      struct ieee80211_vif *vif,
 				      enum nl80211_iftype new_type, bool p2p)
 {
+	struct wl1271 *wl = hw->priv;
+	int ret;
+
+	set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
 	wl1271_op_remove_interface(hw, vif);
 
 	vif->type = ieee80211_iftype_p2p(new_type, p2p);
 	vif->p2p = p2p;
-	return wl1271_op_add_interface(hw, vif);
+	ret = wl1271_op_add_interface(hw, vif);
+
+	clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
+	return ret;
 }
 
 static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -2320,6 +2443,9 @@
 	if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
 		wl1271_info("JOIN while associated.");
 
+	/* clear encryption type */
+	wlvif->encryption_type = KEY_NONE;
+
 	if (set_assoc)
 		set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
 
@@ -2503,38 +2629,41 @@
 		}
 	}
 
-	/*
-	 * if mac80211 changes the PSM mode, make sure the mode is not
-	 * incorrectly changed after the pspoll failure active window.
-	 */
-	if (changed & IEEE80211_CONF_CHANGE_PS)
-		clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
+	if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
 
-	if (conf->flags & IEEE80211_CONF_PS &&
-	    !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
-		set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
+		if ((conf->flags & IEEE80211_CONF_PS) &&
+		    test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
+		    !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
 
-		/*
-		 * We enter PSM only if we're already associated.
-		 * If we're not, we'll enter it when joining an SSID,
-		 * through the bss_info_changed() hook.
-		 */
-		if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
-			wl1271_debug(DEBUG_PSM, "psm enabled");
+			int ps_mode;
+			char *ps_mode_str;
+
+			if (wl->conf.conn.forced_ps) {
+				ps_mode = STATION_POWER_SAVE_MODE;
+				ps_mode_str = "forced";
+			} else {
+				ps_mode = STATION_AUTO_PS_MODE;
+				ps_mode_str = "auto";
+			}
+
+			wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
+
+			ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
+
+			if (ret < 0)
+				wl1271_warning("enter %s ps failed %d",
+					       ps_mode_str, ret);
+
+		} else if (!(conf->flags & IEEE80211_CONF_PS) &&
+			   test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
+
+			wl1271_debug(DEBUG_PSM, "auto ps disabled");
+
 			ret = wl1271_ps_set_mode(wl, wlvif,
-						 STATION_POWER_SAVE_MODE,
-						 wlvif->basic_rate, true);
+						 STATION_ACTIVE_MODE);
+			if (ret < 0)
+				wl1271_warning("exit auto ps failed %d", ret);
 		}
-	} else if (!(conf->flags & IEEE80211_CONF_PS) &&
-		   test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
-		wl1271_debug(DEBUG_PSM, "psm disabled");
-
-		clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
-
-		if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
-			ret = wl1271_ps_set_mode(wl, wlvif,
-						 STATION_ACTIVE_MODE,
-						 wlvif->basic_rate, true);
 	}
 
 	if (conf->power_level != wlvif->power_level) {
@@ -2974,6 +3103,21 @@
 			wl1271_error("Could not add or replace key");
 			goto out_sleep;
 		}
+
+		/*
+		 * reconfiguring arp response if the unicast (or common)
+		 * encryption key type was changed
+		 */
+		if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
+		    (sta || key_type == KEY_WEP) &&
+		    wlvif->encryption_type != key_type) {
+			wlvif->encryption_type = key_type;
+			ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
+			if (ret < 0) {
+				wl1271_warning("build arp rsp failed: %d", ret);
+				goto out_sleep;
+			}
+		}
 		break;
 
 	case DISABLE_KEY:
@@ -3043,10 +3187,6 @@
 		goto out_sleep;
 	}
 
-	/* cancel ROC before scanning */
-	if (wl12xx_dev_role_started(wlvif))
-		wl12xx_stop_dev(wl, wlvif);
-
 	ret = wl1271_scan(hw->priv, vif, ssid, len, req);
 out_sleep:
 	wl1271_ps_elp_sleep(wl);
@@ -3108,6 +3248,11 @@
 
 	mutex_lock(&wl->mutex);
 
+	if (wl->state == WL1271_STATE_OFF) {
+		ret = -EAGAIN;
+		goto out;
+	}
+
 	ret = wl1271_ps_elp_wakeup(wl);
 	if (ret < 0)
 		goto out;
@@ -3139,6 +3284,9 @@
 
 	mutex_lock(&wl->mutex);
 
+	if (wl->state == WL1271_STATE_OFF)
+		goto out;
+
 	ret = wl1271_ps_elp_wakeup(wl);
 	if (ret < 0)
 		goto out;
@@ -3266,6 +3414,7 @@
 static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
 					 struct ieee80211_vif *vif)
 {
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	struct sk_buff *skb;
 	int ret;
 
@@ -3273,7 +3422,7 @@
 	if (!skb)
 		return -EOPNOTSUPP;
 
-	ret = wl1271_cmd_template_set(wl,
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
 				      CMD_TEMPL_AP_PROBE_RESPONSE,
 				      skb->data,
 				      skb->len, 0,
@@ -3297,7 +3446,7 @@
 
 	/* no need to change probe response if the SSID is set correctly */
 	if (wlvif->ssid_len > 0)
-		return wl1271_cmd_template_set(wl,
+		return wl1271_cmd_template_set(wl, wlvif->role_id,
 					       CMD_TEMPL_AP_PROBE_RESPONSE,
 					       probe_rsp_data,
 					       probe_rsp_len, 0,
@@ -3334,7 +3483,7 @@
 	       ptr, probe_rsp_len - (ptr - probe_rsp_data));
 	templ_len += probe_rsp_len - (ptr - probe_rsp_data);
 
-	return wl1271_cmd_template_set(wl,
+	return wl1271_cmd_template_set(wl, wlvif->role_id,
 				       CMD_TEMPL_AP_PROBE_RESPONSE,
 				       probe_rsp_templ,
 				       templ_len, 0,
@@ -3431,7 +3580,7 @@
 		min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
 		tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
 				  CMD_TEMPL_BEACON;
-		ret = wl1271_cmd_template_set(wl, tmpl_id,
+		ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
 					      beacon->data,
 					      beacon->len, 0,
 					      min_rate);
@@ -3470,7 +3619,7 @@
 						beacon->len,
 						min_rate);
 		else
-			ret = wl1271_cmd_template_set(wl,
+			ret = wl1271_cmd_template_set(wl, wlvif->role_id,
 						CMD_TEMPL_PROBE_RESPONSE,
 						beacon->data,
 						beacon->len, 0,
@@ -3634,7 +3783,8 @@
 		wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
 	}
 
-	if (changed & BSS_CHANGED_BSSID)
+	if (changed & BSS_CHANGED_BSSID &&
+	    (is_ibss || bss_conf->assoc))
 		if (!is_zero_ether_addr(bss_conf->bssid)) {
 			ret = wl12xx_cmd_build_null_data(wl, wlvif);
 			if (ret < 0)
@@ -3673,8 +3823,6 @@
 			wlvif->aid = bss_conf->aid;
 			set_assoc = true;
 
-			wlvif->ps_poll_failures = 0;
-
 			/*
 			 * use basic rates from AP, and determine lowest rate
 			 * to use with control frames.
@@ -3734,9 +3882,6 @@
 			dev_kfree_skb(wlvif->probereq);
 			wlvif->probereq = NULL;
 
-			/* re-enable dynamic ps - just in case */
-			ieee80211_enable_dyn_ps(vif);
-
 			/* revert back to minimum rates for the current band */
 			wl1271_set_band_rate(wl, wlvif);
 			wlvif->basic_rate =
@@ -3810,34 +3955,6 @@
 	if (ret < 0)
 		goto out;
 
-	if (changed & BSS_CHANGED_ARP_FILTER) {
-		__be32 addr = bss_conf->arp_addr_list[0];
-		WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
-
-		if (bss_conf->arp_addr_cnt == 1 &&
-		    bss_conf->arp_filter_enabled) {
-			/*
-			 * The template should have been configured only upon
-			 * association. however, it seems that the correct ip
-			 * isn't being set (when sending), so we have to
-			 * reconfigure the template upon every ip change.
-			 */
-			ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
-			if (ret < 0) {
-				wl1271_warning("build arp rsp failed: %d", ret);
-				goto out;
-			}
-
-			ret = wl1271_acx_arp_ip_filter(wl, wlvif,
-				ACX_ARP_FILTER_ARP_FILTERING,
-				addr);
-		} else
-			ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
-
-		if (ret < 0)
-			goto out;
-	}
-
 	if (do_join) {
 		ret = wl1271_join(wl, wlvif, set_assoc);
 		if (ret < 0) {
@@ -3863,19 +3980,6 @@
 			if (ret < 0)
 				goto out;
 		}
-
-		/* If we want to go in PSM but we're not there yet */
-		if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
-		    !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
-			enum wl1271_cmd_ps_mode mode;
-
-			mode = STATION_POWER_SAVE_MODE;
-			ret = wl1271_ps_set_mode(wl, wlvif, mode,
-						 wlvif->basic_rate,
-						 true);
-			if (ret < 0)
-				goto out;
-		}
 	}
 
 	/* Handle new association with HT. Do this after join. */
@@ -3917,6 +4021,41 @@
 		}
 	}
 
+	/* Handle arp filtering. Done after join. */
+	if ((changed & BSS_CHANGED_ARP_FILTER) ||
+	    (!is_ibss && (changed & BSS_CHANGED_QOS))) {
+		__be32 addr = bss_conf->arp_addr_list[0];
+		wlvif->sta.qos = bss_conf->qos;
+		WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
+
+		if (bss_conf->arp_addr_cnt == 1 &&
+		    bss_conf->arp_filter_enabled) {
+			wlvif->ip_addr = addr;
+			/*
+			 * The template should have been configured only upon
+			 * association. however, it seems that the correct ip
+			 * isn't being set (when sending), so we have to
+			 * reconfigure the template upon every ip change.
+			 */
+			ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
+			if (ret < 0) {
+				wl1271_warning("build arp rsp failed: %d", ret);
+				goto out;
+			}
+
+			ret = wl1271_acx_arp_ip_filter(wl, wlvif,
+				(ACX_ARP_FILTER_ARP_FILTERING |
+				 ACX_ARP_FILTER_AUTO_ARP),
+				addr);
+		} else {
+			wlvif->ip_addr = 0;
+			ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
+		}
+
+		if (ret < 0)
+			goto out;
+	}
+
 out:
 	return;
 }
@@ -4012,6 +4151,7 @@
 {
 
 	struct wl1271 *wl = hw->priv;
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	u64 mactime = ULLONG_MAX;
 	int ret;
 
@@ -4026,7 +4166,7 @@
 	if (ret < 0)
 		goto out;
 
-	ret = wl1271_acx_tsf_info(wl, &mactime);
+	ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
 	if (ret < 0)
 		goto out_sleep;
 
@@ -4373,7 +4513,7 @@
 
 	/* TODO: change mac80211 to pass vif as param */
 	wl12xx_for_each_wlvif_sta(wl, wlvif) {
-		ret = wl12xx_cmd_channel_switch(wl, ch_switch);
+		ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
 
 		if (!ret)
 			set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
@@ -4467,6 +4607,7 @@
 /* mapping to indexes for wl1271_rates */
 static const u8 wl1271_rate_to_idx_2ghz[] = {
 	/* MCS rates are used only with 11n */
+	7,                            /* CONF_HW_RXTX_RATE_MCS7_SGI */
 	7,                            /* CONF_HW_RXTX_RATE_MCS7 */
 	6,                            /* CONF_HW_RXTX_RATE_MCS6 */
 	5,                            /* CONF_HW_RXTX_RATE_MCS5 */
@@ -4588,6 +4729,7 @@
 /* mapping to indexes for wl1271_rates_5ghz */
 static const u8 wl1271_rate_to_idx_5ghz[] = {
 	/* MCS rates are used only with 11n */
+	7,                            /* CONF_HW_RXTX_RATE_MCS7_SGI */
 	7,                            /* CONF_HW_RXTX_RATE_MCS7 */
 	6,                            /* CONF_HW_RXTX_RATE_MCS6 */
 	5,                            /* CONF_HW_RXTX_RATE_MCS5 */
@@ -4828,13 +4970,120 @@
 	.read = wl1271_sysfs_read_fwlog,
 };
 
+static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
+{
+	bool supported = false;
+	u8 major, minor;
+
+	if (wl->chip.id == CHIP_ID_1283_PG20) {
+		major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
+		minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
+
+		/* in wl128x we have the MAC address if the PG is >= (2, 1) */
+		if (major > 2 || (major == 2 && minor >= 1))
+			supported = true;
+	} else {
+		major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
+		minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
+
+		/* in wl127x we have the MAC address if the PG is >= (3, 1) */
+		if (major == 3 && minor >= 1)
+			supported = true;
+	}
+
+	wl1271_debug(DEBUG_PROBE,
+		     "PG Ver major = %d minor = %d, MAC %s present",
+		     major, minor, supported ? "is" : "is not");
+
+	return supported;
+}
+
+static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
+					u32 oui, u32 nic, int n)
+{
+	int i;
+
+	wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
+		     oui, nic, n);
+
+	if (nic + n - 1 > 0xffffff)
+		wl1271_warning("NIC part of the MAC address wraps around!");
+
+	for (i = 0; i < n; i++) {
+		wl->addresses[i].addr[0] = (u8)(oui >> 16);
+		wl->addresses[i].addr[1] = (u8)(oui >> 8);
+		wl->addresses[i].addr[2] = (u8) oui;
+		wl->addresses[i].addr[3] = (u8)(nic >> 16);
+		wl->addresses[i].addr[4] = (u8)(nic >> 8);
+		wl->addresses[i].addr[5] = (u8) nic;
+		nic++;
+	}
+
+	wl->hw->wiphy->n_addresses = n;
+	wl->hw->wiphy->addresses = wl->addresses;
+}
+
+static void wl12xx_get_fuse_mac(struct wl1271 *wl)
+{
+	u32 mac1, mac2;
+
+	wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
+
+	mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
+	mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
+
+	/* these are the two parts of the BD_ADDR */
+	wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
+		((mac1 & 0xff000000) >> 24);
+	wl->fuse_nic_addr = mac1 & 0xffffff;
+
+	wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
+}
+
+static int wl12xx_get_hw_info(struct wl1271 *wl)
+{
+	int ret;
+	u32 die_info;
+
+	ret = wl12xx_set_power_on(wl);
+	if (ret < 0)
+		goto out;
+
+	wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
+
+	if (wl->chip.id == CHIP_ID_1283_PG20)
+		die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
+	else
+		die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
+
+	wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
+
+	if (!wl12xx_mac_in_fuse(wl)) {
+		wl->fuse_oui_addr = 0;
+		wl->fuse_nic_addr = 0;
+	} else {
+		wl12xx_get_fuse_mac(wl);
+	}
+
+	wl1271_power_off(wl);
+out:
+	return ret;
+}
+
 static int wl1271_register_hw(struct wl1271 *wl)
 {
 	int ret;
+	u32 oui_addr = 0, nic_addr = 0;
 
 	if (wl->mac80211_registered)
 		return 0;
 
+	ret = wl12xx_get_hw_info(wl);
+	if (ret < 0) {
+		wl1271_error("couldn't get hw info");
+		goto out;
+	}
+
 	ret = wl1271_fetch_nvs(wl);
 	if (ret == 0) {
 		/* NOTE: The wl->nvs->nvs element must be first, in
@@ -4843,20 +5092,25 @@
 		 */
 		u8 *nvs_ptr = (u8 *)wl->nvs;
 
-		wl->mac_addr[0] = nvs_ptr[11];
-		wl->mac_addr[1] = nvs_ptr[10];
-		wl->mac_addr[2] = nvs_ptr[6];
-		wl->mac_addr[3] = nvs_ptr[5];
-		wl->mac_addr[4] = nvs_ptr[4];
-		wl->mac_addr[5] = nvs_ptr[3];
+		oui_addr =
+			(nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
+		nic_addr =
+			(nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
 	}
 
-	SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
+	/* if the MAC address is zeroed in the NVS derive from fuse */
+	if (oui_addr == 0 && nic_addr == 0) {
+		oui_addr = wl->fuse_oui_addr;
+		/* fuse has the BD_ADDR, the WLAN addresses are the next two */
+		nic_addr = wl->fuse_nic_addr + 1;
+	}
+
+	wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
 
 	ret = ieee80211_register_hw(wl->hw);
 	if (ret < 0) {
 		wl1271_error("unable to register mac80211 hw: %d", ret);
-		return ret;
+		goto out;
 	}
 
 	wl->mac80211_registered = true;
@@ -4867,13 +5121,14 @@
 
 	wl1271_notice("loaded");
 
-	return 0;
+out:
+	return ret;
 }
 
 static void wl1271_unregister_hw(struct wl1271 *wl)
 {
-	if (wl->state == WL1271_STATE_PLT)
-		__wl1271_plt_stop(wl);
+	if (wl->plt)
+		wl1271_plt_stop(wl);
 
 	unregister_netdevice_notifier(&wl1271_dev_notifier);
 	ieee80211_unregister_hw(wl->hw);
@@ -4892,7 +5147,7 @@
 	};
 
 	/* The tx descriptor buffer and the TKIP space. */
-	wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
+	wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
 		sizeof(struct wl1271_tx_hw_descr);
 
 	/* unit us */
@@ -4902,6 +5157,7 @@
 
 	wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
 		IEEE80211_HW_SUPPORTS_PS |
+		IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
 		IEEE80211_HW_SUPPORTS_UAPSD |
 		IEEE80211_HW_HAS_RATE_CONTROL |
 		IEEE80211_HW_CONNECTION_MONITOR |
@@ -4909,7 +5165,8 @@
 		IEEE80211_HW_SPECTRUM_MGMT |
 		IEEE80211_HW_AP_LINK_PS |
 		IEEE80211_HW_AMPDU_AGGREGATION |
-		IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
+		IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
+		IEEE80211_HW_SCAN_WHILE_IDLE;
 
 	wl->hw->wiphy->cipher_suites = cipher_suites;
 	wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -4925,10 +5182,10 @@
 	 * should be the maximum length possible for a template, without
 	 * the IEEE80211 header of the template
 	 */
-	wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
+	wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
 			sizeof(struct ieee80211_header);
 
-	wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
+	wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
 		sizeof(struct ieee80211_header);
 
 	wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
@@ -5022,7 +5279,6 @@
 	wl->rx_counter = 0;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
 	wl->band = IEEE80211_BAND_2GHZ;
-	wl->vif = NULL;
 	wl->flags = 0;
 	wl->sg_enabled = true;
 	wl->hw_pg_ver = -1;
@@ -5047,6 +5303,7 @@
 	spin_lock_init(&wl->wl_lock);
 
 	wl->state = WL1271_STATE_OFF;
+	wl->fw_type = WL12XX_FW_TYPE_NONE;
 	mutex_init(&wl->mutex);
 
 	/* Apply default driver configuration. */
@@ -5114,6 +5371,7 @@
 
 	vfree(wl->fw);
 	wl->fw = NULL;
+	wl->fw_type = WL12XX_FW_TYPE_NONE;
 	kfree(wl->nvs);
 	wl->nvs = NULL;
 
@@ -5300,7 +5558,7 @@
 MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
 
 module_param_named(fwlog, fwlog_param, charp, 0);
-MODULE_PARM_DESC(keymap,
+MODULE_PARM_DESC(fwlog,
 		 "FW logger options: continuous, ondemand, dbgpins or disable");
 
 module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index a2bdacd..23d6750 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -56,7 +56,7 @@
 		if (wlvif->bss_type == BSS_TYPE_AP_BSS)
 			goto out;
 
-		if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
+		if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
 		    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
 			goto out;
 	}
@@ -84,7 +84,7 @@
 		if (wlvif->bss_type == BSS_TYPE_AP_BSS)
 			return;
 
-		if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
+		if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
 		    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
 			return;
 	}
@@ -160,28 +160,39 @@
 }
 
 int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-		       enum wl1271_cmd_ps_mode mode, u32 rates, bool send)
+		       enum wl1271_cmd_ps_mode mode)
 {
 	int ret;
+	u16 timeout = wl->conf.conn.dynamic_ps_timeout;
 
 	switch (mode) {
+	case STATION_AUTO_PS_MODE:
 	case STATION_POWER_SAVE_MODE:
-		wl1271_debug(DEBUG_PSM, "entering psm");
+		wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)",
+			     mode, timeout);
 
-		ret = wl1271_acx_wake_up_conditions(wl, wlvif);
+		ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+					    wl->conf.conn.wake_up_event,
+					    wl->conf.conn.listen_interval);
 		if (ret < 0) {
 			wl1271_error("couldn't set wake up conditions");
 			return ret;
 		}
 
-		ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
+		ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout);
 		if (ret < 0)
 			return ret;
 
-		set_bit(WLVIF_FLAG_PSM, &wlvif->flags);
+		set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
+
+		/* enable beacon early termination. Not relevant for 5GHz */
+		if (wlvif->band == IEEE80211_BAND_2GHZ) {
+			ret = wl1271_acx_bet_enable(wl, wlvif, true);
+			if (ret < 0)
+				return ret;
+		}
 		break;
 	case STATION_ACTIVE_MODE:
-	default:
 		wl1271_debug(DEBUG_PSM, "leaving psm");
 
 		/* disable beacon early termination */
@@ -191,12 +202,15 @@
 				return ret;
 		}
 
-		ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE);
+		ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0);
 		if (ret < 0)
 			return ret;
 
-		clear_bit(WLVIF_FLAG_PSM, &wlvif->flags);
+		clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
 		break;
+	default:
+		wl1271_warning("trying to set ps to unsupported mode %d", mode);
+		ret = -EINVAL;
 	}
 
 	return ret;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h
index a12052f0..5f19d4f 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/ps.h
@@ -28,7 +28,7 @@
 #include "acx.h"
 
 int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-		       enum wl1271_cmd_ps_mode mode, u32 rates, bool send);
+		       enum wl1271_cmd_ps_mode mode);
 void wl1271_ps_elp_sleep(struct wl1271 *wl);
 int wl1271_ps_elp_wakeup(struct wl1271 *wl);
 void wl1271_elp_work(struct work_struct *work);
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index df34d59..340db32 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -525,4 +525,31 @@
  */
 #define INTR_TRIG_TX_PROC1 BIT(18)
 
+#define WL127X_REG_FUSE_DATA_2_1	0x050a
+#define WL128X_REG_FUSE_DATA_2_1	0x2152
+#define PG_VER_MASK			0x3c
+#define PG_VER_OFFSET			2
+
+#define WL127X_PG_MAJOR_VER_MASK	0x3
+#define WL127X_PG_MAJOR_VER_OFFSET	0x0
+#define WL127X_PG_MINOR_VER_MASK	0xc
+#define WL127X_PG_MINOR_VER_OFFSET	0x2
+
+#define WL128X_PG_MAJOR_VER_MASK	0xc
+#define WL128X_PG_MAJOR_VER_OFFSET	0x2
+#define WL128X_PG_MINOR_VER_MASK	0x3
+#define WL128X_PG_MINOR_VER_OFFSET	0x0
+
+#define WL127X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL127X_PG_MAJOR_VER_MASK) >> \
+				     WL127X_PG_MAJOR_VER_OFFSET)
+#define WL127X_PG_GET_MINOR(pg_ver) ((pg_ver & WL127X_PG_MINOR_VER_MASK) >> \
+				     WL127X_PG_MINOR_VER_OFFSET)
+#define WL128X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL128X_PG_MAJOR_VER_MASK) >> \
+				     WL128X_PG_MAJOR_VER_OFFSET)
+#define WL128X_PG_GET_MINOR(pg_ver) ((pg_ver & WL128X_PG_MINOR_VER_MASK) >> \
+				     WL128X_PG_MINOR_VER_OFFSET)
+
+#define WL12XX_REG_FUSE_BD_ADDR_1	0x00310eb4
+#define WL12XX_REG_FUSE_BD_ADDR_2	0x00310eb8
+
 #endif
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 4fbd2a7..cfa6071 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -113,7 +113,7 @@
 	 * In PLT mode we seem to get frames and mac80211 warns about them,
 	 * workaround this by not retrieving them at all.
 	 */
-	if (unlikely(wl->state == WL1271_STATE_PLT))
+	if (unlikely(wl->plt))
 		return -EINVAL;
 
 	/* the data read starts with the descriptor */
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index e24111e..e43a6b2 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -38,7 +38,6 @@
 	struct ieee80211_vif *vif;
 	struct wl12xx_vif *wlvif;
 	int ret;
-	bool is_sta, is_ibss;
 
 	dwork = container_of(work, struct delayed_work, work);
 	wl = container_of(dwork, struct wl1271, scan_complete_work);
@@ -70,15 +69,6 @@
 		wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq);
 	}
 
-	/* return to ROC if needed */
-	is_sta = (wlvif->bss_type == BSS_TYPE_STA_BSS);
-	is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
-	if (((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) ||
-	     (is_ibss && !test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))) &&
-	    !test_bit(wlvif->dev_role_id, wl->roc_map)) {
-		/* restore remain on channel */
-		wl12xx_start_dev(wl, wlvif);
-	}
 	wl1271_ps_elp_sleep(wl);
 
 	if (wl->scan.failed) {
@@ -182,14 +172,23 @@
 		goto out;
 	}
 
+	if (wl->conf.scan.split_scan_timeout)
+		scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
+
 	if (passive)
 		scan_options |= WL1271_SCAN_OPT_PASSIVE;
 
-	if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) {
+	if (wlvif->bss_type == BSS_TYPE_AP_BSS ||
+	    test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+		cmd->params.role_id = wlvif->role_id;
+	else
+		cmd->params.role_id = wlvif->dev_role_id;
+
+	if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
 		ret = -EINVAL;
 		goto out;
 	}
-	cmd->params.role_id = wlvif->role_id;
+
 	cmd->params.scan_options = cpu_to_le16(scan_options);
 
 	cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
@@ -202,7 +201,7 @@
 
 	cmd->params.tx_rate = cpu_to_le32(basic_rate);
 	cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
-	cmd->params.tid_trigger = 0;
+	cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
 	cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
 
 	if (band == IEEE80211_BAND_2GHZ)
@@ -217,16 +216,17 @@
 
 	memcpy(cmd->addr, vif->addr, ETH_ALEN);
 
-	ret = wl1271_cmd_build_probe_req(wl, wlvif, wl->scan.ssid,
-					 wl->scan.ssid_len, wl->scan.req->ie,
-					 wl->scan.req->ie_len, band);
+	ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+					 cmd->params.role_id, band,
+					 wl->scan.ssid, wl->scan.ssid_len,
+					 wl->scan.req->ie,
+					 wl->scan.req->ie_len);
 	if (ret < 0) {
 		wl1271_error("PROBE request template failed");
 		goto out;
 	}
 
-	/* disable the timeout */
-	trigger->timeout = 0;
+	trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
 	ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
 			      sizeof(*trigger), 0);
 	if (ret < 0) {
@@ -658,11 +658,13 @@
 	}
 
 	if (!force_passive && cfg->active[0]) {
-		ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
+		u8 band = IEEE80211_BAND_2GHZ;
+		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+						 wlvif->dev_role_id, band,
+						 req->ssids[0].ssid,
 						 req->ssids[0].ssid_len,
-						 ies->ie[IEEE80211_BAND_2GHZ],
-						 ies->len[IEEE80211_BAND_2GHZ],
-						 IEEE80211_BAND_2GHZ);
+						 ies->ie[band],
+						 ies->len[band]);
 		if (ret < 0) {
 			wl1271_error("2.4GHz PROBE request template failed");
 			goto out;
@@ -670,11 +672,13 @@
 	}
 
 	if (!force_passive && cfg->active[1]) {
-		ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
+		u8 band = IEEE80211_BAND_5GHZ;
+		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+						 wlvif->dev_role_id, band,
+						 req->ssids[0].ssid,
 						 req->ssids[0].ssid_len,
-						 ies->ie[IEEE80211_BAND_5GHZ],
-						 ies->len[IEEE80211_BAND_5GHZ],
-						 IEEE80211_BAND_5GHZ);
+						 ies->ie[band],
+						 ies->len[band]);
 		if (ret < 0) {
 			wl1271_error("5GHz PROBE request template failed");
 			goto out;
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index a7ed43d..96ff457 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -48,7 +48,7 @@
 #define WL1271_SCAN_CURRENT_TX_PWR     0
 #define WL1271_SCAN_OPT_ACTIVE         0
 #define WL1271_SCAN_OPT_PASSIVE	       1
-#define WL1271_SCAN_OPT_TRIGGERED_SCAN 2
+#define WL1271_SCAN_OPT_SPLIT_SCAN     2
 #define WL1271_SCAN_OPT_PRIORITY_HIGH  4
 /* scan even if we fail to enter psm */
 #define WL1271_SCAN_OPT_FORCE          8
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 468a505..4b3c327 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -74,6 +74,8 @@
 	struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
 	struct sdio_func *func = dev_to_sdio_func(glue->dev);
 
+	sdio_claim_host(func);
+
 	if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
 		((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
 		dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
@@ -88,6 +90,8 @@
 			addr, len);
 	}
 
+	sdio_release_host(func);
+
 	if (ret)
 		dev_err(child->parent, "sdio read failed (%d)\n", ret);
 }
@@ -99,6 +103,8 @@
 	struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
 	struct sdio_func *func = dev_to_sdio_func(glue->dev);
 
+	sdio_claim_host(func);
+
 	if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
 		sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
 		dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
@@ -113,6 +119,8 @@
 			ret = sdio_memcpy_toio(func, addr, buf, len);
 	}
 
+	sdio_release_host(func);
+
 	if (ret)
 		dev_err(child->parent, "sdio write failed (%d)\n", ret);
 }
@@ -136,6 +144,7 @@
 
 	sdio_claim_host(func);
 	sdio_enable_func(func);
+	sdio_release_host(func);
 
 out:
 	return ret;
@@ -146,6 +155,7 @@
 	int ret;
 	struct sdio_func *func = dev_to_sdio_func(glue->dev);
 
+	sdio_claim_host(func);
 	sdio_disable_func(func);
 	sdio_release_host(func);
 
@@ -314,9 +324,6 @@
 			dev_err(dev, "error while trying to keep power\n");
 			goto out;
 		}
-
-		/* release host */
-		sdio_release_host(func);
 	}
 out:
 	return ret;
@@ -324,15 +331,7 @@
 
 static int wl1271_resume(struct device *dev)
 {
-	struct sdio_func *func = dev_to_sdio_func(dev);
-	struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
-	struct wl1271 *wl = platform_get_drvdata(glue->core);
-
 	dev_dbg(dev, "wl1271 resume\n");
-	if (wl->wow_enabled) {
-		/* claim back host */
-		sdio_claim_host(func);
-	}
 
 	return 0;
 }
@@ -371,5 +370,9 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL127X_FW_NAME);
-MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 92caa7c..2fc18a8 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -433,6 +433,10 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL127X_FW_NAME);
-MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
 MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c
index 25093c0..1e93bb9 100644
--- a/drivers/net/wireless/wl12xx/testmode.c
+++ b/drivers/net/wireless/wl12xx/testmode.c
@@ -30,6 +30,7 @@
 #include "acx.h"
 #include "reg.h"
 #include "ps.h"
+#include "io.h"
 
 #define WL1271_TM_MAX_DATA_LENGTH 1024
 
@@ -41,6 +42,7 @@
 	WL1271_TM_CMD_NVS_PUSH,		/* Not in use. Keep to not break ABI */
 	WL1271_TM_CMD_SET_PLT_MODE,
 	WL1271_TM_CMD_RECOVER,
+	WL1271_TM_CMD_GET_MAC,
 
 	__WL1271_TM_CMD_AFTER_LAST
 };
@@ -264,6 +266,52 @@
 	return 0;
 }
 
+static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[])
+{
+	struct sk_buff *skb;
+	u8 mac_addr[ETH_ALEN];
+	int ret = 0;
+
+	mutex_lock(&wl->mutex);
+
+	if (!wl->plt) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) {
+		ret = -EOPNOTSUPP;
+		goto out;
+	}
+
+	mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16);
+	mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8);
+	mac_addr[2] = (u8) wl->fuse_oui_addr;
+	mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16);
+	mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8);
+	mac_addr[5] = (u8) wl->fuse_nic_addr;
+
+	skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN);
+	if (!skb) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	NLA_PUT(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr);
+	ret = cfg80211_testmode_reply(skb);
+	if (ret < 0)
+		goto out;
+
+out:
+	mutex_unlock(&wl->mutex);
+	return ret;
+
+nla_put_failure:
+	kfree_skb(skb);
+	ret = -EMSGSIZE;
+	goto out;
+}
+
 int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
 {
 	struct wl1271 *wl = hw->priv;
@@ -288,6 +336,8 @@
 		return wl1271_tm_cmd_set_plt_mode(wl, tb);
 	case WL1271_TM_CMD_RECOVER:
 		return wl1271_tm_cmd_recover(wl, tb);
+	case WL1271_TM_CMD_GET_MAC:
+		return wl12xx_tm_cmd_get_mac(wl, tb);
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 4508ccd..6446e4d 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -77,35 +77,6 @@
 	}
 }
 
-static int wl1271_tx_update_filters(struct wl1271 *wl,
-				    struct wl12xx_vif *wlvif,
-				    struct sk_buff *skb)
-{
-	struct ieee80211_hdr *hdr;
-	int ret;
-
-	hdr = (struct ieee80211_hdr *)skb->data;
-
-	/*
-	 * stop bssid-based filtering before transmitting authentication
-	 * requests. this way the hw will never drop authentication
-	 * responses coming from BSSIDs it isn't familiar with (e.g. on
-	 * roaming)
-	 */
-	if (!ieee80211_is_auth(hdr->frame_control))
-		return 0;
-
-	if (wlvif->dev_hlid != WL12XX_INVALID_LINK_ID)
-		goto out;
-
-	wl1271_debug(DEBUG_CMD, "starting device role for roaming");
-	ret = wl12xx_start_dev(wl, wlvif);
-	if (ret < 0)
-		goto out;
-out:
-	return 0;
-}
-
 static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
 						 struct sk_buff *skb)
 {
@@ -187,8 +158,6 @@
 	if (wlvif->bss_type == BSS_TYPE_AP_BSS)
 		return wl12xx_tx_get_hlid_ap(wl, wlvif, skb);
 
-	wl1271_tx_update_filters(wl, wlvif, skb);
-
 	if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
 	     test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
 	    !ieee80211_is_auth(hdr->frame_control) &&
@@ -286,16 +255,20 @@
 	int aligned_len, ac, rate_idx;
 	s64 hosttime;
 	u16 tx_attr = 0;
+	__le16 frame_control;
+	struct ieee80211_hdr *hdr;
+	u8 *frame_start;
 	bool is_dummy;
 
 	desc = (struct wl1271_tx_hw_descr *) skb->data;
+	frame_start = (u8 *)(desc + 1);
+	hdr = (struct ieee80211_hdr *)(frame_start + extra);
+	frame_control = hdr->frame_control;
 
 	/* relocate space for security header */
 	if (extra) {
-		void *framestart = skb->data + sizeof(*desc);
-		u16 fc = *(u16 *)(framestart + extra);
-		int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc));
-		memmove(framestart, framestart + extra, hdrlen);
+		int hdrlen = ieee80211_hdrlen(frame_control);
+		memmove(frame_start, hdr, hdrlen);
 	}
 
 	/* configure packet life time */
@@ -384,6 +357,11 @@
 			     desc->wl127x_mem.total_mem_blocks);
 	}
 
+	/* for WEP shared auth - no fw encryption is needed */
+	if (ieee80211_is_auth(frame_control) &&
+	    ieee80211_has_protected(frame_control))
+		tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
+
 	desc->tx_attr = cpu_to_le16(tx_attr);
 }
 
@@ -408,7 +386,7 @@
 
 	if (info->control.hw_key &&
 	    info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
-		extra = WL1271_TKIP_IV_SPACE;
+		extra = WL1271_EXTRA_SPACE_TKIP;
 
 	if (info->control.hw_key) {
 		bool is_wep;
@@ -795,6 +773,18 @@
 	mutex_unlock(&wl->mutex);
 }
 
+static u8 wl1271_tx_get_rate_flags(u8 rate_class_index)
+{
+	u8 flags = 0;
+
+	if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN &&
+	    rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX)
+		flags |= IEEE80211_TX_RC_MCS;
+	if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI)
+		flags |= IEEE80211_TX_RC_SHORT_GI;
+	return flags;
+}
+
 static void wl1271_tx_complete_packet(struct wl1271 *wl,
 				      struct wl1271_tx_hw_res_descr *result)
 {
@@ -804,6 +794,7 @@
 	struct sk_buff *skb;
 	int id = result->id;
 	int rate = -1;
+	u8 rate_flags = 0;
 	u8 retries = 0;
 
 	/* check for id legality */
@@ -830,6 +821,7 @@
 			info->flags |= IEEE80211_TX_STAT_ACK;
 		rate = wl1271_rate_to_idx(result->rate_class_index,
 					  wlvif->band);
+		rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
 		retries = result->ack_failures;
 	} else if (result->status == TX_RETRY_EXCEEDED) {
 		wl->stats.excessive_retries++;
@@ -838,7 +830,7 @@
 
 	info->status.rates[0].idx = rate;
 	info->status.rates[0].count = retries;
-	info->status.rates[0].flags = 0;
+	info->status.rates[0].flags = rate_flags;
 	info->status.ack_signal = -1;
 
 	wl->stats.retry_count += result->ack_failures;
@@ -869,8 +861,9 @@
 	if (info->control.hw_key &&
 	    info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
 		int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-		memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen);
-		skb_pull(skb, WL1271_TKIP_IV_SPACE);
+		memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
+			hdrlen);
+		skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
 	}
 
 	wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
@@ -1012,9 +1005,9 @@
 			    info->control.hw_key->cipher ==
 			    WLAN_CIPHER_SUITE_TKIP) {
 				int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-				memmove(skb->data + WL1271_TKIP_IV_SPACE,
+				memmove(skb->data + WL1271_EXTRA_SPACE_TKIP,
 					skb->data, hdrlen);
-				skb_pull(skb, WL1271_TKIP_IV_SPACE);
+				skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
 			}
 
 			info->status.rates[0].idx = -1;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 2dbb24e..e3977b5 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -39,6 +39,7 @@
 #define TX_HW_ATTR_LAST_WORD_PAD         (BIT(10) | BIT(11))
 #define TX_HW_ATTR_TX_CMPLT_REQ          BIT(12)
 #define TX_HW_ATTR_TX_DUMMY_REQ          BIT(13)
+#define TX_HW_ATTR_HOST_ENCRYPT          BIT(14)
 
 #define TX_HW_ATTR_OFST_SAVE_RETRIES     0
 #define TX_HW_ATTR_OFST_HEADER_PAD       1
@@ -51,7 +52,9 @@
 #define TX_HW_RESULT_QUEUE_LEN_MASK      0xf
 
 #define WL1271_TX_ALIGN_TO 4
-#define WL1271_TKIP_IV_SPACE 4
+#define WL1271_EXTRA_SPACE_TKIP 4
+#define WL1271_EXTRA_SPACE_AES  8
+#define WL1271_EXTRA_SPACE_MAX  8
 
 /* Used for management frames and dummy packets */
 #define WL1271_TID_MGMT 7
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index b2b09cd..9035241 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -35,8 +35,14 @@
 #include "conf.h"
 #include "ini.h"
 
-#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin"
-#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"
+#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
+#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
+
+#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
+#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
+
+#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
+#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
 
 /*
  * wl127x and wl128x are using the same NVS file name. However, the
@@ -90,7 +96,13 @@
 enum wl1271_state {
 	WL1271_STATE_OFF,
 	WL1271_STATE_ON,
-	WL1271_STATE_PLT,
+};
+
+enum wl12xx_fw_type {
+	WL12XX_FW_TYPE_NONE,
+	WL12XX_FW_TYPE_NORMAL,
+	WL12XX_FW_TYPE_MULTI,
+	WL12XX_FW_TYPE_PLT,
 };
 
 enum wl1271_partition_type {
@@ -247,6 +259,7 @@
 	WL1271_FLAG_PENDING_WORK,
 	WL1271_FLAG_SOFT_GEMINI,
 	WL1271_FLAG_RECOVERY_IN_PROGRESS,
+	WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
 };
 
 enum wl12xx_vif_flags {
@@ -254,8 +267,7 @@
 	WLVIF_FLAG_STA_ASSOCIATED,
 	WLVIF_FLAG_IBSS_JOINED,
 	WLVIF_FLAG_AP_STARTED,
-	WLVIF_FLAG_PSM,
-	WLVIF_FLAG_PSM_REQUESTED,
+	WLVIF_FLAG_IN_PS,
 	WLVIF_FLAG_STA_STATE_SENT,
 	WLVIF_FLAG_RX_STREAMING_STARTED,
 	WLVIF_FLAG_PSPOLL_FAILURE,
@@ -295,6 +307,9 @@
 	spinlock_t wl_lock;
 
 	enum wl1271_state state;
+	enum wl12xx_fw_type fw_type;
+	bool plt;
+	u8 last_vif_count;
 	struct mutex mutex;
 
 	unsigned long flags;
@@ -313,7 +328,12 @@
 
 	s8 hw_pg_ver;
 
-	u8 mac_addr[ETH_ALEN];
+	/* address read from the fuse ROM */
+	u32 fuse_oui_addr;
+	u32 fuse_nic_addr;
+
+	/* we have up to 2 MAC addresses */
+	struct mac_address addresses[2];
 	int channel;
 	u8 system_hlid;
 
@@ -425,8 +445,6 @@
 	struct wl12xx_fw_status *fw_status;
 	struct wl1271_tx_hw_res_if *tx_res_if;
 
-	struct ieee80211_vif *vif;
-
 	/* Current chipset configuration */
 	struct conf_drv_settings conf;
 
@@ -503,6 +521,8 @@
 			u8 basic_rate_idx;
 			u8 ap_rate_idx;
 			u8 p2p_rate_idx;
+
+			bool qos;
 		} sta;
 		struct {
 			u8 global_hlid;
@@ -560,12 +580,6 @@
 	/* Session counter for the chipset */
 	int session_counter;
 
-	struct completion *ps_compl;
-	struct delayed_work pspoll_work;
-
-	/* counter for ps-poll delivery failures */
-	int ps_poll_failures;
-
 	/* retry counter for PSM entries */
 	u8 psm_entry_retry;
 
@@ -575,6 +589,10 @@
 	int rssi_thold;
 	int last_rssi_event;
 
+	/* save the current encryption type for auto-arp config */
+	u8 encryption_type;
+	__be32 ip_addr;
+
 	/* RX BA constraint value */
 	bool ba_support;
 	bool ba_allowed;
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 8f0ffaf..22b0bc9 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -117,7 +117,7 @@
 } __packed;
 
 struct wl12xx_arp_rsp_template {
-	struct ieee80211_hdr_3addr hdr;
+	/* not including ieee80211 header */
 
 	u8 llc_hdr[sizeof(rfc1042_header)];
 	__be16 llc_type;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 98a574a..9fcde36 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -306,9 +306,19 @@
 	r = set_mc_hash(mac);
 	if (r)
 		goto disable_int;
+
+	/* Wait after setting the multicast hash table and powering on
+	 * the radio otherwise interface bring up will fail. This matches
+	 * what the vendor driver did.
+	 */
+	msleep(10);
+
 	r = zd_chip_switch_radio_on(chip);
-	if (r < 0)
+	if (r < 0) {
+		dev_err(zd_chip_dev(chip),
+			"%s: failed to set radio on\n", __func__);
 		goto disable_int;
+	}
 	r = zd_chip_enable_rxtx(chip);
 	if (r < 0)
 		goto disable_radio;
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index ad56e21..be35a68 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -156,21 +156,23 @@
  * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
  *	or %NL80211_ATTR_MAC.
  *
- * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
- *	%NL80222_CMD_NEW_BEACON message)
- * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
- *	using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
- *	%NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
- *	Following attributes are provided for drivers that generate full Beacon
- *	and Probe Response frames internally: %NL80211_ATTR_SSID,
+ * @NL80211_CMD_GET_BEACON: (not used)
+ * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface
+ *	using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL
+ *	attributes. For drivers that generate the beacon and probe responses
+ *	internally, the following attributes must be provided: %NL80211_ATTR_IE,
+ *	%NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP.
+ * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters
+ *	are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
+ *	do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
+ *	%NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
  *	%NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
  *	%NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
- *	%NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
- *	%NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
- *	%NL80211_ATTR_IE_ASSOC_RESP.
- * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
- *	parameters are like for %NL80211_CMD_SET_BEACON.
- * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *	%NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY and
+ *	%NL80211_ATTR_AUTH_TYPE.
+ * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
+ * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
+ * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
  *
  * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
  *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
@@ -565,8 +567,10 @@
 
 	NL80211_CMD_GET_BEACON,
 	NL80211_CMD_SET_BEACON,
-	NL80211_CMD_NEW_BEACON,
-	NL80211_CMD_DEL_BEACON,
+	NL80211_CMD_START_AP,
+	NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP,
+	NL80211_CMD_STOP_AP,
+	NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP,
 
 	NL80211_CMD_GET_STATION,
 	NL80211_CMD_SET_STATION,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e0c9ff3..0178c74 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -366,25 +366,13 @@
 };
 
 /**
- * struct beacon_parameters - beacon parameters
- *
- * Used to configure the beacon for an interface.
- *
+ * struct cfg80211_beacon_data - beacon data
  * @head: head portion of beacon (before TIM IE)
  *     or %NULL if not changed
  * @tail: tail portion of beacon (after TIM IE)
  *     or %NULL if not changed
- * @interval: beacon interval or zero if not changed
- * @dtim_period: DTIM period or zero if not changed
  * @head_len: length of @head
  * @tail_len: length of @tail
- * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
- *	user space)
- * @ssid_len: length of @ssid
- * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
- * @crypto: crypto settings
- * @privacy: the BSS uses privacy
- * @auth_type: Authentication type (algorithm)
  * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL
  * @beacon_ies_len: length of beacon_ies in octets
  * @proberesp_ies: extra information element(s) to add into Probe Response
@@ -396,24 +384,46 @@
  * @probe_resp_len: length of probe response template (@probe_resp)
  * @probe_resp: probe response template (AP mode only)
  */
-struct beacon_parameters {
-	u8 *head, *tail;
-	int interval, dtim_period;
-	int head_len, tail_len;
+struct cfg80211_beacon_data {
+	const u8 *head, *tail;
+	const u8 *beacon_ies;
+	const u8 *proberesp_ies;
+	const u8 *assocresp_ies;
+	const u8 *probe_resp;
+
+	size_t head_len, tail_len;
+	size_t beacon_ies_len;
+	size_t proberesp_ies_len;
+	size_t assocresp_ies_len;
+	size_t probe_resp_len;
+};
+
+/**
+ * struct cfg80211_ap_settings - AP configuration
+ *
+ * Used to configure an AP interface.
+ *
+ * @beacon: beacon data
+ * @beacon_interval: beacon interval
+ * @dtim_period: DTIM period
+ * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
+ *	user space)
+ * @ssid_len: length of @ssid
+ * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
+ * @crypto: crypto settings
+ * @privacy: the BSS uses privacy
+ * @auth_type: Authentication type (algorithm)
+ */
+struct cfg80211_ap_settings {
+	struct cfg80211_beacon_data beacon;
+
+	int beacon_interval, dtim_period;
 	const u8 *ssid;
 	size_t ssid_len;
 	enum nl80211_hidden_ssid hidden_ssid;
 	struct cfg80211_crypto_settings crypto;
 	bool privacy;
 	enum nl80211_auth_type auth_type;
-	const u8 *beacon_ies;
-	size_t beacon_ies_len;
-	const u8 *proberesp_ies;
-	size_t proberesp_ies_len;
-	const u8 *assocresp_ies;
-	size_t assocresp_ies_len;
-	int probe_resp_len;
-	u8 *probe_resp;
 };
 
 /**
@@ -1518,11 +1528,11 @@
 					struct net_device *netdev,
 					u8 key_index);
 
-	int	(*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
-			      struct beacon_parameters *info);
-	int	(*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
-			      struct beacon_parameters *info);
-	int	(*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
+	int	(*start_ap)(struct wiphy *wiphy, struct net_device *dev,
+			    struct cfg80211_ap_settings *settings);
+	int	(*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
+				 struct cfg80211_beacon_data *info);
+	int	(*stop_ap)(struct wiphy *wiphy, struct net_device *dev);
 
 
 	int	(*add_station)(struct wiphy *wiphy, struct net_device *dev,
@@ -1577,11 +1587,9 @@
 	int	(*assoc)(struct wiphy *wiphy, struct net_device *dev,
 			 struct cfg80211_assoc_request *req);
 	int	(*deauth)(struct wiphy *wiphy, struct net_device *dev,
-			  struct cfg80211_deauth_request *req,
-			  void *cookie);
+			  struct cfg80211_deauth_request *req);
 	int	(*disassoc)(struct wiphy *wiphy, struct net_device *dev,
-			    struct cfg80211_disassoc_request *req,
-			    void *cookie);
+			    struct cfg80211_disassoc_request *req);
 
 	int	(*connect)(struct wiphy *wiphy, struct net_device *dev,
 			   struct cfg80211_connect_params *sme);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cbff4f9..7477f02 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -341,9 +341,9 @@
  *	used to indicate that a frame was already retried due to PS
  * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
  *	used to indicate frame should not be encrypted
- * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll
- *	frame (PS-Poll or uAPSD) and should be sent although the station
- *	is in powersave mode.
+ * @IEEE80211_TX_CTL_NO_PS_BUFFER: This frame is a response to a poll
+ *	frame (PS-Poll or uAPSD) or a non-bufferable MMPDU and must
+ *	be sent although the station is in powersave mode.
  * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the
  *	transmit function after the current frame, this can be used
  *	by drivers to kick the DMA queue only if unset or when the
@@ -399,7 +399,7 @@
 	IEEE80211_TX_INTFL_NEED_TXPROCESSING	= BIT(14),
 	IEEE80211_TX_INTFL_RETRIED		= BIT(15),
 	IEEE80211_TX_INTFL_DONT_ENCRYPT		= BIT(16),
-	IEEE80211_TX_CTL_POLL_RESPONSE		= BIT(17),
+	IEEE80211_TX_CTL_NO_PS_BUFFER		= BIT(17),
 	IEEE80211_TX_CTL_MORE_FRAMES		= BIT(18),
 	IEEE80211_TX_INTFL_RETRANSMISSION	= BIT(19),
 	/* hole at 20, use later */
@@ -425,7 +425,7 @@
 	IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU |	      \
 	IEEE80211_TX_STAT_TX_FILTERED |	IEEE80211_TX_STAT_ACK |		      \
 	IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK |	      \
-	IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE |   \
+	IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_NO_PS_BUFFER |    \
 	IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC |		      \
 	IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
 
@@ -1634,7 +1634,7 @@
  * the station sends a PS-Poll or a uAPSD trigger frame, mac80211
  * will inform the driver of this with the @allow_buffered_frames
  * callback; this callback is optional. mac80211 will then transmit
- * the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE
+ * the frames as usual and set the %IEEE80211_TX_CTL_NO_PS_BUFFER
  * on each frame. The last frame in the service period (or the only
  * response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to
  * indicate that it ends the service period; as this frame must have
@@ -1642,6 +1642,9 @@
  * When TX status is reported for this frame, the service period is
  * marked has having ended and a new one can be started by the peer.
  *
+ * Additionally, non-bufferable MMPDUs can also be transmitted by
+ * mac80211 with the %IEEE80211_TX_CTL_NO_PS_BUFFER set in them.
+ *
  * Another race condition can happen on some devices like iwlwifi
  * when there are frames queued for the station and it wakes up
  * or polls; the frames that are already queued could end up being
@@ -2140,7 +2143,7 @@
  * @allow_buffered_frames: Prepare device to allow the given number of frames
  *	to go out to the given station. The frames will be sent by mac80211
  *	via the usual TX path after this call. The TX information for frames
- *	released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set
+ *	released will also have the %IEEE80211_TX_CTL_NO_PS_BUFFER flag set
  *	and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case
  *	frames from multiple TIDs are released and the driver might reorder
  *	them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c3de921..6a77d4c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -489,27 +489,13 @@
 	return ret;
 }
 
-static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
-				     struct beacon_parameters *params)
-{
-	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-
-	bss_conf->ssid_len = params->ssid_len;
-
-	if (params->ssid_len)
-		memcpy(bss_conf->ssid, params->ssid, params->ssid_len);
-
-	bss_conf->hidden_ssid =
-		(params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
-}
-
 static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
-				    u8 *resp, size_t resp_len)
+				    const u8 *resp, size_t resp_len)
 {
 	struct sk_buff *new, *old;
 
 	if (!resp || !resp_len)
-		return -EINVAL;
+		return 1;
 
 	old = rtnl_dereference(sdata->u.ap.probe_resp);
 
@@ -520,50 +506,28 @@
 	memcpy(skb_put(new, resp_len), resp, resp_len);
 
 	rcu_assign_pointer(sdata->u.ap.probe_resp, new);
-	synchronize_rcu();
-
-	if (old)
+	if (old) {
+		/* TODO: use call_rcu() */
+		synchronize_rcu();
 		dev_kfree_skb(old);
+	}
 
 	return 0;
 }
 
-/*
- * This handles both adding a beacon and setting new beacon info
- */
-static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
-				   struct beacon_parameters *params)
+static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+				   struct cfg80211_beacon_data *params)
 {
 	struct beacon_data *new, *old;
 	int new_head_len, new_tail_len;
-	int size;
-	int err = -EINVAL;
-	u32 changed = 0;
+	int size, err;
+	u32 changed = BSS_CHANGED_BEACON;
 
 	old = rtnl_dereference(sdata->u.ap.beacon);
 
-	/* head must not be zero-length */
-	if (params->head && !params->head_len)
-		return -EINVAL;
-
-	/*
-	 * This is a kludge. beacon interval should really be part
-	 * of the beacon information.
-	 */
-	if (params->interval &&
-	    (sdata->vif.bss_conf.beacon_int != params->interval)) {
-		sdata->vif.bss_conf.beacon_int = params->interval;
-		ieee80211_bss_info_change_notify(sdata,
-						 BSS_CHANGED_BEACON_INT);
-	}
-
 	/* Need to have a beacon head if we don't have one yet */
 	if (!params->head && !old)
-		return err;
-
-	/* sorry, no way to start beaconing without dtim period */
-	if (!params->dtim_period && !old)
-		return err;
+		return -EINVAL;
 
 	/* new or old head? */
 	if (params->head)
@@ -586,12 +550,6 @@
 
 	/* start filling the new info now */
 
-	/* new or old dtim period? */
-	if (params->dtim_period)
-		new->dtim_period = params->dtim_period;
-	else
-		new->dtim_period = old->dtim_period;
-
 	/*
 	 * pointers go into the block we allocated,
 	 * memory is | beacon_data | head | tail |
@@ -614,46 +572,37 @@
 		if (old)
 			memcpy(new->tail, old->tail, new_tail_len);
 
-	sdata->vif.bss_conf.dtim_period = new->dtim_period;
+	err = ieee80211_set_probe_resp(sdata, params->probe_resp,
+				       params->probe_resp_len);
+	if (err < 0)
+		return err;
+	if (err == 0)
+		changed |= BSS_CHANGED_AP_PROBE_RESP;
 
 	rcu_assign_pointer(sdata->u.ap.beacon, new);
 
-	synchronize_rcu();
+	if (old)
+		kfree_rcu(old, rcu_head);
 
-	kfree(old);
-
-	err = ieee80211_set_probe_resp(sdata, params->probe_resp,
-				       params->probe_resp_len);
-	if (!err)
-		changed |= BSS_CHANGED_AP_PROBE_RESP;
-
-	ieee80211_config_ap_ssid(sdata, params);
-	changed |= BSS_CHANGED_BEACON_ENABLED |
-		   BSS_CHANGED_BEACON |
-		   BSS_CHANGED_SSID;
-
-	ieee80211_bss_info_change_notify(sdata, changed);
-	return 0;
+	return changed;
 }
 
-static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
-				struct beacon_parameters *params)
+static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
+			      struct cfg80211_ap_settings *params)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct beacon_data *old;
 	struct ieee80211_sub_if_data *vlan;
-	int ret;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	u32 changed = BSS_CHANGED_BEACON_INT |
+		      BSS_CHANGED_BEACON_ENABLED |
+		      BSS_CHANGED_BEACON |
+		      BSS_CHANGED_SSID;
+	int err;
 
 	old = rtnl_dereference(sdata->u.ap.beacon);
 	if (old)
 		return -EALREADY;
 
-	ret = ieee80211_config_beacon(sdata, params);
-	if (ret)
-		return ret;
-
 	/*
 	 * Apply control port protocol, this allows us to
 	 * not encrypt dynamic WEP control frames.
@@ -667,14 +616,32 @@
 			params->crypto.control_port_no_encrypt;
 	}
 
+	sdata->vif.bss_conf.beacon_int = params->beacon_interval;
+	sdata->vif.bss_conf.dtim_period = params->dtim_period;
+
+	sdata->vif.bss_conf.ssid_len = params->ssid_len;
+	if (params->ssid_len)
+		memcpy(sdata->vif.bss_conf.ssid, params->ssid,
+		       params->ssid_len);
+	sdata->vif.bss_conf.hidden_ssid =
+		(params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
+
+	err = ieee80211_assign_beacon(sdata, &params->beacon);
+	if (err < 0)
+		return err;
+	changed |= err;
+
+	ieee80211_bss_info_change_notify(sdata, changed);
+
 	return 0;
 }
 
-static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
-				struct beacon_parameters *params)
+static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
+				   struct cfg80211_beacon_data *params)
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct beacon_data *old;
+	int err;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -682,10 +649,14 @@
 	if (!old)
 		return -ENOENT;
 
-	return ieee80211_config_beacon(sdata, params);
+	err = ieee80211_assign_beacon(sdata, params);
+	if (err < 0)
+		return err;
+	ieee80211_bss_info_change_notify(sdata, err);
+	return 0;
 }
 
-static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct beacon_data *old;
@@ -697,10 +668,11 @@
 		return -ENOENT;
 
 	RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
-	synchronize_rcu();
-	kfree(old);
+
+	kfree_rcu(old, rcu_head);
 
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+
 	return 0;
 }
 
@@ -1623,19 +1595,15 @@
 }
 
 static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
-			    struct cfg80211_deauth_request *req,
-			    void *cookie)
+			    struct cfg80211_deauth_request *req)
 {
-	return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev),
-				    req, cookie);
+	return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
-			      struct cfg80211_disassoc_request *req,
-			      void *cookie)
+			      struct cfg80211_disassoc_request *req)
 {
-	return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev),
-				      req, cookie);
+	return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
@@ -2699,9 +2667,9 @@
 	.get_key = ieee80211_get_key,
 	.set_default_key = ieee80211_config_default_key,
 	.set_default_mgmt_key = ieee80211_config_default_mgmt_key,
-	.add_beacon = ieee80211_add_beacon,
-	.set_beacon = ieee80211_set_beacon,
-	.del_beacon = ieee80211_del_beacon,
+	.start_ap = ieee80211_start_ap,
+	.change_beacon = ieee80211_change_beacon,
+	.stop_ap = ieee80211_stop_ap,
 	.add_station = ieee80211_add_station,
 	.del_station = ieee80211_del_station,
 	.change_station = ieee80211_change_station,
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 8361da4..7f9ac57 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -20,7 +20,6 @@
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <net/mac80211.h>
-#include <asm/unaligned.h>
 
 #include "ieee80211_i.h"
 #include "driver-ops.h"
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 74594f0..cee0c74 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -228,7 +228,7 @@
 struct beacon_data {
 	u8 *head, *tail;
 	int head_len, tail_len;
-	int dtim_period;
+	struct rcu_head rcu_head;
 };
 
 struct ieee80211_if_ap {
@@ -1128,12 +1128,6 @@
 	return container_of(hw, struct ieee80211_local, hw);
 }
 
-static inline struct ieee80211_hw *local_to_hw(
-	struct ieee80211_local *local)
-{
-	return &local->hw;
-}
-
 
 static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 {
@@ -1156,11 +1150,9 @@
 int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 			struct cfg80211_assoc_request *req);
 int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
-			 struct cfg80211_deauth_request *req,
-			 void *cookie);
+			 struct cfg80211_deauth_request *req);
 int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
-			   struct cfg80211_disassoc_request *req,
-			   void *cookie);
+			   struct cfg80211_disassoc_request *req);
 void ieee80211_send_pspoll(struct ieee80211_local *local,
 			   struct ieee80211_sub_if_data *sdata);
 void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
@@ -1178,6 +1170,7 @@
 				  struct sk_buff *skb);
 void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
+void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata);
 
 /* IBSS code */
 void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index daa50ea..620ca8d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -644,6 +644,8 @@
 
 	if (ieee80211_vif_is_mesh(&sdata->vif))
 		mesh_rmc_free(sdata);
+	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		ieee80211_mgd_teardown(sdata);
 
 	flushed = sta_info_flush(local, sdata);
 	WARN_ON(flushed);
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index e8616b3..5bb600d 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <net/mac80211.h>
+#include <asm/unaligned.h>
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 #include "debugfs_key.h"
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 2306d75..36fa805 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -286,11 +286,11 @@
 			/* Clear skb->pkt_type in order to not confuse kernel
 			 * netstack. */
 			skb->pkt_type = 0;
-			ieee80211_rx(local_to_hw(local), skb);
+			ieee80211_rx(&local->hw, skb);
 			break;
 		case IEEE80211_TX_STATUS_MSG:
 			skb->pkt_type = 0;
-			ieee80211_tx_status(local_to_hw(local), skb);
+			ieee80211_tx_status(&local->hw, skb);
 			break;
 		case IEEE80211_EOSP_MSG:
 			eosp_data = (void *)skb->cb;
@@ -668,7 +668,7 @@
 
 	ieee80211_hw_roc_setup(local);
 
-	return local_to_hw(local);
+	return &local->hw;
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
 
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index bd14bd2..c7e5c49 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -13,7 +13,6 @@
 
 #include <linux/types.h>
 #include <linux/jhash.h>
-#include <asm/unaligned.h>
 #include "ieee80211_i.h"
 
 
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index c27dec9..31bc762 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/slab.h>
+#include <asm/unaligned.h>
 #include "wme.h"
 #include "mesh.h"
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 52133da..caf97f5 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -88,6 +88,8 @@
 #define TMR_RUNNING_TIMER	0
 #define TMR_RUNNING_CHANSW	1
 
+#define DEAUTH_DISASSOC_LEN	(24 /* hdr */ + 2 /* reason */)
+
 /*
  * All cfg80211 functions have to be called outside a locked
  * section so that they can acquire a lock themselves... This
@@ -612,47 +614,42 @@
 }
 
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
-					   const u8 *bssid, u16 stype, u16 reason,
-					   void *cookie, bool send_frame)
+					   const u8 *bssid, u16 stype,
+					   u16 reason, bool send_frame,
+					   u8 *frame_buf)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_mgmt *mgmt = (void *)frame_buf;
 
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
-	if (!skb)
-		return;
-
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
+	/* build frame */
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
+	mgmt->duration = 0; /* initialize only */
+	mgmt->seq_ctrl = 0; /* initialize only */
 	memcpy(mgmt->da, bssid, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
-	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
-	skb_put(skb, 2);
 	/* u.deauth.reason_code == u.disassoc.reason_code */
 	mgmt->u.deauth.reason_code = cpu_to_le16(reason);
 
-	if (stype == IEEE80211_STYPE_DEAUTH)
-		if (cookie)
-			__cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
-		else
-			cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
-	else
-		if (cookie)
-			__cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
-		else
-			cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
-	if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
-		IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	if (send_frame) {
+		skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+				    DEAUTH_DISASSOC_LEN);
+		if (!skb)
+			return;
 
-	if (send_frame)
+		skb_reserve(skb, local->hw.extra_tx_headroom);
+
+		/* copy in frame */
+		memcpy(skb_put(skb, DEAUTH_DISASSOC_LEN),
+		       mgmt, DEAUTH_DISASSOC_LEN);
+
+		if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
+			IEEE80211_SKB_CB(skb)->flags |=
+				IEEE80211_TX_INTFL_DONT_ENCRYPT;
 		ieee80211_tx_skb(sdata, skb);
-	else
-		kfree_skb(skb);
+	}
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -1392,7 +1389,8 @@
 }
 
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-				   bool remove_sta, bool tx)
+				   u16 stype, u16 reason, bool tx,
+				   u8 *frame_buf)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
@@ -1402,6 +1400,9 @@
 
 	ASSERT_MGD_MTX(ifmgd);
 
+	if (WARN_ON_ONCE(tx && !frame_buf))
+		return;
+
 	if (WARN_ON(!ifmgd->associated))
 		return;
 
@@ -1435,6 +1436,19 @@
 	}
 	mutex_unlock(&local->sta_mtx);
 
+	/* deauthenticate/disassociate now */
+	if (tx || frame_buf)
+		ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason,
+					       tx, frame_buf);
+
+	/* flush out frame */
+	if (tx)
+		drv_flush(local, false);
+
+	/* remove AP and TDLS peers */
+	sta_info_flush(local, sdata);
+
+	/* finally reset all BSS / config parameters */
 	changed |= ieee80211_reset_erp_info(sdata);
 
 	ieee80211_led_assoc(local, 0);
@@ -1474,10 +1488,6 @@
 	changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
 	ieee80211_bss_info_change_notify(sdata, changed);
 
-	/* remove AP and TDLS peers */
-	if (remove_sta)
-		sta_info_flush(local, sdata);
-
 	del_timer_sync(&sdata->u.mgd.conn_mon_timer);
 	del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
 	del_timer_sync(&sdata->u.mgd.timer);
@@ -1674,6 +1684,7 @@
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
 	u8 bssid[ETH_ALEN];
+	u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
 	mutex_lock(&ifmgd->mtx);
 	if (!ifmgd->associated) {
@@ -1686,17 +1697,16 @@
 	printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n",
 	       sdata->name, bssid);
 
-	ieee80211_set_disassoc(sdata, true, true);
+	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+			       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+			       false, frame_buf);
 	mutex_unlock(&ifmgd->mtx);
 
 	/*
 	 * must be outside lock due to cfg80211,
 	 * but that's not a problem.
 	 */
-	ieee80211_send_deauth_disassoc(sdata, bssid,
-				       IEEE80211_STYPE_DEAUTH,
-				       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-				       NULL, true);
+	cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
 
 	mutex_lock(&local->mtx);
 	ieee80211_recalc_idle(local);
@@ -1903,7 +1913,8 @@
 	printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
 			sdata->name, bssid, reason_code);
 
-	ieee80211_set_disassoc(sdata, true, false);
+	ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
+
 	mutex_lock(&sdata->local->mtx);
 	ieee80211_recalc_idle(sdata->local);
 	mutex_unlock(&sdata->local->mtx);
@@ -1933,10 +1944,12 @@
 	printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
 			sdata->name, mgmt->sa, reason_code);
 
-	ieee80211_set_disassoc(sdata, true, false);
+	ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
+
 	mutex_lock(&sdata->local->mtx);
 	ieee80211_recalc_idle(sdata->local);
 	mutex_unlock(&sdata->local->mtx);
+
 	return RX_MGMT_CFG80211_DISASSOC;
 }
 
@@ -2238,14 +2251,28 @@
 	} else {
 		printk(KERN_DEBUG "%s: associated\n", sdata->name);
 
-		ieee80211_destroy_assoc_data(sdata, true);
+		/* tell driver about sync done first */
+		if (assoc_data->synced) {
+			drv_finish_tx_sync(sdata->local, sdata,
+					   assoc_data->bss->bssid,
+					   IEEE80211_TX_SYNC_ASSOC);
+			assoc_data->synced = false;
+		}
 
 		if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
 			/* oops -- internal error -- send timeout for now */
+			ieee80211_destroy_assoc_data(sdata, true);
 			sta_info_destroy_addr(sdata, mgmt->bssid);
 			cfg80211_put_bss(*bss);
 			return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
 		}
+
+		/*
+		 * destroy assoc_data afterwards, as otherwise an idle
+		 * recalc after assoc_data is NULL but before associated
+		 * is set can cause the interface to go idle
+		 */
+		ieee80211_destroy_assoc_data(sdata, true);
 	}
 
 	return RX_MGMT_CFG80211_RX_ASSOC;
@@ -2681,19 +2708,20 @@
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
 	ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
 			  IEEE80211_STA_BEACON_POLL);
 
-	ieee80211_set_disassoc(sdata, true, true);
+	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
+			       false, frame_buf);
 	mutex_unlock(&ifmgd->mtx);
+
 	/*
 	 * must be outside lock due to cfg80211,
 	 * but that's not a problem.
 	 */
-	ieee80211_send_deauth_disassoc(sdata, bssid,
-			IEEE80211_STYPE_DEAUTH, reason,
-			NULL, true);
+	cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
 
 	mutex_lock(&local->mtx);
 	ieee80211_recalc_idle(local);
@@ -2974,13 +3002,17 @@
 
 static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
 {
+	u32 flags;
+
 	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 		sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL |
 					IEEE80211_STA_CONNECTION_POLL);
 
 		/* let's probe the connection once */
-		ieee80211_queue_work(&sdata->local->hw,
-			   &sdata->u.mgd.monitor_work);
+		flags = sdata->local->hw.flags;
+		if (!(flags & IEEE80211_HW_CONNECTION_MONITOR))
+			ieee80211_queue_work(&sdata->local->hw,
+					     &sdata->u.mgd.monitor_work);
 		/* and do all the other regular work too */
 		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 	}
@@ -3044,7 +3076,6 @@
 		add_timer(&ifmgd->chswitch_timer);
 	ieee80211_sta_reset_beacon_monitor(sdata);
 	ieee80211_restart_sta_timer(sdata);
-	ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work);
 }
 #endif
 
@@ -3174,7 +3205,7 @@
 	ifmgd->auth_data = auth_data;
 
 	if (ifmgd->associated)
-		ieee80211_set_disassoc(sdata, true, false);
+		ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
 	printk(KERN_DEBUG "%s: authenticate with %pM\n",
 	       sdata->name, req->bss->bssid);
@@ -3252,7 +3283,7 @@
 	mutex_lock(&ifmgd->mtx);
 
 	if (ifmgd->associated)
-		ieee80211_set_disassoc(sdata, true, false);
+		ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
 	if (ifmgd->auth_data && !ifmgd->auth_data->done) {
 		err = -EBUSY;
@@ -3422,32 +3453,35 @@
 }
 
 int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
-			 struct cfg80211_deauth_request *req,
-			 void *cookie)
+			 struct cfg80211_deauth_request *req)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	bool assoc_bss = false;
+	u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
 	mutex_lock(&ifmgd->mtx);
 
-	if (ifmgd->associated &&
-	    memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) {
-		ieee80211_set_disassoc(sdata, false, true);
-		assoc_bss = true;
-	} else if (ifmgd->auth_data) {
+	if (ifmgd->auth_data) {
 		ieee80211_destroy_auth_data(sdata, false);
 		mutex_unlock(&ifmgd->mtx);
 		return 0;
 	}
-	mutex_unlock(&ifmgd->mtx);
 
-	printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
+	printk(KERN_DEBUG
+	       "%s: deauthenticating from %pM by local choice (reason=%d)\n",
 	       sdata->name, req->bssid, req->reason_code);
 
-	ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH,
-				       req->reason_code, cookie, true);
-	if (assoc_bss)
-		sta_info_flush(sdata->local, sdata);
+	if (ifmgd->associated &&
+	    memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0)
+		ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+				       req->reason_code, true, frame_buf);
+	else
+		ieee80211_send_deauth_disassoc(sdata, req->bssid,
+					       IEEE80211_STYPE_DEAUTH,
+					       req->reason_code, true,
+					       frame_buf);
+	mutex_unlock(&ifmgd->mtx);
+
+	__cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
 
 	mutex_lock(&sdata->local->mtx);
 	ieee80211_recalc_idle(sdata->local);
@@ -3457,11 +3491,11 @@
 }
 
 int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
-			   struct cfg80211_disassoc_request *req,
-			   void *cookie)
+			   struct cfg80211_disassoc_request *req)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	u8 bssid[ETH_ALEN];
+	u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
 	mutex_lock(&ifmgd->mtx);
 
@@ -3480,14 +3514,12 @@
 	       sdata->name, req->bss->bssid, req->reason_code);
 
 	memcpy(bssid, req->bss->bssid, ETH_ALEN);
-	ieee80211_set_disassoc(sdata, false, true);
-
+	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
+			       req->reason_code, !req->local_state_change,
+			       frame_buf);
 	mutex_unlock(&ifmgd->mtx);
 
-	ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
-			IEEE80211_STYPE_DISASSOC, req->reason_code,
-			cookie, !req->local_state_change);
-	sta_info_flush(sdata->local, sdata);
+	__cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
 
 	mutex_lock(&sdata->local->mtx);
 	ieee80211_recalc_idle(sdata->local);
@@ -3496,6 +3528,19 @@
 	return 0;
 }
 
+void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+	mutex_lock(&ifmgd->mtx);
+	if (ifmgd->assoc_data)
+		ieee80211_destroy_assoc_data(sdata, false);
+	if (ifmgd->auth_data)
+		ieee80211_destroy_auth_data(sdata, false);
+	del_timer_sync(&ifmgd->timer);
+	mutex_unlock(&ifmgd->mtx);
+}
+
 void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 			       enum nl80211_cqm_rssi_threshold_event rssi_event,
 			       gfp_t gfp)
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 2b53a53..ef8eba1 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -102,7 +102,7 @@
 
 			state = sta->sta_state;
 			for (; state > IEEE80211_STA_NOTEXIST; state--)
-				WARN_ON(drv_sta_state(local, sdata, sta,
+				WARN_ON(drv_sta_state(local, sta->sdata, sta,
 						      state, state - 1));
 		}
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 3ab85c0..7a4ff02 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -19,6 +19,7 @@
 #include <linux/export.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
+#include <asm/unaligned.h>
 
 #include "ieee80211_i.h"
 #include "driver-ops.h"
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 4034ee61..cd0f265 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -865,8 +865,10 @@
 
 	mutex_lock(&local->sta_mtx);
 	list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
-		if (!sdata || sdata == sta->sdata)
+		if (!sdata || sdata == sta->sdata) {
 			WARN_ON(__sta_info_destroy(sta));
+			ret++;
+		}
 	}
 	mutex_unlock(&local->sta_mtx);
 
@@ -1048,7 +1050,7 @@
 	 * exchange. Also set EOSP to indicate this packet
 	 * ends the poll/service period.
 	 */
-	info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE |
+	info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
 		       IEEE80211_TX_STATUS_EOSP |
 		       IEEE80211_TX_CTL_REQ_TX_STATUS;
 
@@ -1175,7 +1177,7 @@
 			 * STA may still remain is PS mode after this frame
 			 * exchange.
 			 */
-			info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
+			info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
 
 			/*
 			 * Use MoreData flag to indicate whether there are
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index d67f0b9..c928e4a 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -11,6 +11,7 @@
 
 #include <linux/export.h>
 #include <net/mac80211.h>
+#include <asm/unaligned.h>
 #include "ieee80211_i.h"
 #include "rate.h"
 #include "mesh.h"
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1be0ca2..570737d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -448,18 +448,23 @@
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 	struct ieee80211_local *local = tx->local;
 
-	if (unlikely(!sta ||
-		     ieee80211_is_probe_resp(hdr->frame_control) ||
-		     ieee80211_is_auth(hdr->frame_control) ||
-		     ieee80211_is_assoc_resp(hdr->frame_control) ||
-		     ieee80211_is_reassoc_resp(hdr->frame_control)))
+	if (unlikely(!sta))
 		return TX_CONTINUE;
 
 	if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
 		      test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
-		     !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) {
+		     !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
 		int ac = skb_get_queue_mapping(tx->skb);
 
+		/* only deauth, disassoc and action are bufferable MMPDUs */
+		if (ieee80211_is_mgmt(hdr->frame_control) &&
+		    !ieee80211_is_deauth(hdr->frame_control) &&
+		    !ieee80211_is_disassoc(hdr->frame_control) &&
+		    !ieee80211_is_action(hdr->frame_control)) {
+			info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+			return TX_CONTINUE;
+		}
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
 		       sta->sta.addr, sta->sta.aid, ac);
@@ -625,7 +630,7 @@
 			 tx->local->hw.wiphy->frag_threshold);
 
 	/* set up the tx rate control struct we give the RC algo */
-	txrc.hw = local_to_hw(tx->local);
+	txrc.hw = &tx->local->hw;
 	txrc.sband = sband;
 	txrc.bss_conf = &tx->sdata->vif.bss_conf;
 	txrc.skb = tx->skb;
@@ -2206,7 +2211,8 @@
 
 /* functions for drivers to get certain frames */
 
-static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
+static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_if_ap *bss,
 				     struct sk_buff *skb,
 				     struct beacon_data *beacon)
 {
@@ -2223,7 +2229,7 @@
 					  IEEE80211_MAX_AID+1);
 
 	if (bss->dtim_count == 0)
-		bss->dtim_count = beacon->dtim_period - 1;
+		bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
 	else
 		bss->dtim_count--;
 
@@ -2231,7 +2237,7 @@
 	*pos++ = WLAN_EID_TIM;
 	*pos++ = 4;
 	*pos++ = bss->dtim_count;
-	*pos++ = beacon->dtim_period;
+	*pos++ = sdata->vif.bss_conf.dtim_period;
 
 	if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
 		aid0 = 1;
@@ -2324,12 +2330,14 @@
 			 * of the tim bitmap in mac80211 and the driver.
 			 */
 			if (local->tim_in_locked_section) {
-				ieee80211_beacon_add_tim(ap, skb, beacon);
+				ieee80211_beacon_add_tim(sdata, ap, skb,
+							 beacon);
 			} else {
 				unsigned long flags;
 
 				spin_lock_irqsave(&local->tim_lock, flags);
-				ieee80211_beacon_add_tim(ap, skb, beacon);
+				ieee80211_beacon_add_tim(sdata, ap, skb,
+							 beacon);
 				spin_unlock_irqrestore(&local->tim_lock, flags);
 			}
 
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 264397a..f6e4cef 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -753,7 +753,7 @@
 	use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
 		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
 
-	for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
+	for (queue = 0; queue < local->hw.queues; queue++) {
 		/* Set defaults according to 802.11-2007 Table 7-37 */
 		aCWmax = 1023;
 		if (use_11b)
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index d553d36..fb1e721 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -455,7 +455,7 @@
 		return 0;
 	}
 
-	return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+	return rdev->ops->deauth(&rdev->wiphy, dev, &req);
 }
 
 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
@@ -500,7 +500,7 @@
 	else
 		return -ENOTCONN;
 
-	return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
+	return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
 }
 
 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
@@ -541,7 +541,7 @@
 
 	memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
 	req.bssid = bssid;
-	rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+	rdev->ops->deauth(&rdev->wiphy, dev, &req);
 
 	if (wdev->current_bss) {
 		cfg80211_unhold_bss(wdev->current_bss);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fe27476..1998c36 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -871,7 +871,7 @@
 	CMD(add_virtual_intf, NEW_INTERFACE);
 	CMD(change_virtual_intf, SET_INTERFACE);
 	CMD(add_key, NEW_KEY);
-	CMD(add_beacon, NEW_BEACON);
+	CMD(start_ap, START_AP);
 	CMD(add_station, NEW_STATION);
 	CMD(add_mpath, NEW_MPATH);
 	CMD(update_mesh_config, SET_MESH_CONFIG);
@@ -2075,15 +2075,10 @@
 	return err;
 }
 
-static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_parse_beacon(struct genl_info *info,
+				struct cfg80211_beacon_data *bcn)
 {
-        int (*call)(struct wiphy *wiphy, struct net_device *dev,
-		    struct beacon_parameters *info);
-	struct cfg80211_registered_device *rdev = info->user_ptr[0];
-	struct net_device *dev = info->user_ptr[1];
-	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	struct beacon_parameters params;
-	int haveinfo = 0, err;
+	bool haveinfo = false;
 
 	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
 	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
@@ -2091,149 +2086,183 @@
 	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
 		return -EINVAL;
 
-	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
-		return -EOPNOTSUPP;
-
-	memset(&params, 0, sizeof(params));
-
-	switch (info->genlhdr->cmd) {
-	case NL80211_CMD_NEW_BEACON:
-		/* these are required for NEW_BEACON */
-		if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
-		    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
-		    !info->attrs[NL80211_ATTR_BEACON_HEAD])
-			return -EINVAL;
-
-		params.interval =
-			nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
-		params.dtim_period =
-			nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
-
-		err = cfg80211_validate_beacon_int(rdev, params.interval);
-		if (err)
-			return err;
-
-		/*
-		 * In theory, some of these attributes could be required for
-		 * NEW_BEACON, but since they were not used when the command was
-		 * originally added, keep them optional for old user space
-		 * programs to work with drivers that do not need the additional
-		 * information.
-		 */
-		if (info->attrs[NL80211_ATTR_SSID]) {
-			params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
-			params.ssid_len =
-				nla_len(info->attrs[NL80211_ATTR_SSID]);
-			if (params.ssid_len == 0 ||
-			    params.ssid_len > IEEE80211_MAX_SSID_LEN)
-				return -EINVAL;
-		}
-
-		if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
-			params.hidden_ssid = nla_get_u32(
-				info->attrs[NL80211_ATTR_HIDDEN_SSID]);
-			if (params.hidden_ssid !=
-			    NL80211_HIDDEN_SSID_NOT_IN_USE &&
-			    params.hidden_ssid !=
-			    NL80211_HIDDEN_SSID_ZERO_LEN &&
-			    params.hidden_ssid !=
-			    NL80211_HIDDEN_SSID_ZERO_CONTENTS)
-				return -EINVAL;
-		}
-
-		params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
-
-		if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
-			params.auth_type = nla_get_u32(
-				info->attrs[NL80211_ATTR_AUTH_TYPE]);
-			if (!nl80211_valid_auth_type(params.auth_type))
-				return -EINVAL;
-		} else
-			params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-
-		err = nl80211_crypto_settings(rdev, info, &params.crypto,
-					      NL80211_MAX_NR_CIPHER_SUITES);
-		if (err)
-			return err;
-
-		call = rdev->ops->add_beacon;
-		break;
-	case NL80211_CMD_SET_BEACON:
-		call = rdev->ops->set_beacon;
-		break;
-	default:
-		WARN_ON(1);
-		return -EOPNOTSUPP;
-	}
-
-	if (!call)
-		return -EOPNOTSUPP;
+	memset(bcn, 0, sizeof(*bcn));
 
 	if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-		params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-		params.head_len =
-		    nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-		haveinfo = 1;
+		bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+		bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+		if (!bcn->head_len)
+			return -EINVAL;
+		haveinfo = true;
 	}
 
 	if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
-		params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-		params.tail_len =
+		bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+		bcn->tail_len =
 		    nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-		haveinfo = 1;
+		haveinfo = true;
 	}
 
 	if (!haveinfo)
 		return -EINVAL;
 
 	if (info->attrs[NL80211_ATTR_IE]) {
-		params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
-		params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+		bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+		bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
 	}
 
 	if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
-		params.proberesp_ies =
+		bcn->proberesp_ies =
 			nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
-		params.proberesp_ies_len =
+		bcn->proberesp_ies_len =
 			nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
 	}
 
 	if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
-		params.assocresp_ies =
+		bcn->assocresp_ies =
 			nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
-		params.assocresp_ies_len =
+		bcn->assocresp_ies_len =
 			nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
 	}
 
 	if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
-		params.probe_resp =
+		bcn->probe_resp =
 			nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
-		params.probe_resp_len =
+		bcn->probe_resp_len =
 			nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
 	}
 
-	err = call(&rdev->wiphy, dev, &params);
-	if (!err && params.interval)
-		wdev->beacon_interval = params.interval;
+	return 0;
+}
+
+static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_ap_settings params;
+	int err;
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+		return -EOPNOTSUPP;
+
+	if (!rdev->ops->start_ap)
+		return -EOPNOTSUPP;
+
+	if (wdev->beacon_interval)
+		return -EALREADY;
+
+	memset(&params, 0, sizeof(params));
+
+	/* these are required for START_AP */
+	if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+	    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+	    !info->attrs[NL80211_ATTR_BEACON_HEAD])
+		return -EINVAL;
+
+	err = nl80211_parse_beacon(info, &params.beacon);
+	if (err)
+		return err;
+
+	params.beacon_interval =
+		nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+	params.dtim_period =
+		nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+
+	err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
+	if (err)
+		return err;
+
+	/*
+	 * In theory, some of these attributes should be required here
+	 * but since they were not used when the command was originally
+	 * added, keep them optional for old user space programs to let
+	 * them continue to work with drivers that do not need the
+	 * additional information -- drivers must check!
+	 */
+	if (info->attrs[NL80211_ATTR_SSID]) {
+		params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+		params.ssid_len =
+			nla_len(info->attrs[NL80211_ATTR_SSID]);
+		if (params.ssid_len == 0 ||
+		    params.ssid_len > IEEE80211_MAX_SSID_LEN)
+			return -EINVAL;
+	}
+
+	if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
+		params.hidden_ssid = nla_get_u32(
+			info->attrs[NL80211_ATTR_HIDDEN_SSID]);
+		if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
+		    params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
+		    params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
+			return -EINVAL;
+	}
+
+	params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+	if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+		params.auth_type = nla_get_u32(
+			info->attrs[NL80211_ATTR_AUTH_TYPE]);
+		if (!nl80211_valid_auth_type(params.auth_type))
+			return -EINVAL;
+	} else
+		params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+	err = nl80211_crypto_settings(rdev, info, &params.crypto,
+				      NL80211_MAX_NR_CIPHER_SUITES);
+	if (err)
+		return err;
+
+	err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
+	if (!err)
+		wdev->beacon_interval = params.beacon_interval;
 	return err;
 }
 
-static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_beacon_data params;
+	int err;
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+		return -EOPNOTSUPP;
+
+	if (!rdev->ops->change_beacon)
+		return -EOPNOTSUPP;
+
+	if (!wdev->beacon_interval)
+		return -EINVAL;
+
+	err = nl80211_parse_beacon(info, &params);
+	if (err)
+		return err;
+
+	return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
+}
+
+static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct net_device *dev = info->user_ptr[1];
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
 
-	if (!rdev->ops->del_beacon)
+	if (!rdev->ops->stop_ap)
 		return -EOPNOTSUPP;
 
 	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
 	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
 		return -EOPNOTSUPP;
 
-	err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+	if (!wdev->beacon_interval)
+		return -ENOENT;
+
+	err = rdev->ops->stop_ap(&rdev->wiphy, dev);
 	if (!err)
 		wdev->beacon_interval = 0;
 	return err;
@@ -6357,23 +6386,23 @@
 		.cmd = NL80211_CMD_SET_BEACON,
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
-		.doit = nl80211_addset_beacon,
+		.doit = nl80211_set_beacon,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
 	{
-		.cmd = NL80211_CMD_NEW_BEACON,
+		.cmd = NL80211_CMD_START_AP,
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
-		.doit = nl80211_addset_beacon,
+		.doit = nl80211_start_ap,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
 	{
-		.cmd = NL80211_CMD_DEL_BEACON,
+		.cmd = NL80211_CMD_STOP_AP,
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
-		.doit = nl80211_del_beacon,
+		.doit = nl80211_stop_ap,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},